Reputation: 8138
What I want to get is the AppUserModelId of all installed StoreApp applications, so that I can pass it to IApplicationActivationManager->ActivateApplication
.
In Windows 8 it was stored in the Registry, but in Windows 10 it is not anymore.
There are a lot of questions about this in internet but even after days of searching I could not find a satisfying solution.
What I have so far is the following:
IPackageManager
,FindPackagesByUserSecurityId()
with the SID of the current user,IPackage
interfaceIPackageId
interface,IPackageId->get_FamilyName()
With that I have for example on Windows 10 for the Windows Calculator the string "Microsoft.WindowsCalculator_8wekyb3d8bbwe
".
When I append to this string an "!App
" I have the complete AppUserModelId to start the Windows Calculator: "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
"
But not all applications use an "!App
" behind the FamilyName.
For example Spartan uses the AppUserModelId
"Microsoft.Windows.Spartan_cw5n1h2txyewy!Microsoft.Spartan.Spartan
" which does not end with "!App
". And when I replace "!Microsoft.Spartan.Spartan
" with "!App
" it will not start -> "This app does not support the contract specified".
So my question is where do I get the last missing part from?
I found a PowerShell code in internet (http://poshcode.org/5702) that seems to do something very similar:
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
}
}
}
}
I really don't understand this cryptic PowerShell stuff, but one line seems interesting to me:
foreach($Application in $_.Package.Applications.Application)
This seems to enumerate Applications in a Package.
A comment in the same PowerShell code says:
# The full AppUserModelId is composed of the package name,
the publisher id, and the app id, such as
Microsoft.ZuneMusic_8wekyb3d8bbwe!Microsoft.ZuneMusic
so what is missing is the $Application.Id
.
If I could get an IAppInfo
interface anyhow I could call IAppInfo->get_Id()
and I would be ready.
But I don't know how to get this from an IPackage
in C++.
Upvotes: 2
Views: 4004
Reputation: 8138
Incredible that nobody has an idea! This shows how Microsoft makes us life hard. Such a universal task like enumerating the installed StoreApps with their AppUserModelId requires a cientific research department.
I finally came to a solution that works perfectly on Windows 8 and Windows 10. But a lot of code is required.
It seems that Windows does not hold the Application ID's in memory and there is no API to determine them directly. I studied all header files in the Windows 10 SDK and could not find a corresponding interface useful for that task.
But I found out how to get them. I continue after the 6 steps in my question:
IPackage->get_InstalledLocation()
which returns an IStorageFolder
.IStorageItem
IStorageItem->get_Path()
Now you have the path were the App is installed. Windows 10 uses two base folders:
and several others like
In the returned folder path you will find a file "AppxManifest.xml
".
This file looks like:
<?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>
And voilà, there they are. This package has two application ID's: "microsoft.windowslive.mail
" and "microsoft.windowslive.calendar
".
Then you take the package's FamilyName from step 6 append an "!" and append this ID and you are done.
This package can be started with IApplicationActivationManager->ActivateApplication()
using one of the AppUserModelId's:
microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar
"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail
"Upvotes: 4
Reputation: 527
Use PackageManager APIs to enumerate packages and GetPackageApplicationIds to enumerate applications in a package e.g. pseudo-code
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
}
See GetPackageApplicationIds() on MSDN for more details including working sample code https://msdn.microsoft.com/en-us/library/windows/desktop/dn270603(v=vs.85).aspx
Upvotes: 1