C++获取商店应用(msix应用)桌面快捷方式的安装目录
传统应用的快捷方式目标指向可执行文件的路径,但是对于商店应用(也叫msix打包应用),则指向一个奇怪的字符串,使用IShellLink::GetPath
获取路径时,则得到的是空字符串,而我们的最终目的是要拿到应用的安装路径,那该怎么办呢?
首先解释一下,那个奇怪的字符串叫AUMID
(App User Model Id)
,由应用包系列名称AppInfo.PackageFamilyName和应用标识符AppInfo.Id组成。
分3步获取安装目录
1,先获取快捷方式的PIDL
HRESULT hr = S_OK; IShellLinkW* psl = NULL; IPersistFile* psf = NULL; LPITEMIDLIST pidlLnk = NULL; do { hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID*)&psl); if (FAILED(hr)) { break; } hr = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&psf); if (FAILED(hr)) { break; } //加载快捷方式 hr = psf->Load(L"C:\\Users\\Xyy\\Desktop\\Microsoft Teams - 快捷方式.lnk", STGM_READ); if (FAILED(hr)) { break; } //获取快捷方式 hr = psl->GetIDList(&pidlLnk); if (FAILED(hr)) { break; } } while (false); //释放资源 if (pidlLnk) ILFree(pidlLnk);
2,通过PIDL
获取应用的AUMID
这里要注意,并非所有拿不到路径的快捷方式都是商店应用,因此要判断快捷方式的父目录是否是FOLDERID_AppsFolder
,这是一个虚拟目录
... LPITEMIDLIST pidlAppsFolder = NULL; PWSTR ppszName = NULL; do { ... //获取FOLDERID_AppsFolder的PIDL hr = SHGetKnownFolderIDList(FOLDERID_AppsFolder, 0, NULL, &pidlAppsFolder); if (FAILED(hr)) { break; } //判断当前快捷方式的父目录是否是FOLDERID_AppsFolder if (!ILIsParent(pidlAppsFolder, pidlLnk, FALSE)) { printf("此快捷方式不是商店应用"); break; } //根据PIDL获取AUMID hr = SHGetNameFromIDList(pidlLnk, SIGDN_PARENTRELATIVEPARSING, &ppszName); if (FAILED(hr)) { break; } } while (false); //释放资源 ... if (pidlAppsFolder) ILFree(pidlAppsFolder); if (ppszName) CoTaskMemFree(ppszName);
3,通过AUMID
解析出packageFamily,再根据PackageManager解析出安装目录
PackageManager
是WinRT
的类型,如何在c++中使用WinRT,请参考C++/WinRT
以下代码需要管理员权限才能运行。
//根据AUMID拿到packageFamily std::wstring fullString(ppszName); size_t pos = fullString.find(L'!'); if (pos == std::wstring::npos) { break; } std::wstring packageFamily = fullString.substr(0, pos); std::wstring installPath = L""; PackageManager packageManager; //通过packageFamily查找所有包 auto packages = packageManager.FindPackages(packageFamily); for (auto package : packages) { auto listEnties = package.GetAppListEntries(); for (auto entry : listEnties) { if (entry.AppUserModelId() == ppszName) { installPath == package.InstalledPath(); break; } } if (!installPath.empty()) { break; } } if (installPath.empty()) { break; } //找到安装目录 printf("找到安装目录:%ls", installPath.c_str());