diff --git a/docs/README.md b/docs/README.md index b3629024..9293a7ad 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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 diff --git a/docs/faq.md b/docs/faq.md index b2127ff6..bcf8b7d1 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -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 `` element in AppxManifest.xml for each helper executable +- **Windows 10**: Add both an `` 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). + diff --git a/docs/msix-createprocess-guide.md b/docs/msix-createprocess-guide.md new file mode 100644 index 00000000..2955cc55 --- /dev/null +++ b/docs/msix-createprocess-guide.md @@ -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 `` element, even if it's only started by your own application's code and not directly by the user. + +Example AppxManifest.xml entry: + +```xml + + + + + + + + + +``` + +## Requirements for Windows 10 + +Windows 10 has more stringent requirements for helper executables. You need to: + +1. Add an `` 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 + + + + + + + + + + + + + + + + +``` + +> **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 `` 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 | - `` element in AppxManifest
- App execution alias | +| Windows 11 | - `` element in AppxManifest | + +Always test on both Windows 10 and Windows 11 to ensure compatibility across platforms. \ No newline at end of file