Description
Sparse-packaged apps (apps with package identity registered via AddPackageByUriAsync) that use a custom ProjectPriFileName (e.g., AssemblyName.pri) cannot load resources through the default ResourceManager() constructor.
Related: microsoft/microsoft-ui-xaml#10856
Why This Matters
Unpackaged apps that need package-identity-only APIs (e.g., Windows AI APIs) must use sparse app registration (AddPackageByUriAsync) to acquire identity. When multiple such apps share the same output directory, each needs its own module-specific PRI (via ProjectPriFileName) to avoid resource conflicts — but this bug prevents sparse-packaged apps from discovering any PRI file other than resources.pri.
Root Cause
In dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/src/Helper.cpp, GetDefaultPriFile() calls GetDefaultPriFileForCurrentPackage() first. For sparse apps this fails (resources aren't deployed through the package system), but the error is not APPMODEL_ERROR_NO_PACKAGE because sparse apps do have package identity.
This causes isPackaged = true, so GetDefaultPriFileForCurentModule(true, ...) passes "resources.pri" to MrmGetFilePathFromName ΓÇö which only searches for that exact filename. The [modulename].pri fallback (triggered by passing nullptr) is never reached.
GetDefaultPriFile
+-- GetDefaultPriFileForCurrentPackage -> FAILS (sparse app, not real package)
+-- isPackaged = true (has identity, not APPMODEL_ERROR_NO_PACKAGE)
+-- GetDefaultPriFileForCurentModule(true) -> MrmGetFilePathFromName("resources.pri") -> NOT FOUND
+-- Returns error -- never tries nullptr path which would find [modulename].pri
Affected Scenarios
| Deployment |
Identity |
resources.pri exists |
[module].pri exists |
Result |
| Fully packaged |
Yes |
Yes (via package) |
N/A |
Works |
| Unpackaged |
No |
No |
Yes |
Works (nullptr path) |
| Sparse |
Yes |
No |
Yes |
Broken |
Proposed Fix
When GetDefaultPriFileForCurentModule(isPackaged=true) fails for an app with identity, fall back to GetDefaultPriFileForCurentModule(false) which passes nullptr to MrmGetFilePathFromName, triggering the broader search including [modulename].pri.
If the fallback also fails, return the original HRESULT to preserve error behavior for existing callers.
Impact
- Affects any sparse-packaged app using MRT
ResourceManager() default constructor with a custom PRI filename
- WinUI controls also fail to load localized strings in self-contained sparse app deployments
- Fix is scoped: only activates for apps with identity where
resources.pri was not found
Description
Sparse-packaged apps (apps with package identity registered via
AddPackageByUriAsync) that use a customProjectPriFileName(e.g.,AssemblyName.pri) cannot load resources through the defaultResourceManager()constructor.Related: microsoft/microsoft-ui-xaml#10856
Why This Matters
Unpackaged apps that need package-identity-only APIs (e.g., Windows AI APIs) must use sparse app registration (
AddPackageByUriAsync) to acquire identity. When multiple such apps share the same output directory, each needs its own module-specific PRI (viaProjectPriFileName) to avoid resource conflicts — but this bug prevents sparse-packaged apps from discovering any PRI file other thanresources.pri.Root Cause
In
dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/src/Helper.cpp,GetDefaultPriFile()callsGetDefaultPriFileForCurrentPackage()first. For sparse apps this fails (resources aren't deployed through the package system), but the error is notAPPMODEL_ERROR_NO_PACKAGEbecause sparse apps do have package identity.This causes
isPackaged = true, soGetDefaultPriFileForCurentModule(true, ...)passes"resources.pri"toMrmGetFilePathFromNameΓÇö which only searches for that exact filename. The[modulename].prifallback (triggered by passingnullptr) is never reached.Affected Scenarios
Proposed Fix
When
GetDefaultPriFileForCurentModule(isPackaged=true)fails for an app with identity, fall back toGetDefaultPriFileForCurentModule(false)which passesnullptrtoMrmGetFilePathFromName, triggering the broader search including[modulename].pri.If the fallback also fails, return the original HRESULT to preserve error behavior for existing callers.
Impact
ResourceManager()default constructor with a custom PRI filenameresources.priwas not found