November 10th, 2026
like1 reaction

Activation via AppUserModelId

Principal Software Engineer

An application can be directly activated by calling IApplicationActivationManager::ActivateApplication() with its Application User Model ID, also known as AppUserModelId or AUMID.

For example, let’s use a package with this AppxManifest.xml fragment:

<?xml version="1.0" encoding="utf-8"?>
<Package ...>
  <Identity Name="Contoso.PointOfSale"
            Publisher="CN=Contoso LLC, O=Contoso LLC, L=Paris, C=France"
            Version="1.2.3.4"
            ProcessorArchitecture="x64" />
  ...
  <Applications>
    <Application Id="CardReader" Executable="PointOfSale.exe" ...>
...
</Package>

This package’s full name is Contoso.PointOfSale_1.2.3.4_x64__eh4htm4n7tdre.

The eh4htm4n7tdre suffix is the publisher ID derived from the package’s publisher.

Its package family name is therefore Contoso.PointOfSale_eh4htm4n7tdre.

The <Application>‘s Id attribute is the application’s Package Relative Application Id, also known as PRAID.

An AUMID is a combination of the application’s package family name and PRAID:

AUMID = <PackageFamilyName> "!" <PRAID>

Thus the card reader’s AUMID is Contoso.PointOfSale_eh4htm4n7tdre!CardReader. We can now activate the application via its AUMID.

Building StartApp.exe

Let’s create StartApp.exe demonstrating activation via AppUserModelId in C, C++, and C#.

StartApp.c

Windows doesn’t provide a convenient way to activate an application given an AUMID, so let’s make one.

StartApp.exe activates an app by AUMID. Here’s a minimal low-level implementation:

#define COBJMACROS
#include <windows.h>
#include <shobjidl.h>

HRESULT Run(PCWSTR appUserModelId, PCWSTR parameters, DWORD* processId)
{
    IApplicationActivationManager *aam = NULL;
    HRESULT hr = S_OK;

    if (appUserModelId == NULL || *appUserModelId == L'\0' || processId == NULL)
    {
        return E_INVALIDARG;
    }

    hr = CoCreateInstance(&CLSID_ApplicationActivationManager, NULL,
        CLSCTX_INPROC_SERVER, &IID_IApplicationActivationManager, (void**)&aam);
    if (FAILED(hr))
    {
        return hr;
    }

    hr = IApplicationActivationManager_ActivateApplication(aam,
        appUserModelId, parameters != NULL ? parameters : L"", AO_NONE, processId);

    IApplicationActivationManager_Release(aam);

    return hr;
}

int wmain(int argc, wchar_t* argv[])
{
    HRESULT hr = S_OK;
    DWORD processId = 0;

    if (argc < 2)
    {
        wprintf(L"Usage: StartApp.exe <aumid>\n");
        return ERROR_INVALID_PARAMETER;
    }

    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (FAILED(hr))
    {
        return hr;
    }

    hr = Run(argv[1], NULL, &processId);
    if (SUCCEEDED(hr))
    {
        wprintf(L"StartApp activated %ls: PID %u\n", argv[1], processId);
    }
    else
    {
        fwprintf(stderr, L"StartApp failed to activate %ls: 0x%08lX\n",
            argv[1], (unsigned long)hr);
    }

    CoUninitialize();

    return (int)hr;
}

Pretty basic but it gets the job done. This creates the ApplicationActivationManager (AAM) instance and calls its ActivateApplication() method with the AUMID, with basic error handling throughout.

But we can do better.

StartApp.cpp

Next, let’s add support for parameters.

We’ll also switch to Modern C++ and Windows Implementation Library (WIL) for ease of use and improved error handling.

#include <windows.h>
#include <shobjidl.h>

#include <string>

#include <wil/com.h>
#include <wil/resource.h>
#include <wil/result.h>

DWORD Run(const std::wstring& appUserModelId, const std::wstring& parameters)
{
    THROW_HR_IF(E_INVALIDARG, appUserModelId.empty());

    auto aam{ wil::CoCreateInstance<IApplicationActivationManager>(CLSID_ApplicationActivationManager) };

    DWORD processId{};
    THROW_IF_FAILED(aam->ActivateApplication(
        appUserModelId.c_str(), parameters.c_str(), AO_NONE, &processId));

    return processId;
}

int wmain(int argc, wchar_t* argv[])
{
    if (argc < 2)
    {
        std::fwprintf(stderr, L"Usage: StartApp.exe <aumid> [parameters...]\n");
        return ERROR_INVALID_PARAMETER;
    }

    const std::wstring appUserModelId{ argv[1] };

    // Handling backslashes, quotes, spaces and other complexities in argv
    // is left as an exercise for the reader :-)
    std::wstring parameters;
    for (int index = 2; index < argc; ++index)
    {
        if (index > 2)
        {
            parameters += L' ';
        }
        parameters += argv[index];
    }

    try
    {
        const auto com{ wil::CoInitializeEx(COINIT_APARTMENTTHREADED) };

        const auto processId{ Run(appUserModelId, parameters) };
        wprintf(L"StartApp activated %ls with \"%ls\": PID %u\n",
            appUserModelId.c_str(), parameters.c_str(), processId);
    }
    catch (const wil::ResultException& ex)
    {
        std::fwprintf(stderr, L"StartApp failed to activate %ls: 0x%08lX\n",
            appUserModelId.c_str(), static_cast<unsigned long>(ex.GetErrorCode()));
        return static_cast<int>(ex.GetErrorCode());
    }

    return 0;
}

StartApp.exe is both simpler and more capable thanks to C++ and WIL. Modern C++ eliminates much of the manual resource management, while WIL provides concise COM helpers and consistent exception-based error handling.

StartApp.cs

For bonus points, here’ a C# implementation.

using System;
using System.Runtime.InteropServices;

internal static class Program
{
    private const uint AO_NONE = 0;

    [ComImport]
    [Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IApplicationActivationManager
    {
        int ActivateApplication(
            [MarshalAs(UnmanagedType.LPWStr)] string appUserModelId,
            [MarshalAs(UnmanagedType.LPWStr)] string arguments,
            uint options,
            out uint processId);

        int ActivateForFile(
            IntPtr itemArray,
            [MarshalAs(UnmanagedType.LPWStr)] string verb,
            out uint processId);

        int ActivateForProtocol(
            IntPtr itemArray,
            out uint processId);
    }

    [ComImport]
    [Guid("2E941141-7F97-4756-BA1D-9DECDE894A3D")]
    private sealed class ApplicationActivationManager
    {
    }

    private static uint Run(string appUserModelId, string parameters)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(appUserModelId);

        var aam = (IApplicationActivationManager)new ApplicationActivationManager();

        var hr = aam.ActivateApplication(
            appUserModelId, parameters, AO_NONE, out var processId);

        Marshal.ThrowExceptionForHR(hr);

        return processId;
    }

    public static int Main(string[] args)
    {
        if (args.Length < 1)
        {
            Console.Error.WriteLine(
                "Usage: StartApp.exe <aumid> [parameters...]");
            return 2;
        }

        var appUserModelId = args[0];

        // Handling backslashes, quotes, spaces and other complexities in argv
        // is left as an exercise for the reader :-)
        var parameters = string.Join(" ", args[1..]);

        try
        {
            var processId = Run(appUserModelId, parameters);

            Console.WriteLine(
                $"StartApp activated {appUserModelId} with \"{parameters}\": PID {processId}");

            return 0;
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(
                $"StartApp failed to activate {appUserModelId}: {ex.HResult:X8}");

            return ex.HResult;
        }
    }
}

Activation via AppUserModelId from the Command Line

Activation by AUMID is fine, but not always convenient. Some tools only know how to run programs via a command line. Windows doesn’t include a utility like StartApp.exe to facilitate activation by AUMID.

You can programmatically define a shortcut on the StartMenu to launch a packaged app by AUMID but File Explorer’s right-click context menu’s New > Shortcut won’t accept an AUMID directly.

Is there another option?

Of course.

We’ll explore several options in the next blog post…

Author

Howard Kapustein
Principal Software Engineer

MSIX Development Engineer/Architect

0 comments