Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ system tidy
* Packaging and system integration so Windows understands what your app is doing
* App-to-app inter-process communication helpers so your apps can work with other app easily
* Privacy-aware resource access APIs for camera, microphone, location, and more
* [Guidance for packaged applications](msix-createprocess-guide.md) to help you navigate MSIX packaging scenarios

You'll start using these APIs by adding a reference to the Windows App SDK NuGet package
and then adding uses of the APIs in your app code. Use as much or as little of Windows App SDK
Expand Down
11 changes: 11 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,14 @@ the in-box components while we focus on making the Windows App SDK surface compl

[Create an issue to ask a question or start a discussion](https://github.com/microsoft/WindowsAppSDK/issues/new/choose).

## Why does CreateProcess fail with ERROR_ACCESS_DENIED for helper EXEs in my MSIX package?

When an MSIX packaged application tries to use CreateProcess to launch a helper executable that's included in the package, it might fail with ERROR_ACCESS_DENIED (error code 5). This happens because Windows uses package identity to determine which executables are allowed to run within the context of an MSIX package.

The solution varies between Windows 10 and Windows 11:

- **Windows 11**: Add an `<Application>` element in AppxManifest.xml for each helper executable
- **Windows 10**: Add both an `<Application>` element and an app execution alias for each helper executable

For detailed guidance, see our [complete guide on making CreateProcess work with helper executables in MSIX packages](msix-createprocess-guide.md).

133 changes: 133 additions & 0 deletions docs/msix-createprocess-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Making CreateProcess Work with Helper Executables in MSIX Packages

This document provides guidance on how to successfully use `CreateProcess` to launch helper executables that are included within an MSIX package.

## Overview of the Issue

When an application packaged with MSIX attempts to use `CreateProcess` to launch another executable that is included within the same package, it may receive `ERROR_ACCESS_DENIED` (Access is denied, error code 5). This happens because Windows uses package identity to determine which executables are allowed to run within the context of an MSIX package.

The behavior differs between Windows 10 and Windows 11, with Windows 11 making it easier to launch helper executables within the same package.

## Requirements for Windows 11

On Windows 11, the primary requirement for launching a helper executable with `CreateProcess` is:

1. Each executable must be listed in the AppxManifest.xml using an `<Application>` element, even if it's only started by your own application's code and not directly by the user.

Example AppxManifest.xml entry:

```xml
<Applications>
<Application Id="MainApp" Executable="MainApp.exe" EntryPoint="Windows.FullTrustApplication">
<!-- Main application settings -->
</Application>
<Application Id="HelperTool" Executable="tools\HelperTool.exe" EntryPoint="Windows.FullTrustApplication">
<!-- No need for visible entry in start menu -->
<uap:VisualElements DisplayName="Helper Tool" Square150x150Logo="Assets\Logo.png" Square44x44Logo="Assets\SmallLogo.png" Description="Helper Tool" BackgroundColor="transparent" AppListEntry="none" />
</Application>
</Applications>
```

## Requirements for Windows 10

Windows 10 has more stringent requirements for helper executables. You need to:

1. Add an `<Application>` element in AppxManifest.xml for each helper executable (as shown above)
2. Add an app execution alias for the helper executable, even if you don't use this alias to invoke the executable

Example AppxManifest.xml entry with execution alias:

```xml
<Applications>
<Application Id="MainApp" Executable="MainApp.exe" EntryPoint="Windows.FullTrustApplication">
<!-- Main application settings -->
</Application>
<Application Id="HelperTool" Executable="tools\HelperTool.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements DisplayName="Helper Tool" Square150x150Logo="Assets\Logo.png" Square44x44Logo="Assets\SmallLogo.png" Description="Helper Tool" BackgroundColor="transparent" AppListEntry="none" />
<!-- The execution alias is required for Windows 10, even if you don't use it directly -->
<Extensions>
<uap3:Extension Category="windows.appExecutionAlias">
<uap3:AppExecutionAlias>
<desktop:ExecutionAlias Alias="HelperTool.exe" />
</uap3:AppExecutionAlias>
</uap3:Extension>
</Extensions>
</Application>
</Applications>
```

> **Note:** The alias name must match the executable name, even though you might be calling the executable with its full path.

## Advanced Options Using Thread Attributes

Instead of modifying the AppxManifest, you can also control process creation behavior by using thread attributes with the `CreateProcess` API. This approach provides more programmatic control but requires modifying your code that calls `CreateProcess`.

To prevent child processes from breaking away from the parent process identity:

```cpp
// Set up process attributes
SIZE_T attributeListSize = 0;
InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListSize);
PPROC_THREAD_ATTRIBUTE_LIST attributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
GetProcessHeap(), 0, attributeListSize);
InitializeProcThreadAttributeList(attributeList, 1, 0, &attributeListSize);

// Set policy to override breakaway behavior
DWORD policy = PROCESS_CREATION_DESKTOP_APP_BREAKAWAY_OVERRIDE;
UpdateProcThreadAttribute(attributeList, 0, PROC_THREAD_ATTRIBUTE_DESKTOP_APP_POLICY,
&policy, sizeof(policy), NULL, NULL);

// Set up startup info
STARTUPINFOEX info = {0};
info.StartupInfo.cb = sizeof(info);
info.lpAttributeList = attributeList;

// Create the process
CreateProcess(executablePath, commandLine, NULL, NULL, FALSE,
EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &info.StartupInfo, &processInfo);

// Clean up
DeleteProcThreadAttributeList(attributeList);
HeapFree(GetProcessHeap(), 0, attributeList);
```

### Example from Windows App SDK

The Windows App SDK uses a similar approach in its RestartAgent implementation. When an application needs to restart itself, the Windows App SDK:

1. Launches a special RestartAgent.exe helper
2. Configures process attributes to maintain package identity through the restart
3. Uses `PROCESS_CREATION_DESKTOP_APP_BREAKAWAY_OVERRIDE` to ensure the restarted process has the proper context

This is an advanced technique that requires careful implementation, but it shows how Windows App SDK itself handles cross-process interactions within an MSIX package.

## Troubleshooting

If you're experiencing `ERROR_ACCESS_DENIED` when using `CreateProcess`:

1. Verify that all executables have an `<Application>` entry in the AppxManifest
2. On Windows 10, ensure you've added the execution alias for each helper executable
3. Check if there are multiple installed packages with the same execution alias, which can cause conflicts
4. Consider using the thread attributes approach described above

## Tips and Caveats

1. **Store Submission Challenges**: Adding execution aliases for helper executables may cause your app to be flagged as a "headless" or CLI app during Microsoft Store submission, which might require special permission. The Microsoft Store has restrictions on command-line utilities that don't have a primary UI. If you run into this issue, you might need to:
- Apply for an exception to the Store policy for your app
- Consider alternative distribution methods if your app is rejected
- Design your app to avoid needing helper executables that require execution aliases

2. **Package Conflicts**: If two different MSIX packages try to register the same execution alias, Windows 10 will grant priority to the first installed package, causing `ERROR_ACCESS_DENIED` for the second package trying to use that alias.

3. **Testing**: Thoroughly test your application on both Windows 10 and Windows 11 to ensure it works correctly across versions.

## Summary

The main differences in behavior:

| Windows Version | Requirements for Helper EXEs |
|----------------|----------------------------|
| Windows 10 | - `<Application>` element in AppxManifest<br>- App execution alias |
| Windows 11 | - `<Application>` element in AppxManifest |

Always test on both Windows 10 and Windows 11 to ensure compatibility across platforms.