当前位置:首页 > c++ > 正文内容

c++ windows固定到任务栏(应用程序或快捷方式)

xuwenyan1年前 (2021-12-17)c++795

将一些常用的应用程序固定到任务栏,可以方便我们使用时快速打开。下面就介绍一下使用c++固定到任务栏的几种方法。

方法一

使用ShellExecute接口,但是这个方法在win10已经无效了。

::ShellExecute(NULL, L"taskbarpin", L"C:\Windows\System32\notepad.exe", NULL, NULL, 0);

方法二

此方法在win10测试有效,按理来说其它环境应该也支持(xp是个奇葩,不一定)。

#include <atlbase.h>

bool TaskbarPinWin10(LPCTSTR lpszFilePath, LPCTSTR lpszFileName) {
  TCHAR  szVal[MAX_PATH] = { 0 };
  ULONG  uValSize = MAX_PATH;
  CRegKey  regKey;

  if (ERROR_SUCCESS != regKey.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\Windows.taskbarpin"), KEY_READ)) {
    return false;
  }
  if (ERROR_SUCCESS != regKey.QueryStringValue(_T("ExplorerCommandHandler"), szVal, &uValSize)) {
    return false;
  }
  regKey.Close();
  if (ERROR_SUCCESS != regKey.Create(HKEY_CURRENT_USER, _T("SOFTWARE\Classes\*\shell\{:}"))) {
    return false;
  }
  if (ERROR_SUCCESS != regKey.SetStringValue(_T("ExplorerCommandHandler"), szVal)) {
    return false;
  }
  regKey.Close();

  IShellDispatch* pShellDisp = NULL;
  Folder *pFolder;
  FolderItem *pFolderItem;
  CComBSTR    stitle, str;
  HRESULT hr = S_OK;

  hr = ::CoCreateInstance(CLSID_Shell, NULL,
    CLSCTX_SERVER, IID_IShellDispatch, (LPVOID*)&pShellDisp);
  if (SUCCEEDED(hr)) {
    hr = pShellDisp->NameSpace(CComVariant(lpszFilePath), &pFolder);
    hr = pFolder->ParseName(CComBSTR(lpszFileName), &pFolderItem);
    if (SUCCEEDED(hr)) {
      pFolderItem->InvokeVerb(CComVariant(_T("{:}")));
    }
    hr = pShellDisp->Release();
    pShellDisp = NULL;
  }

  if (ERROR_SUCCESS != regKey.Open(HKEY_CURRENT_USER, _T("SOFTWARE\Classes\*\shell"), KEY_READ | KEY_WRITE)) {
    return false;
  }

  regKey.RecurseDeleteKey(_T("{:}"));
  regKey.Close();

  return true;
}

void main() {
  ::CoInitialize(NULL);

  TaskbarPinWin10(L"C:\Windows\system32\", L"notepad.exe");

  ::CoUninitialize();
}

方法三

此方法并未测试成功,原理是模拟点击右键菜单里的固定到任务栏,但是Win10添加了限制,判断了当前程序名是否是 explorer.exe,所以需要调用NtQuerySystemInformation修改PEB 里 PRTL_USER_PROCESS_PARAMETERS 中的 ImagePathName为 explorer.exe,要求新构造的 ImagePathName 长度不能比原来的 ImagePathName.Length 长,不然修改会失败。总之有点不实用,列出来仅作参考吧。

#include <winternl.h>
#include <atlcomcli.h>

void ChangeImageName(HANDLE hProcess) {
  typedef NTSTATUS(NTAPI* NtQueryInformationProcessPtr)(
    IN HANDLE ProcessHandle,
    IN PROCESSINFOCLASS ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL);

  HMODULE hModule = GetModuleHandle(L"ntdll.dll");
  NtQueryInformationProcessPtr NtQueryInformationProcess =
    (NtQueryInformationProcessPtr)GetProcAddress(hModule, "NtQueryInformationProcess");

  if (!NtQueryInformationProcess)
    return;

  PROCESS_BASIC_INFORMATION pbi = { 0 };
  ULONG ulRetLength = 0;
  NTSTATUS ntStatus = NtQueryInformationProcess(
    hProcess,
    ProcessBasicInformation,
    &pbi,
    sizeof(PROCESS_BASIC_INFORMATION),
    &ulRetLength);

  BOOL bRet = (ntStatus >= 0);
  if (!bRet) {
    fprintf(stderr, "Could not get process information. Status = %X
",
      ntStatus);
    return;
  }

  PPEB ppeb = pbi.PebBaseAddress;
  PRTL_USER_PROCESS_PARAMETERS pRtlProcParam = ppeb->ProcessParameters;


  //ref https://stackoverflow.com/a/38880235
  WCHAR szImagePath[MAX_PATH] = { 0 };
  wcscpy_s(szImagePath, pRtlProcParam->ImagePathName.Buffer);
  PathRemoveFileSpec(szImagePath);
  PathAddBackslash(szImagePath);
  wcscat_s(szImagePath, L"explorer.exe");

  int len = wcslen(szImagePath) * sizeof(WCHAR);
  int originalLen = pRtlProcParam->ImagePathName.Length;
  if (len > originalLen) {
    fwprintf(stderr, L"new ImagePathName cannot be longer than the original one
");
    return;
  }
  SecureZeroMemory(pRtlProcParam->ImagePathName.Buffer, originalLen);
  memcpy(pRtlProcParam->ImagePathName.Buffer, szImagePath, len);
};

bool PinUnpinTaskbar(LPCWSTR szFilePath, bool pin) {
  HRESULT hr = S_OK;

  WCHAR szVerbName[MAX_PATH] = { 0 };
  HINSTANCE ht = LoadLibrary(L"Shell32.dll");

  //5386 is the DLL index for"Pin to Tas&kbar"
  //ref.//http://www.win7dll.info/shell32_dll.html
  UINT uID = pin ? 5386 : 5387;
  LoadString(ht, uID, szVerbName, MAX_PATH);

  CComPtr<IShellDispatch> pShellDisp;

  hr = CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_SERVER, IID_IShellDispatch, reinterpret_cast<LPVOID*>(&pShellDisp));

  if (FAILED(hr))
    return false;

  CComPtr<Folder> pFolder;
  CComPtr<FolderItem> pFolderItem;

  WCHAR szTempPath[MAX_PATH] = { 0 };

  //folder
  wcscpy_s(szTempPath, szFilePath);
  PathRemoveFileSpec(szTempPath);
  CComVariant vDir(szTempPath);
  hr = pShellDisp->NameSpace(vDir, &pFolder);

  if (FAILED(hr))
    return false;

  //file name
  wcscpy_s(szTempPath, szFilePath);
  PathStripPath(szTempPath);
  hr = pFolder->ParseName(CComBSTR(szTempPath), &pFolderItem);

  if (FAILED(hr))
    return false;

  CComPtr<FolderItemVerbs> itemVerbs;
  hr = pFolderItem->Verbs(&itemVerbs);

  if (FAILED(hr))
    return false;

  LONG itemCount = 0;
  itemVerbs->get_Count(&itemCount);

  CComBSTR ccombstr(szVerbName);
  for (int i = 0; i < itemCount; i++) {
    CComPtr<FolderItemVerb> verb;
    itemVerbs->Item(CComVariant(i), &verb);
    if (verb) {
      CComBSTR name;
      hr = verb->get_Name(&name);

      if (SUCCEEDED(hr) && ccombstr == name) {
        verb->DoIt();
        fprintf(stdout, "verb founded, do it.
");
        return true;
      }
    }
  }
  return false;
}

void main() {
  ::CoInitialize(NULL);

  ChangeImageName(GetCurrentProcess());
  PinUnpinTaskbar(L"C:\Windows\system32\notepad.exe", true);

  ::CoUninitialize();
}


    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/2299

    分享给朋友:

    “c++ windows固定到任务栏(应用程序或快捷方式)” 的相关文章

    C++实现win32窗口文件拖拽

    C++实现win32窗口文件拖拽

    如题,C++如何实现win32窗口文件拖拽,直接上代码 方法1:使用win32消息实现 此方法的弊端在于,无法过滤可以拖拽的文件,拖拽时显示的图标也默认的,无法像资源管理器那样自定义。实现步骤大致分为以下三步: 第一步:首先创建窗口时必须在exStyle加上WS_EX_ACCEP...

    C++如何获取控制台程序的输出内容?

    C++如何获取控制台程序的输出内容?

    很多工具程序(如ffmpeg)的进度显示往往都是以控制台字符显示的方法,我们可能需要调用这种控制台工具去完成工作,但同时又希望以友好的ui界面去显示当前的工作状态(如进度)。此时我们能想到的就是运行控制台程序,然后以某种方式去获取到控制台程序的输出,然后转换到我们的ui界面上去显示。 有多种...

    使用GDI、MFC_GDI、GDI+绘制数组RGBA序列

    使用GDI、MFC_GDI、GDI+绘制数组RGBA序列

    学习ffmpeg时遇到一个问题,ffmpeg解码出RGB颜色后怎么绘制到屏幕上,于是将GDI、MFC_GDI、GDI+等方式都记录一下 1:注意按windows的要求,R、G、B、A顺序要调整为B、G、R、A 。 2:GDI不支持透明通道A,透明通道A的值读进去以后没有作用。想要支持透...

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    例如,我用VC2015的工程向导新建一个ATL的工程名字叫myAtl,那么VC会同时给我生成一个叫做myAtlPS的工程。这个myAtlPS工程是做什么的?什么情况下可以不需要它?什么情况下它又是必须存在的? PS工程是什么?可以不要吗? 这个PS工程叫做代理与存根(proxy&nbs...

    ATL实现windows右键菜单扩展(ContextMenu)

    ATL实现windows右键菜单扩展(ContextMenu)

    右键菜单,即用户右击shell对象时弹出的上下文菜单(context menu)。本文记录了如何创建右键菜单的基本过程,跟着步骤一步一步来,即可创建出一个右键菜单工程。第一步,新建一个ATL工程Visual Studio—>新建项目—>ATL—>使用默认配置(一直按下一步即可)。注...

    C++ 获取进程所在目录(进程全路径)

    C++ 获取进程所在目录(进程全路径)

    打开windows任务管理器,会看到很多的进程在运行,随机挑选一个,如何通过c++代码获取某一个进程的所在全路径呢?这也是在windows软件开发中经常遇到的需求。通过进程名获取进程全路径由于可能很多进程叫同一个名字,所以获得的结果也有可能是多个#include <windows.h...