wpfdesktop-bridgemsix

How to detect URI activation on a WPF desktop package (WAP) after it has already launched?


I have a WPF desktop application that is MSIX-packaged using a Windows Application Package (WAP) project. I already know how to launch my WPF desktop app the first time using URI activation, by calling AppInstance.GetActivatedEventArgs() and then analyzing the arguments:

if (activatedEventArgs.Kind == ActivationKind.Launch)
{
    if (((LaunchActivatedEventArgs)activatedEventArgs).Arguments == "myactivationcode")
        // .. do something
}

But if a user runs the URI activation a 2nd time, while my app is already launched, I have learned that a new instance of my app is launched. This doesn't happen with UWP apps, just desktop apps. I can kill the 2nd instance to follow a desired singleton pattern, but what I want is for the first instance of my WPF app to get some event that lets it know to come back into view.

Things I've researched that have no answers that I can see:

  1. How to handle URI activation in a Windows Application Packaging Project?
  2. How can I handle file activation from a WPF app which is running as UWP?
  3. https://learn.microsoft.com/en-us/windows/uwp/launch-resume/handle-uri-activation#step-3-handle-the-activated-event

Does any such API or event exist for URI re-activation? Or do I need to do some other form of IPC, like named pipes or WCF on the 2nd instance of my app? Any help here would be greatly appreciated.


Solution

  • But if a user runs the URI activation a 2nd time, while my app is already launched, I have learned that a new instance of my app is launched.

    Whether a second instance is launched depends on the implementation of your custom Main method.

    In your second link, there is a link to blog post and a code example that demonstrates how to prevent another instance from being launched.

    It uses named pipes to communicate with the already running app instance and passes a serialized IActivatedEventArgs to it:

    [STAThread]
    static void Main(string[] args)
    {
        IActivatedEventArgs activatedEventArgs = AppInstance.GetActivatedEventArgs();
        using (Mutex mutex = new Mutex(false, AppUniqueGuid))
        {
            if (mutex.WaitOne(0, false))
            {
                new Thread(CreateNamedPipeServer) { IsBackground = true }
                    .Start();
    
                s_application = new App();
                s_application.InitializeComponent();
                if (activatedEventArgs != null)
                    s_application.OnProtocolActivated(activatedEventArgs);
                s_application.Run();
            }
            else if (activatedEventArgs != null)
            {
                //instance already running
                using (NamedPipeClientStream namedPipeClientStream
                    = new NamedPipeClientStream(NamedPipeServerName, AppUniqueGuid, PipeDirection.Out))
                {
                    try
                    {
                        namedPipeClientStream.Connect(s_connectionTimeout);
                        SerializableActivatedEventArgs serializableActivatedEventArgs = Serializer.Serialize(activatedEventArgs);
                        s_formatter.Serialize(namedPipeClientStream, serializableActivatedEventArgs);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, string.Empty, MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }
        }
    }
    

    Does any such API or event exist for URI re-activation?

    No

    Or do I need to do some other form of IPC, like named pipes or WCF on the 2nd instance of my app?

    Yes. Again, please refer to the mentioned blog post and accompanied code sample.