如何在 Windows 8 和 10 中枚举已安装的 StoreApps 及其 ID
How to enumerate the installed StoreApps and their ID in Windows 8 and 10
我想得到的是所有安装的StoreApp应用的AppUserModelId,这样我就可以把它传递给IApplicationActivationManager->ActivateApplication
。
在 Windows 8 中它存储在注册表中,但在 Windows 10 中它不再存在。
互联网上有很多关于这个的问题,但即使经过几天的搜索,我也找不到令人满意的解决方案。
到目前为止我有以下内容:
- 我创建了一个实例
IPackageManager
,
- 我用当前用户的SID调用
FindPackagesByUserSecurityId()
,
- 我遍历返回的集合
- 我得到一个
IPackage
接口
- 从那里我得到一个
IPackageId
接口,
- 然后我打电话给
IPackageId->get_FamilyName()
例如,我在 Windows 10 上为 Windows 计算器输入字符串“Microsoft.WindowsCalculator_8wekyb3d8bbwe
”。
当我向这个字符串附加一个“!App
”时,我有完整的 AppUserModelId 来启动 Windows 计算器:“Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
“
但并非所有应用程序都在 FamilyName 后面使用“!App
”。
例如 Spartan 使用 AppUserModelId
“Microsoft.Windows.Spartan_cw5n1h2txyewy!Microsoft.Spartan.Spartan
”不以“!App
”结尾。当我将“!Microsoft.Spartan.Spartan
”替换为“!App
”时,它不会启动 -> "This app does not support the contract specified".
所以我的问题是我从哪里得到最后缺失的部分?
我在互联网 (http://poshcode.org/5702) 上找到了一个 PowerShell 代码,它似乎做的事情非常相似:
Get-AppXPackage $PackageName -pv Package |
Get-AppxPackageManifest | % {
foreach($Application in $_.Package.Applications.Application) {
if($Application.Id -like $AppId) {
if($Protocol -and !($Application.Extensions.Extension.Protocol.Name | ? { ($_ + "://") -match (($Protocol -replace '\*','.*') + "(://)?") })) {
continue
}
[PSCustomObject]@{
# Notice the secret magic property:
PSTypeName = "Microsoft.Windows.Appx.Application"
AppUserModelId = $Package.PackageFamilyName + "!" + $Application.Id
}
}
}
}
我真的不明白这些神秘的 PowerShell 东西,但有一行对我来说似乎很有趣:
foreach($Application in $_.Package.Applications.Application)
这似乎是在一个包中枚举应用程序。
同一 PowerShell 代码中的注释说:
# The full AppUserModelId is composed of the package name,
the publisher id, and the app id, such as
Microsoft.ZuneMusic_8wekyb3d8bbwe!Microsoft.ZuneMusic
所以缺少的是$Application.Id
。
如果我能得到一个 IAppInfo
接口,我可以调用 IAppInfo->get_Id()
,我就准备好了。
但我不知道如何从 C++ 中的 IPackage
中获取它。
令人难以置信的是,没有人有想法!
这表明微软是如何让我们生活艰难的。
像使用 AppUserModelId 枚举已安装的 StoreApps 这样的通用任务需要一个科学研究部门。
我终于找到了一个在 Windows 8 和 Windows 10 上完美运行的解决方案。但是需要很多代码。
似乎 Windows 没有在内存中保存应用程序 ID,也没有 API 直接确定它们。我研究了 Windows 10 SDK 中的所有头文件,但找不到可用于该任务的相应接口。
但我找到了获取它们的方法。我在问题的 6 个步骤之后继续:
- 调用
IPackage->get_InstalledLocation()
其中 returns 一个 IStorageFolder
。
IStorageItem
的查询接口
- 致电
IStorageItem->get_Path()
现在您有了应用程序的安装路径。 Windows 10 使用两个基本文件夹:
- C:\程序Files\WindowsApps
- C:\Windows\SystemApps
和其他几个人
- C:\Windows\vpnplugins
- C:\Windows\devicesflow
- C:\Windows\MicracastView
- C:\Windows\PrintDialog
- C:\Windows\PrintDialog3D
- C:\Windows\WinStore
在返回的文件夹路径中,您将找到一个文件“AppxManifest.xml
”。
这个文件看起来像:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns=".....">
......
......
<Applications>
<Application Id="microsoft.windowslive.mail" Executable="HxMail.exe" EntryPoint="Executable">
......
......
</Application>
<Application Id="microsoft.windowslive.calendar" Executable="HxCalendarAppImm.exe" EntryPoint="Executable">
......
......
</Application>
</Applications>
</Package>
瞧,它们就在那里。这个包有两个应用程序 ID:“microsoft.windowslive.mail
”和“microsoft.windowslive.calendar
”。
然后从第 6 步中获取包的 FamilyName 附加一个“!”并附加此 ID,您就完成了。
可以使用 AppUserModelId 之一从 IApplicationActivationManager->ActivateApplication()
启动此包:
- "
microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar
"
- "
microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail
"
使用 PackageManager API 枚举包,使用 GetPackageApplicationIds 枚举包中的应用程序,例如伪代码
FOREACH p IN PackageManager.FindPackagesForUserWithPackageTypes(null,
PackageType_Main|PackageType_Optional)
{
PACKAGE_INFO_REFERENCE pir
OpenPackageInfoByFullName(p.Id.FullName, 0, &pir)
UINT32 n=0
GetPackageApplicationIds(pir, &n, null, null)
BYTE* buffer = new BYTE[n]
UINT32 count=0
GetPackageApplicationIds(pir, &n, buffer, &count)
ClosePackageInfo(pir)
PCWSTR * applicationUserModelIds = reinterpret_cast<PCWSTR*>(buffer);
FOR (i=0; i<count; ++i)
{
PCWSTR applicationUserModelId = applicationUserModelIds[i]
}
delete [] buffer
}
请参阅 MSDN 上的 GetPackageApplicationIds() 了解更多详细信息,包括工作示例代码
https://msdn.microsoft.com/en-us/library/windows/desktop/dn270603(v=vs.85).aspx
我想得到的是所有安装的StoreApp应用的AppUserModelId,这样我就可以把它传递给IApplicationActivationManager->ActivateApplication
。
在 Windows 8 中它存储在注册表中,但在 Windows 10 中它不再存在。
互联网上有很多关于这个的问题,但即使经过几天的搜索,我也找不到令人满意的解决方案。
到目前为止我有以下内容:
- 我创建了一个实例
IPackageManager
, - 我用当前用户的SID调用
FindPackagesByUserSecurityId()
, - 我遍历返回的集合
- 我得到一个
IPackage
接口 - 从那里我得到一个
IPackageId
接口, - 然后我打电话给
IPackageId->get_FamilyName()
例如,我在 Windows 10 上为 Windows 计算器输入字符串“Microsoft.WindowsCalculator_8wekyb3d8bbwe
”。
当我向这个字符串附加一个“!App
”时,我有完整的 AppUserModelId 来启动 Windows 计算器:“Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
“
但并非所有应用程序都在 FamilyName 后面使用“!App
”。
例如 Spartan 使用 AppUserModelId
“Microsoft.Windows.Spartan_cw5n1h2txyewy!Microsoft.Spartan.Spartan
”不以“!App
”结尾。当我将“!Microsoft.Spartan.Spartan
”替换为“!App
”时,它不会启动 -> "This app does not support the contract specified".
所以我的问题是我从哪里得到最后缺失的部分?
我在互联网 (http://poshcode.org/5702) 上找到了一个 PowerShell 代码,它似乎做的事情非常相似:
Get-AppXPackage $PackageName -pv Package |
Get-AppxPackageManifest | % {
foreach($Application in $_.Package.Applications.Application) {
if($Application.Id -like $AppId) {
if($Protocol -and !($Application.Extensions.Extension.Protocol.Name | ? { ($_ + "://") -match (($Protocol -replace '\*','.*') + "(://)?") })) {
continue
}
[PSCustomObject]@{
# Notice the secret magic property:
PSTypeName = "Microsoft.Windows.Appx.Application"
AppUserModelId = $Package.PackageFamilyName + "!" + $Application.Id
}
}
}
}
我真的不明白这些神秘的 PowerShell 东西,但有一行对我来说似乎很有趣:
foreach($Application in $_.Package.Applications.Application)
这似乎是在一个包中枚举应用程序。
同一 PowerShell 代码中的注释说:
# The full AppUserModelId is composed of the package name,
the publisher id, and the app id, such as
Microsoft.ZuneMusic_8wekyb3d8bbwe!Microsoft.ZuneMusic
所以缺少的是$Application.Id
。
如果我能得到一个 IAppInfo
接口,我可以调用 IAppInfo->get_Id()
,我就准备好了。
但我不知道如何从 C++ 中的 IPackage
中获取它。
令人难以置信的是,没有人有想法! 这表明微软是如何让我们生活艰难的。 像使用 AppUserModelId 枚举已安装的 StoreApps 这样的通用任务需要一个科学研究部门。
我终于找到了一个在 Windows 8 和 Windows 10 上完美运行的解决方案。但是需要很多代码。
似乎 Windows 没有在内存中保存应用程序 ID,也没有 API 直接确定它们。我研究了 Windows 10 SDK 中的所有头文件,但找不到可用于该任务的相应接口。
但我找到了获取它们的方法。我在问题的 6 个步骤之后继续:
- 调用
IPackage->get_InstalledLocation()
其中 returns 一个IStorageFolder
。 IStorageItem
的查询接口
- 致电
IStorageItem->get_Path()
现在您有了应用程序的安装路径。 Windows 10 使用两个基本文件夹:
- C:\程序Files\WindowsApps
- C:\Windows\SystemApps
和其他几个人
- C:\Windows\vpnplugins
- C:\Windows\devicesflow
- C:\Windows\MicracastView
- C:\Windows\PrintDialog
- C:\Windows\PrintDialog3D
- C:\Windows\WinStore
在返回的文件夹路径中,您将找到一个文件“AppxManifest.xml
”。
这个文件看起来像:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns=".....">
......
......
<Applications>
<Application Id="microsoft.windowslive.mail" Executable="HxMail.exe" EntryPoint="Executable">
......
......
</Application>
<Application Id="microsoft.windowslive.calendar" Executable="HxCalendarAppImm.exe" EntryPoint="Executable">
......
......
</Application>
</Applications>
</Package>
瞧,它们就在那里。这个包有两个应用程序 ID:“microsoft.windowslive.mail
”和“microsoft.windowslive.calendar
”。
然后从第 6 步中获取包的 FamilyName 附加一个“!”并附加此 ID,您就完成了。
可以使用 AppUserModelId 之一从 IApplicationActivationManager->ActivateApplication()
启动此包:
- "
microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar
" - "
microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail
"
使用 PackageManager API 枚举包,使用 GetPackageApplicationIds 枚举包中的应用程序,例如伪代码
FOREACH p IN PackageManager.FindPackagesForUserWithPackageTypes(null,
PackageType_Main|PackageType_Optional)
{
PACKAGE_INFO_REFERENCE pir
OpenPackageInfoByFullName(p.Id.FullName, 0, &pir)
UINT32 n=0
GetPackageApplicationIds(pir, &n, null, null)
BYTE* buffer = new BYTE[n]
UINT32 count=0
GetPackageApplicationIds(pir, &n, buffer, &count)
ClosePackageInfo(pir)
PCWSTR * applicationUserModelIds = reinterpret_cast<PCWSTR*>(buffer);
FOR (i=0; i<count; ++i)
{
PCWSTR applicationUserModelId = applicationUserModelIds[i]
}
delete [] buffer
}
请参阅 MSDN 上的 GetPackageApplicationIds() 了解更多详细信息,包括工作示例代码 https://msdn.microsoft.com/en-us/library/windows/desktop/dn270603(v=vs.85).aspx