0

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.

Tam Bui
  • 2,940
  • 2
  • 18
  • 27
  • It seems that you need to disable the multi-instance feature of your WPF application. – Roy Li - MSFT Apr 21 '22 at 01:50
  • @RoyLi-MSFT is that some property of WPF applications that I'm not aware of? Can you please elaborate on what you mean? As I said before, I'm already applying a singleton pattern by implementing a mutex. But it doesn't help the already running instance of my app, it only prevents the 2nd one from launching. What I need is for the 1st instance of my app to get some notification that a URI activation is happening again. – Tam Bui Apr 21 '22 at 02:51
  • Well, the URI activation is designed for UWP apps. UWP apps are designed to be single instance by default, but desktop apps are not. Kill the 2nd instance and left one instance doesn't mean the desktop app is a single instance app. Every time the URI activation will try to launch another instance not the 1st instance. – Roy Li - MSFT Apr 21 '22 at 03:16
  • @RoyLi-MSFT I agree with you that from my experiments, every time the URI activation will try to launch another instance not the 1st instance. Am I correct in understanding your original reply hinted that there was a way to disable this multi-instance feature of the WPF application? Can you please explain how to do that? – Tam Bui Apr 21 '22 at 03:49
  • I'm not sure if WPF has such a function to achieve this, I'm saying this because I know that for another type of desktop application- a Windows APP SDK app, [multi-instance could be disabled](https://blogs.windows.com/windowsdeveloper/2022/01/28/making-the-app-single-instanced-part-3/). So if WPF could do the same, then it should help to achieve the behavior you want. – Roy Li - MSFT Apr 21 '22 at 05:37
  • 1
    *"Or do I need to do some other form of IPC, like named pipes or WCF on the 2nd instance of my app?"* – I'd expect this to the only solution for desktop applications. – Martin Prikryl Apr 21 '22 at 06:26

1 Answers1

2

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.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • That's exactly what I needed! In the second link I provided, I made the mistake of only looking at the SO summary of the blog post, which did not reference the named pipes at all. I should have known better. Thanks! – Tam Bui Apr 21 '22 at 15:12