microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.82k stars 321 forks source link

Self-Contained Deployment Redirect Activation COM Error #3439

Open justinsoderstrom opened 1 year ago

justinsoderstrom commented 1 year ago

Describe the bug

The AppInstance.RedirectActivationToAsync method throws COMException: Interface not registered (0x80040155) when using the SDK self-contained deployment model. This doesn't occur when using the default framework-dependent model.

This is a problem when you want to use self-contained deployment and enforce single instancing in the application. There isn't a supported way in the framework to do this in the self-contained deployment model while this bug exists.

Steps to reproduce the bug

I created a reproduction repository that features the issue: https://github.com/justinsoderstrom/winappsdk-selfcontained-activation-error. It is a packaged, Windows App SDK project using the SDK self-contained deployment model.

The Program.cs file demonstrates the reproduction usage of AppInstance.RedirectActivationToAsync.

Once you clone the repository, open it in Visual Studio 2022 do the following:

  1. Place a breakpoint on line 63 in the Program.cs file where AppInstance.RedirectActivationToAsync is used.
  2. Run the application using WinAppSDKSelfContainedActivationError (Package) profile with Debugging.
  3. While the app is running, try to launch the app again. The app is called WinAppSDKSelfContainedActivationError.
  4. Step over RedirectActivationToAsync statement
  5. You should see an System.AggregateException with an inner exception of COMException: Interface not registered (0x80040155)
System.AggregateException
  HResult=0x80131500
  Message=One or more errors occurred. (Interface not registered (0x80040155))
  Source=System.Private.CoreLib
  StackTrace:
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:line 1883
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:line 2733
   at System.Threading.Tasks.Task.Wait() in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:line 2607
   at WinAppSDKSelfContainedActivationError.Program.<>c__DisplayClass3_0.<RedirectActivationTo>b__0() in C:\Code\Other\WinAppSDKSelfContainedActivationError\WinAppSDKSelfContainedActivationError\Program.cs:line 63
   at System.Threading.Tasks.Task.InnerInvoke() in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:line 2397
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:line 2376
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs:line 268

Inner Exception 1:
COMException: Interface not registered (0x80040155)

If you open WinAppSDKSelfContainedActivationError.csproj and remove <WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained> to change back to framework-dependent deployment, the error will not occur and will work as expected.

Expected behavior

The AppInstance.Activated event should have been triggered and the OnActivated method in Program.cs on line 50 should have been called. There should be no COMException: Interface not registered (0x80040155) error raised.

Screenshots

COMBreakpoint COMException

NuGet package version

Windows App SDK 1.2.3: 1.2.230118.102

Packaging type

Packaged (MSIX)

Windows version

Windows 10 version 21H2 (19044, November 2021 Update)

IDE

Visual Studio 2022

Additional context

I only tested this on Windows 10, version 21H2 using packaged (MSIX) deployment. I do not know if this also occurs on other Windows versions.

The current workaround is to switch back to using framework-dependent deployment of the SDK, but that is not an option in all scenarios.

The issue reproduction repository README provides more information about the sample project. The Program.cs file implementation that demonstrates the issue follows the implementation guidelines from the Microsoft sample.

ritt-app commented 1 year ago

I ran into the same problem on Windows 11, version 22H2, with Windows App SDK 1.2.230217.4.

KWodarczyk commented 1 year ago

How come this went unnoticed through msft testing ? either there is a gap in the validation or msft knows about this and ignored that issue. I imagine that msft has tests for redirection cause it works in Framework dependent mode, so nobody thought to make a test for Self-contained mode ?

koenvd commented 1 year ago

Tried this as well but in our app this seems to be working while indeed the example app is crashing on my system as well.

We don't have a custom main method like in the example however (we're keeping the app single instance in the OnLaunched method). So not sure if other people in this thread are in that case as well.

I updated the code in the sample app to do: Task.Run(async () => { await keyInstance.RedirectActivationToAsync(args); redirectSemaphore.Release(); }); and noticed the OnActivated event handler is not being called. So somehow that mechanism seems to be stuck. After setting WindowsAppSDKSelfContained to false this indeed starts to work.

So not sure if this can be related to having a custom main method and somehow my app initialisation phase is a bit different where this starts working.

koenvd commented 1 year ago

Ok I really got side tracked by this but when:

  1. Starting from https://github.com/microsoft/WindowsAppSDK-Samples/tree/main/Samples/AppLifecycle/Instancing/cs-winui-packaged/CsWinUiDesktopInstancing
  2. Changing Program.cs to call RedirectActivationTo when a second instance is Launched.
  3. Making that app self contained

Then I also don't have a crash (This setup is similar as our setup).

But tbh I cannot spot where the difference is with your sample. Maybe the .wapproject 🤔

KWodarczyk commented 1 year ago

@koenvd is your app elevated ? Also custom main method was a workaround for elevation before it was fixed in 1.1

koenvd commented 1 year ago

@koenvd is your app elevated ? Also custom main method was a workaround for elevation before it was fixed in 1.1

No. Full trust. But both of them are.

koenvd commented 1 year ago

So yeah. Seems like the sample code that fails is also working if I copy paste to a Packaged App with a .wapproj project file.

No idea how this can have an impact though 🤔 . But maybe this can help you as well in short term @justinsoderstrom @ritt-app @KWodarczyk .

justinsoderstrom commented 1 year ago

@koenvd I think you may be onto something with packaging the project using Windows Application Packaging Project (.wapproj). I haven't dug much into it yet, but I was also able to create a quick SDK self-contained project using the same code as the example, but packages with the packaging project. The redirect logic seems to work on my machine with the small testing I did 😃

Here is the project I created: SelfContainedPackagedProject.zip

My example uses the single-project MSIX feature since that's the generally recommended format. I tried adding a packaging project to my example, but I run into a different error when trying to redirect. I still need to determine what's the difference between this project and the one that works.

koenvd commented 1 year ago

Yep. I also don't get what the difference is but seems to be somehow specific to a single project MSIX.

koenvd commented 1 year ago

Seems duplicate of https://github.com/microsoft/WindowsAppSDK/issues/3179 as well.

koenvd commented 1 year ago

Wondering @DrusTheAxe if you would have an idea what's going on here?

RedirectActivationToAsync is not working when the app is self contained and built with a single project MSIX. This seems to be working fine in an app built with a Packaging Project (.wapproj).

I just would like to understand if moving to .wapproj is then the temporary workaround for this issue. Or if there still might be a risk this might not work on some devices even if the app is built with a .wapproj project.

Thanks!

KWodarczyk commented 1 year ago

@koenvd instead of RedirectActivationToAsync you can use pinvoke version and works fine.

koenvd commented 1 year ago

Could you give a bit more details please @KWodarczyk? I'm not completely following tbh 🙂.

I need to PInvoke RedirectActivation somehow?

KWodarczyk commented 1 year ago

Not the "redirect activation" but you can use pinvoke to bring tunning app to front and kill the second one.

koenvd commented 1 year ago

Not sure this will work tbh @KWodarczyk . I mean not sure if a second app instance can give focus to the first instance. What I do know that works is if the RedirectActivation would work the first instance can use PInvoke to bring itself to the front.

And I can't pass the arguments as well off course in that mechanism.

So would prefer a fix or at least a working workaround 😄 .

KWodarczyk commented 1 year ago

you can use

        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

and

var appProcess = Process.GetProcessById((int)appInstance.ProcessId);
ShowWindow(appProcess.MainWindowHandle, SwRestore);

not sure how log we will wait for the fix

bogdan-patraucean commented 1 year ago

I just encountered the same issue on 1.3 preview.

bogdan-patraucean commented 1 year ago

@gabbybilka I think this two are duplicates. https://github.com/microsoft/WindowsAppSDK/issues/3179

koenvd commented 1 year ago

Could we have an update on this @bpulliam @gabbybilka ?

RedirectActivation in a self contained packaged app built without using a packaging project just doesn't seem to work 🤷‍♂️ .

justinsoderstrom commented 1 year ago

Agreed, I ultimately had to switch to a packaging project, and I've not run into any issues.

I would like to know if there are any potential issues with using this approach as the work around until a fix is released.

optsing commented 1 year ago

Still not working for versions 1.4.230811000-preview2 and 1.3.230724000. Same error. Packaged application with a single msix project and WindowsAppSDKSelfContained=true, tested on Windows 11. But it works when WindowsAppSDKSelfContained=false.

optsing commented 1 year ago

Same problem in release version 1.4 (1.4.230822000)

AdriaanLarcai commented 1 year ago

Still experiencing this issue in our unpackaged self contained release with the latest WindowsAppSDK, 1.4 (1.4.230822000).

Lightczx commented 9 months ago

It's the winrt::Microsoft::Windows::AppLifecycle::IAppActivationArguments that causing the error which iid is {14F99EAF-1580-5062-BDC8-D5D1C31138FB}

DominicMaas commented 8 months ago

Having the same issue over here as well

juanmalm commented 7 months ago

Same issue here

jonwis commented 7 months ago

Sorry for the long delay on getting to this.

The IAppActivationArguments interface uses metadata-based marshalling when sent between processes. While the metadata-based marshaller is not well documented (we'll fix this) it basically needs to map the runtimeclass of the type to a WinMD file visible to the application. Metadata in the WinMD is used to synthesize a marshaller. For this type, Microsoft.Windows.AppLifecycle.winmd from the Windows App SDK Runtime is necessary.

Apps that use the shared distribution (the framework package) get it automatically - FWP dependencies are resolved prior to app launch.

Apps that use self-contained (packaged or otherwise) distribution must include the .WinMD files from the framework package in their package. The project machinery should be copying this for you.

Apps that are unpackaged using the runtime framework must use the Bootstrapper to ensure the framework package is pulled into your process before using any part of the Windows App Runtime.

For folks still having this problem (hi @asklar !) can you let me know which configuration you're in?

If you're in unpackaged, make sure your build scripts are copying the WinMDs and support files into your deployment vehicle for delivery to your customers.

jonwis commented 7 months ago

Oh see also #2006 where @BenJKuhn talks about which files need to be retained vs copied.

I have a hunch that the "single file" dotnet publish mode is discarding the WinMDs and preventing this system from working. The mapping of runtimeclass to file name is trivial - we just look for Foo.Bar.Bas.Zot.WinMD then Foo.Bar.Bas.WinMD then Foo.Bar.WinMD, etc. There's no means of redirecting to say "hey this DLL contains this WinMD you can use!" at this time.

asklar commented 7 months ago

@jonwis I'm hitting this with single project framework package (via nuget)