Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unpackaged framework-dependent app crashes if fusion manifest not present/embedded #2634

Open
riverar opened this issue Jun 16, 2022 · 6 comments
Assignees
Labels
area-UndockedRegFreeWinRT bug Something isn't working

Comments

@riverar
Copy link
Contributor

riverar commented Jun 16, 2022

Describe the bug

In scenarios where the fusion manifest is not embedded into the output executable, an app bootstrapping with Windows App SDK will fail to start. This appears to have regressed since 1.0.0.

Repro project: repro.zip

Steps to reproduce the bug

  1. Open repro project provided above
  2. Compile/execute output
  3. Observe app does not start correctly
  4. Edit the .vcxproj and replace all instances of <EmbedManifest>false</EmbedManifest> with <EmbedManifest>true</EmbedManifest>.
  5. Compile/execute output
  6. Observe app starts correctly

Expected behavior

App to start correctly regardless of fusion manifest presence.

NuGet package version

1.1.1 ❌ Broken
1.1.0 ❌ Broken
1.0.4 ❌ Broken
1.0.3 ❌ Broken
1.0.2 ❌ Broken
1.0.1 ❌ Broken
1.0.0 ✔️ Works

Packaging type

Unpackaged

Windows version

Insider Build (xxxxx)

IDE

Visual Studio 2022

Additional context

Impacted Rust bindings, which does not use fusion manifests.

It appears the bootstrapping component is attempting to locate reg-free WinRT information. In non-framework-dependent apps, that is expected. In framework-dependent apps it is not. The fusion manifest in these scenarios will have very little aside from optional common controls/DPI flags.

Output window
'repro.exe' (Win32): Loaded 'C:\Sources\was-repros\redacted\x64\Debug\repro\repro.exe'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\ntdll.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\kernel32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\KernelBase.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\combase.dll'. Symbol loading disabled by Include/Exclude setting.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\ucrtbase.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\vcruntime140d.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\rpcrt4.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\msvcp140d.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\oleaut32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Sources\was-repros\redacted\x64\Debug\repro\Microsoft.WindowsAppRuntime.Bootstrap.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\vcruntime140_1d.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\msvcp_win.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\ucrtbased.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\ucrtbased.dll'. Symbols loaded.
'repro.exe' (Win32): Unloaded 'C:\Windows\System32\ucrtbased.dll'
'repro.exe' (Win32): Loaded 'C:\Windows\System32\ole32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\gdi32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\win32u.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\gdi32full.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\user32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\advapi32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\msvcrt.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\sechost.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\shell32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\imm32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\bcryptprimitives.dll'. Symbols loaded.
D:\a\_work\1\s\BuildOutput\Release\x64\WindowsAppRuntime_DLL\WindowsAppRuntimeInsights.h(53)\Microsoft.WindowsAppRuntime.Bootstrap.dll!00007FFC598324DB: (caller: 00007FFC5982E1C6) LogHr(1) tid(b6f8) 8007007E The specified module could not be found.
    Msg:[Unable to load resource dll. Microsoft.WindowsAppRuntime.Insights.Resource.dll] 
'repro.exe' (Win32): Loaded 'C:\Windows\System32\kernel.appcore.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\clbcatq.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\AppXDeploymentClient.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\Windows.ApplicationModel.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\WinTypes.dll'. Symbols loaded.
D:\a\_work\1\s\dev\WindowsAppRuntime_BootstrapDLL\MddBootstrap.cpp(776)\Microsoft.WindowsAppRuntime.Bootstrap.dll!00007FFC5982B0D9: (caller: 00007FFC59829C2F) LogHr(2) tid(b6f8) 80040010 Object is not in any of the inplace active states
    Msg:[Bootstrap.Intitialize: Scanning packages for Major.Minor=1.1, Tag=, MinVersion=1001.524.1918.0] CallContext:[\Initialize] 
'repro.exe' (Win32): Loaded 'C:\Windows\System32\Windows.StateRepositoryCore.dll'. Symbols loaded.
D:\a\_work\1\s\dev\WindowsAppRuntime_BootstrapDLL\MddBootstrap.cpp(865)\Microsoft.WindowsAppRuntime.Bootstrap.dll!00007FFC5982B85C: (caller: 00007FFC59829C2F) LogHr(3) tid(b6f8) 80040011 Not able to convert object
    Msg:[Bootstrap.Intitialize: Microsoft.WinAppRuntime.DDLM.1000.516.2156.0-x6_1000.516.2156.0_x64__8wekyb3d8bbwe not applicable. Version doesn't match MinVersion criteria (Major.Minor=1.1, Tag=, MinVersion=1001.524.1918.0)] CallContext:[\Initialize] 
D:\a\_work\1\s\dev\WindowsAppRuntime_BootstrapDLL\MddBootstrap.cpp(865)\Microsoft.WindowsAppRuntime.Bootstrap.dll!00007FFC5982B85C: (caller: 00007FFC59829C2F) LogHr(4) tid(b6f8) 80040011 Not able to convert object
    Msg:[Bootstrap.Intitialize: Microsoft.WinAppRuntime.DDLM.1000.516.2156.0-x8_1000.516.2156.0_x86__8wekyb3d8bbwe not applicable. Version doesn't match MinVersion criteria (Major.Minor=1.1, Tag=, MinVersion=1001.524.1918.0)] CallContext:[\Initialize] 
D:\a\_work\1\s\dev\WindowsAppRuntime_BootstrapDLL\MddBootstrap.cpp(885)\Microsoft.WindowsAppRuntime.Bootstrap.dll!00007FFC5982BB5E: (caller: 00007FFC59829C2F) LogHr(5) tid(b6f8) 80040012 Not able to perform the operation because object is not given storage yet
    Msg:[Bootstrap.Intitialize: Microsoft.WinAppRuntime.DDLM.1001.524.1918.0-x6_1001.524.1918.0_x64__8wekyb3d8bbwe is applicable (Major.Minor=1.1, Tag=, MinVersion=1001.524.1918.0)] CallContext:[\Initialize] 
D:\a\_work\1\s\dev\WindowsAppRuntime_BootstrapDLL\MddBootstrap.cpp(908)\Microsoft.WindowsAppRuntime.Bootstrap.dll!00007FFC5982C486: (caller: 00007FFC59829C2F) LogHr(6) tid(b6f8) 80040013     Msg:[Bootstrap.Intitialize: Microsoft.WinAppRuntime.DDLM.1001.524.1918.0-x6_1001.524.1918.0_x64__8wekyb3d8bbwe best matches the criteria (Major.Minor=1.1, Tag=, MinVersion=1001.524.1918.0) of 172 packages scanned] CallContext:[\Initialize] 
'repro.exe' (Win32): Loaded 'C:\Windows\System32\twinui.appcore.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\windows.storage.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\OneCoreUAPCommonProxyStub.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\SHCore.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\daxexec.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\container.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\userenv.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\usermgrcli.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\Windows.StateRepositoryClient.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\Windows.StateRepositoryPS.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\LicenseManagerApi.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\capauthz.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\ntmarta.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\shlwapi.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\uxtheme.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\propsys.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\profapi.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\cfgmgr32.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\apphelp.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\networkexplorer.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\Windows.FileExplorer.Common.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\edputil.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\urlmon.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\iertutil.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\srvcli.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\netutils.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\cldapi.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\sspicli.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\AppResolver.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\BCP47Langs.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\mpr.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\OneCoreCommonProxyStub.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\execmodelproxy.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Program Files\WindowsApps\Microsoft.WindowsAppRuntime.1.1_1001.524.1918.0_x64__8wekyb3d8bbwe\Microsoft.WindowsAppRuntime.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\powrprof.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\rometadata.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\powrprof.dll'. Symbols loaded.
'repro.exe' (Win32): Loaded 'C:\Windows\System32\xmllite.dll'. Symbols loaded.
'repro.exe' (Win32): Unloaded 'C:\Windows\System32\powrprof.dll'
'repro.exe' (Win32): Loaded 'C:\Windows\System32\umpdc.dll'. Symbols loaded.
D:\a\_work\1\s\dev\UndockedRegFreeWinRT\urfw.cpp(416)\Microsoft.WindowsAppRuntime.dll!00007FFC5901C617: (caller: 00007FFC5902FA12) ReturnHr(1) tid(b6f8) 8007000E Not enough memory resources are available to complete this operation.
D:\a\_work\1\s\dev\WindowsAppRuntime_DLL\dllmain.cpp(30)\Microsoft.WindowsAppRuntime.dll!00007FFC5902FBF3: (caller: 00007FFC5903B7EB) FailFast(1) tid(b6f8) 8007000E Not enough memory resources are available to complete this operation.
Unhandled exception at 0x00007FFC5902FBF3 (Microsoft.WindowsAppRuntime.dll) in repro.exe: Fatal program exit requested.

@BenJKuhn BenJKuhn added area-Deployment Issues related to packaging, installation, runtime (e.g., SelfContained, Unpackaged) bug Something isn't working labels Jun 16, 2022
@DrusTheAxe
Copy link
Member

That's surprising - I thought I'd built apps using WinAppSDK/fwk-dependent and no Fusion manifest. Will investigate.

It appears the bootstrapping component is attempting to locate reg-free WinRT information...In framework-dependent apps [that is not expected]

Checking for Fusion manifest is expected. Failing when not found or embedded (even if it has no RegFreeWinRT info) is not expected.

The WinRT activation+metadata lookup hunt sequence1,2,3 with WinAppSDK is...

  1. Package Graph
  2. Undocked RegFree WinRT (URFW)
  3. OS

When the Bootstrapper fires in an app using WinAppSDK framework-dependent it should find WinAppSDK types via 1 and OS types via 3 (e.g. PackageManager). The latter case will cause lookups to walk through the Fusion manifest (if any) but it should be fine if the executable has none (or an embedded one w/o any RegFree info).

The fusion manifest in these scenarios will have very little aside from optional common controls/DPI flags.

In the simple case. It could have more e.g. if a LolzCatzVidz project uses WinAppSDK framework-dependent and a AwesomeSauceVideoPlaybackWidget WinRT object from another library in a self-contained way.


1 WinRT types in the Windows.* namespace must be defined by Windows. The PackageGraph and RegFreeWinRT are ignored for Windows.* types.

2 Windows (without WinAppSDK) has a slightly different ordering: 1=PackageGraph, 2=RegFreeWinRT (19H1+).

3 Langauge projections can supplment the hunt sequence e.g. C++/WinRT and C#/WinRT add a step 4. Crawl file system to look for a DLL containing the type if not found by one of the other mechanisms.

@DrusTheAxe DrusTheAxe added area-UndockedRegFreeWinRT and removed area-Deployment Issues related to packaging, installation, runtime (e.g., SelfContained, Unpackaged) labels Jun 17, 2022
@riverar
Copy link
Contributor Author

riverar commented Jun 17, 2022

Given that the package graph satisfied the hunt, I don't think WAS should have ever attempted to look for URFW / OS metadata right? Or are you searching all sources for the best candidate? (If so, would be great to see that debug spew added in a future release I think.)

@DrusTheAxe
Copy link
Member

DrusTheAxe commented Jun 18, 2022

I don't think WAS should have ever attempted to look for URFW / OS metadata right

For what type? And used how?

if (RoActivateInstance(acid) == REGDB_E_CLASSNOTFOUND)

isn't an unusual "use X if available" recipe, just like

if (CoCreateInstance(clsid) == REGDB_E_CLASSNOTFOUND)

It depends on what ACID is being looked for when this went sideways.

Or are you searching all sources for the best candidate?

Not COM/WinRT. That's purely "Find X, and 1st match wins" model (same as it's been for decades)

Something seems fishy but I can't put my finger on it. Yet. I need to do some poking and prodding...

@DrusTheAxe
Copy link
Member

TL;DR UndockedRegFreeWinRT has a few discrepancies from Windows' RegFreeWinRT behavior. Putting together some tests to repro and then verify changes.

UndockedRegFreeWinRT (URFW) will load an Fusion manifest embedded for an exe or dll or a file if not exe|dll

HRESULT LoadManifestFromPath(std::wstring path)
{
    if (path.size() < 4)
    {
        return COR_E_ARGUMENT;
    }
    std::wstring ext(path.substr(path.size() - 4, path.size()));
    if ((CompareStringOrdinal(ext.c_str(), -1, L".exe", -1, TRUE) == CSTR_EQUAL) ||
        (CompareStringOrdinal(ext.c_str(), -1, L".dll", -1, TRUE) == CSTR_EQUAL))
    {
        return LoadFromEmbeddedManifest(path.c_str());
    }
    else
    {
        return LoadFromSxSManifest(path.c_str());
    }
}

That's not how Windows does it. Windows will load an embedded manifest if exists, and then from a file (as an override). Supposed to give devs the easy 'embed when built' and admins the ability to 'provide via file and override the embedded (if any)'.

And that's only called once via ExtRoLoadCatalog() -- only called in DllMain() when Microsoft.WindowsAppRuntime.dll.

So LoadFromEmbeddedManifest() is called for exe+dll (and LoadFromSxSManifest() never is. Problem #1.

And even if we have an embedded manifest we're not looking for a file manifest (as an admin override). Problem #2.

LoadFromEmbeddedManifest() looks for the resource via LoadLibrary, FindResource(), LoadResource(), LockResource() and any failure will return ERROR_FILE_NOT_FOUND but these functions all have error info via GetLastError(). Problem #3.

Lookup of the embedded manifest resource is IF (FindResource(1)!=OK) THEN FindResource(2). That's based on winuser.h line 314+

#define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE( 1)
#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2)
#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3)

1=CREATEPROCESS_MANIFEST_RESOURCE_ID == exe

2=ISOLATIONAWARE_MANIFEST_RESOURCE_ID == dll

3=ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID Remarks mention "This is never used by the loader." and it's not otherwise interesting to URFW so we can ignore it.

We're always checking id 1+2. We should only check 1 for exe and 2 for dl. Problem #4.

Whipping up a test suite for the various permutations and then fixes.

@DrusTheAxe
Copy link
Member

Oops! Sorry I missed this question earlier

Given that the package graph satisfied the hunt

UndockedRegFreeWinRT resolves Fusion + MSIX manifests at different times - DLL load vs 1st-use.

Fusion manifest resolution occurs in Microsoft.WindowsAppRuntime.dll's DllMain() when the DLL's loaded. Whatever answer's found is used until the DLL unloads. An embedded file can't change for the life of the DLL in the process, and the file (if any) is expected to match (or at least any changes after load wouldn't affect).

This differs from URFW's package graph support. That can change dynamically over the life of the process so that's resolved on 1st use as needed (i.e. just-in-time). As that's based on appxmanifest.xml and packages should be immutable once installed the manifest itself wouldn't change, we simply don't know which packages may be needed until later when we use WinRT activation (or metadata) APIs. We walk the package graph looking for answers and if a package's manifest hasn't been loaded yet it's loaded and cached for all successive uses of that package's manifest.

I don't think WAS should have ever attempted to look for URFW Fusion / OS metadata

Small correction. Technically we use URFW to resolve Fusion+MSIX manifested WinRT metadata. URFW is the code altering WinRT's activation+metadata lookup to also use our Fusion+MSIX data.

@riverar
Copy link
Contributor Author

riverar commented Jun 20, 2022

Very happy to see you tracked it down and we're going to see URFW support loose fusion manifests again. That will make things a lot easier for Rust where there's no easy access to MT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-UndockedRegFreeWinRT bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants