【问题标题】:How to enumerate the installed StoreApps and their ID in Windows 8 and 10如何在 Windows 8 和 10 中枚举已安装的 StoreApp 及其 ID
【发布时间】:2015-08-21 23:38:52
【问题描述】:

我想要得到的是所有已安装的 StoreApp 应用程序的 AppUserModelId,这样我就可以将它传递给IApplicationActivationManager->ActivateApplication

在 Windows 8 中它存储在注册表中,但在 Windows 10 中不再存在。

互联网上有很多关于此的问题,但即使经过几天的搜索,我也找不到令人满意的解决方案。

到目前为止,我有以下内容:

  1. 我创建了一个IPackageManager 的实例,
  2. 我用当前用户的 SID 调用FindPackagesByUserSecurityId()
  3. 我遍历返回的集合
  4. 我得到一个IPackage 接口
  5. 从中我得到一个IPackageId 接口,
  6. 然后我打电话给IPackageId->get_FamilyName()

例如,我在 Windows 10 上为 Windows Calculator 提供了字符串“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”时,它不会启动->“此应用不支持指定的合同”。

所以我的问题是我从哪里得到最后一个缺失的部分?

我在互联网 (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 获取此信息。

【问题讨论】:

    标签: c++ windows powershell app-store


    【解决方案1】:

    令人难以置信的是,没有人有任何想法! 这显示了微软如何让我们的生活变得艰难。 像用 AppUserModelId 枚举已安装的 StoreApps 这样的通用任务需要一个科研部门。

    我终于找到了在 Windows 8 和 Windows 10 上完美运行的解决方案。但是需要大量代码。

    Windows 似乎没有将应用程序 ID 保存在内存中,并且没有 API 可以直接确定它们。我研究了 Windows 10 SDK 中的所有头文件,找不到对那个任务有用的相应接口。

    但我发现了如何获得它们。我在问题中的 6 个步骤之后继续:

    1. 调用IPackage->get_InstalledLocation(),返回IStorageFolder
    2. IStorageItem 的查询接口
    3. 致电IStorageItem->get_Path()

    现在您有了安装应用程序的路径。 Windows 10 使用两个基本文件夹:

    • C:\Program 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-&gt;ActivateApplication() 启动:

    • microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar
    • microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail

    【讨论】:

    • 这依赖于未记录的行为。不推荐也不建议这样做。有关使用公共(记录和支持)API 的解决方案,请参阅下面的评论
    • 我没有尝试你的代码。但是 MSDN 说 GetPackageApplicationIds() 需要 Windows 8.1。对我来说,如果代码在 Windows 8.0 上也不起作用,那它就是无用的。
    【解决方案2】:

    使用 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

    【讨论】:

    • 我没有尝试这个代码。但是 MSDN 说 GetPackageApplicationIds() 需要 Windows 8.1。对我来说,如果代码在 Windows 8.0 上也不起作用,那它就是无用的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 2018-12-17
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多