WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

Setting WindowsPackageType=None should delay-load all WinAppSDK import libraries

Open jonwis opened this issue 4 years ago • 1 comments

@niklasb-ms discovered that using WinAppSDK from an unpackaged app using dynamic dependencies can cause the exe to fail to launch with a "module not found" error. This appears to be caused by the exe getting a static-import record for dwritecore.dll, which isn't in the loader's paths until MddBoostrapInitialize is called. Switching to a LoadLibrary or a DELAYLOAD import of the DLL works fine.

So:

  • Unpackaged (like MSI) using WinAppSDK (any version)
  • App calls DWriteCoreCreateFactory in its WinMain
  • App crashes at launch with ERROR_MOD_NOT_FOUND

Potential solution:

When the project has <WindowsPackageType>None</WindowsPackageType> all WinAppSDK DLLs should be delay-loaded. This can be done with by adding a /delayload:dllname linker option, per https://docs.microsoft.com/en-us/cpp/build/reference/linker-support-for-delay-loaded-dlls?view=msvc-160

jonwis avatar Jul 25 '21 04:07 jonwis

The potential solution's a good one but slight clarification: "...all WinAppSDK DLLs with non-COM/WinRT exports should be delay-loaded". Only DLLs with exports others link with at build time are a concern (e.g. COM/WinRT's GetDllClassFactory is dynamically loaded so no issue). This narrows the problem to just WinAppSDK DLLs provided Flat-C APIs; most APIs are WinRT so not a problem.

I don't recall if VS emits warnings if you specify /delayload:foo but don't actually link to foo. Something we'll need to verify.

FYI this is only a problem for unpackaged apps, and only if they load a PE file with WinAppSDK imports before calling MddBootstrapInitialize(). @niklasb-ms had an exe that called the bootstrapper and an IAT with imports from DLLs in the WinAppSDK Framework package. It's not an issue if the exe only called the bootstrapper and DWrite calls were in a DLL not loaded when the exe loads. We can add /delayload for all DLLs in our .props files but we'll want some flexibility here

(Packaged apps don't have this problem as Windows creates their process with their resolved dependencies at birth. No bootstrap issue)

VS' DelayLoad has constaints. Notably, can't bind entrypoint forwarders, code referencing functions through global variables may be affected and can't delayload exported data just functions (though we strongly frown on the last regardless so it shouldn't be an issue). We'll need to make verify these aren't a problem.

DrusTheAxe avatar Jul 26 '21 22:07 DrusTheAxe