Repository navigation
Fix sparse-packaged apps unable to discover module-specific PRI files - #6376
Conversation
Sparse-packaged apps have package identity (via AddPackageByUriAsync) but deploy resources as loose files next to the executable. GetDefaultPriFile() determines isPackaged=true for these apps (since they have identity), causing GetDefaultPriFileForCurentModule to pass "resources.pri" to MrmGetFilePathFromName — which only searches for that exact filename, skipping the [modulename].pri fallback that unpackaged apps receive. When the "resources.pri" search fails for apps with identity, fall back to the unpackaged discovery path (pass nullptr to MrmGetFilePathFromName) which triggers the broader search including "[modulename].pri" derived via PathCchRenameExtension from the process executable name. If the fallback also fails, return the original HRESULT from the "resources.pri" search so callers that check for specific errors (e.g., ERROR_FILE_NOT_FOUND) are not broken. Existing test coverage: - DefaultResourceManagerWithExePri validates the nullptr fallback mechanism - DefaultResourceManager validates error behavior when no PRI exists - DefaultResourceManagerWithResourcePri validates the normal packaged path A full sparse-app integration test requires actual sparse package registration (AddPackageByUriAsync) which is beyond unit test scope. Fixes: microsoft/microsoft-ui-xaml#10856 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
This PR updates MRTCore’s default PRI discovery logic to support sparse-packaged apps (apps with package identity but deploying PRI files as loose files next to the executable), ensuring module-specific PRI files (e.g., [modulename].pri) can be discovered when resources.pri is not present.
Changes:
- After a failed packaged-module lookup (
"resources.pri"), add a fallback to the unpackaged discovery path (MrmGetFilePathFromName(nullptr, ...)) for apps with identity. - Preserve the original HRESULT from the packaged-module lookup when the fallback also fails.
|
Copilot review |
Agent-Logs-Url: https://github.com/microsoft/WindowsAppSDK/sessions/ed36cfc6-52ad-414b-8e1a-dc16f413a97e Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com>
Reviewed the current state of |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Scott Jones (@Scottj1s) when it will be considered for the release? High priority for PowerToys. |
…-specific PRI files (#6376) (#6493) * Fix sparse-packaged apps unable to discover module-specific PRI files (#6376) * Fix sparse-packaged apps unable to discover module-specific PRI files Sparse-packaged apps have package identity (via AddPackageByUriAsync) but deploy resources as loose files next to the executable. GetDefaultPriFile() determines isPackaged=true for these apps (since they have identity), causing GetDefaultPriFileForCurentModule to pass "resources.pri" to MrmGetFilePathFromName — which only searches for that exact filename, skipping the [modulename].pri fallback that unpackaged apps receive. When the "resources.pri" search fails for apps with identity, fall back to the unpackaged discovery path (pass nullptr to MrmGetFilePathFromName) which triggers the broader search including "[modulename].pri" derived via PathCchRenameExtension from the process executable name. If the fallback also fails, return the original HRESULT from the "resources.pri" search so callers that check for specific errors (e.g., ERROR_FILE_NOT_FOUND) are not broken. Existing test coverage: - DefaultResourceManagerWithExePri validates the nullptr fallback mechanism - DefaultResourceManager validates error behavior when no PRI exists - DefaultResourceManagerWithResourcePri validates the normal packaged path A full sparse-app integration test requires actual sparse package registration (AddPackageByUriAsync) which is beyond unit test scope. Fixes: microsoft/microsoft-ui-xaml#10856 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: simplify flow, shorten comment, gate on file-not-found * Add backward-compatibility comment on return hr * Move backward-compat comment to fallback block for clarity * Keep comment sentences on single lines * Use existing IsResourceNotFound() helper instead of manual HRESULT checks * Merge two-line comment into single line Agent-Logs-Url: https://github.com/microsoft/WindowsAppSDK/sessions/ed36cfc6-52ad-414b-8e1a-dc16f413a97e Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> * Add containment for sparse PRI fallback fix Bug 62382643: gate the sparse PRI fallback with containment so it can be rolled back if needed. * Fix containment version to WinAppSDK_2_1_5 * Fix bug ID in containment comment * Contain all changed code inside containment gate * Use IsPackagedProcess() for package detection inside containment * Add MRTCore_SparsePackagedPriFallback to RuntimeCompatibilityChange enum * Revert "Add MRTCore_SparsePackagedPriFallback to RuntimeCompatibilityChange enum" This reverts commit 068135d. --------- Co-authored-by: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: agniuks <41223743+agniuks@users.noreply.github.com>
…fic PRI files (#6376) (#6492) * Fix sparse-packaged apps unable to discover module-specific PRI files (#6376) * Fix sparse-packaged apps unable to discover module-specific PRI files Sparse-packaged apps have package identity (via AddPackageByUriAsync) but deploy resources as loose files next to the executable. GetDefaultPriFile() determines isPackaged=true for these apps (since they have identity), causing GetDefaultPriFileForCurentModule to pass "resources.pri" to MrmGetFilePathFromName — which only searches for that exact filename, skipping the [modulename].pri fallback that unpackaged apps receive. When the "resources.pri" search fails for apps with identity, fall back to the unpackaged discovery path (pass nullptr to MrmGetFilePathFromName) which triggers the broader search including "[modulename].pri" derived via PathCchRenameExtension from the process executable name. If the fallback also fails, return the original HRESULT from the "resources.pri" search so callers that check for specific errors (e.g., ERROR_FILE_NOT_FOUND) are not broken. Existing test coverage: - DefaultResourceManagerWithExePri validates the nullptr fallback mechanism - DefaultResourceManager validates error behavior when no PRI exists - DefaultResourceManagerWithResourcePri validates the normal packaged path A full sparse-app integration test requires actual sparse package registration (AddPackageByUriAsync) which is beyond unit test scope. Fixes: microsoft/microsoft-ui-xaml#10856 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: simplify flow, shorten comment, gate on file-not-found * Add backward-compatibility comment on return hr * Move backward-compat comment to fallback block for clarity * Keep comment sentences on single lines * Use existing IsResourceNotFound() helper instead of manual HRESULT checks * Merge two-line comment into single line Agent-Logs-Url: https://github.com/microsoft/WindowsAppSDK/sessions/ed36cfc6-52ad-414b-8e1a-dc16f413a97e Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> * Add containment for sparse PRI fallback fix Bug 62382643: gate the sparse PRI fallback with containment so it can be rolled back if needed. * Fix containment version to WinAppSDK_2_1_5 * Fix bug ID in containment comment * Contain all changed code inside containment gate * Use IsPackagedProcess() for package detection inside containment * Add MRTCore_SparsePackagedPriFallback to RuntimeCompatibilityChange enum * Revert "Add MRTCore_SparsePackagedPriFallback to RuntimeCompatibilityChange enum" This reverts commit 73d274f. --------- Co-authored-by: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: agniuks <41223743+agniuks@users.noreply.github.com>
…(supersedes #5828) (#6603) * Add fallback for MrmGetFilePathFromName * Update dev/MRTCore/mrt/Core/src/MRM.cpp Co-authored-by: Rafael Rivera <rafael@withinwindows.com> * Complete MrmGetFilePathFromName fallback: return S_OK with a valid path PR #5828 added a DefaultFallback search pass to restore the documented "always succeed, return a best-effort path" contract of MrmGetFilePathFromName (regressed in #4965 to return ERROR_FILE_NOT_FOUND, breaking ResourceManager creation when no resources.pri exists - #5814 / #5940). However DefaultFallback was unreachable: both terminal passes (ParentPathForFileName, exeDirForModulePri) jumped to Final, skipping it. The function therefore returned S_OK with *filePath == nullptr, which crashes callers that dereference the path (e.g. MrmCreateResourceManager rejects an empty path with E_INVALIDARG, and the GetFilePath unit test AVs on wcsstr). Changes: - MRM.cpp: route both terminal passes into DefaultFallback so it runs as the final pass; return S_OK with a non-null best-effort path (the provided filename, else resources.pri) under the base directory (if set) otherwise the module directory - matching pre-#4965 (legacy) behavior. Preserve the module directory since the parent-folder search mutates exeDir in place. - Helper.cpp (GetDefaultPriFile): the sparse-packaged [modulename].pri fallback gated on IsResourceNotFound(hr); since MrmGetFilePathFromName now returns S_OK, gate on actual file existence (CheckFile) instead, and only adopt the unpackaged result if it resolves to an existing file (avoids re-regressing #6376 / microsoft-ui-xaml#10856). - MrmTests.cpp: strengthen GetFilePath to assert the fallback path is under the module directory. - BypassTests.json: remove the now-passing UnitTest::BasicTest::GetFilePath and MrtCoreUnpackagedTests.TestClass.DefaultResourceManager entries so they gate again (they were bypassed in #5498 / #5919 after the #4965 regression, which is why the regression shipped undetected). Verified locally (x64 Debug): MrmUnitTest 21/21, MrtCoreUnpackagedTests 27/27. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: 王宇逸 <Strawberry_Str@hotmail.com> Co-authored-by: Rafael Rivera <rafael@withinwindows.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Fixes sparse-packaged apps (unpackaged + self-contained WinUI3 with identity via
AddPackageByUriAsync) failing to locate module-specific PRI files (e.g.,MyApp.priset viaProjectPriFileName).Why This Matters
Not an regression, it doesn't work from the first day.
While 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. This fix unblocks that scenario - without it, any sparse-packaged app with a custom PRI name fails to load resources.Problem
GetDefaultPriFile()determinesisPackaged=truefor sparse apps because they have package identity. This causesGetDefaultPriFileForCurentModuleto pass"resources.pri"toMrmGetFilePathFromName, which only searches for that exact filename - skipping the[modulename].prifallback that unpackaged apps (the one leverage sparse app) receive.When multiple apps share the same output directory, each needs its own module-specific PRI to avoid conflicts, but sparse apps could only find
resources.pri.Fix
When the packaged
"resources.pri"search fails for apps with identity, fall back to the unpackaged discovery path (passnullptrtoMrmGetFilePathFromName) which triggers the broader search including"[modulename].pri"derived from the process executable name.The fallback is gated on
IsResourceNotFound(hr)to ensure only genuine not-found conditions trigger it, avoiding masking real errors (e.g.,E_OUTOFMEMORY,E_ACCESSDENIED). If the fallback also fails, the original HRESULT from the"resources.pri"search is returned for backward compatibility so callers checking for specific errors (e.g.,ERROR_FILE_NOT_FOUND) are not broken.Changed file
dev/MRTCore/mrt/Microsoft.Windows.ApplicationModel.Resources/src/Helper.cppExisting test coverage
DefaultResourceManagerWithExePri— validates the nullptr fallback mechanismDefaultResourceManager— validates error behavior when no PRI existsDefaultResourceManagerWithResourcePri— validates the normal packaged pathA full sparse-app integration test requires actual sparse package registration (
AddPackageByUriAsync) which is beyond unit test scope.Validation
Builds clean with no warnings
/azp runpipeline validationA microsoft employee must use /azp run to validate using the pipelines below.
WARNING:
Comments made by azure-pipelines bot maybe inaccurate.
Please see pipeline link to verify that the build is being ran.
For status checks on the main branch, please use TransportPackage-Foundation-PR
(https://microsoft.visualstudio.com/ProjectReunion/_build?definitionId=81063&_a=summary)
and run the build against your PR branch with the default parameters.