I'm adding this new, more complete answer, though I don't pretend to completely understand this yet, and I did not do great job keeping track of what sample code I got from where. And, I should've gotten back to here months ago.
Note my logp() method which writes to the console, and MainPage.Inst.setOpeningString() which passes the URI along.
Windows/Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Microsoft.UI.Dispatching;
using Microsoft.Windows.AppLifecycle;
using Windows.ApplicationModel.Activation;
using Windows.Storage;
using System.Runtime.InteropServices;
using static OpenerAppMaui.Util;
namespace OpenerAppMaui.WinUI;
class Program {
[STAThread]
static void Main(string[] args) {
logp($"Program.Main({args.Length} args)");
WinRT.ComWrappersSupport.InitializeComWrappers();
bool isRedirect = DecideRedirection();
if (!isRedirect) {
logp("Program.Main() NOT isRedir");
Microsoft.UI.Xaml.Application.Start((p) =>
{
var context = new DispatcherQueueSynchronizationContext(
DispatcherQueue.GetForCurrentThread());
SynchronizationContext.SetSynchronizationContext(context);
// Important: has to go to the WINDOW APP "App" class (not the generic one)
new App();
logp("Program.Main() after new App()");
});
} else {
logp("Program.Main() IS isRedir (should get handled with OnActivated() below)");
}
}
private static bool DecideRedirection() {
bool isRedirect = false;
AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs();
ExtendedActivationKind kind = args.Kind;
logp($"Program.DecideRedirection() kind={kind}, ");
if (args.Kind == ExtendedActivationKind.Protocol) {
ProtocolActivatedEventArgs dataProtActEvArgs = args.Data as ProtocolActivatedEventArgs;
logp($"Program.DecideRedirection()) data= {dataProtActEvArgs.Uri}");
}
try {
AppInstance keyInstance = AppInstance.FindOrRegisterForKey("randomKey");
if (keyInstance.IsCurrent) {
keyInstance.Activated += OnActivated;
} else {
isRedirect = true;
logp($"Program.DecideRedirection() Redirect to keyInstance {keyInstance}");
RedirectActivationTo(args, keyInstance);
}
} catch (Exception ex) {
logp($"Program.DecideRedirection() Exception, ex={ex.Message}");
}
return isRedirect;
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr CreateEvent(
IntPtr lpEventAttributes, bool bManualReset,
bool bInitialState, string lpName);
[DllImport("kernel32.dll")]
private static extern bool SetEvent(IntPtr hEvent);
[DllImport("ole32.dll")]
private static extern uint CoWaitForMultipleObjects(
uint dwFlags, uint dwMilliseconds, ulong nHandles,
IntPtr[] pHandles, out uint dwIndex);
private static IntPtr redirectEventHandle = IntPtr.Zero;
// Do the redirection on another thread, and use a non-blocking
// wait method to wait for the redirection to complete.
public static void RedirectActivationTo( AppActivationArguments args, AppInstance keyInstance) {
redirectEventHandle = CreateEvent(IntPtr.Zero, true, false, null);
Task.Run(() =>
{
keyInstance.RedirectActivationToAsync(args).AsTask().Wait();
SetEvent(redirectEventHandle);
});
uint CWMO_DEFAULT = 0;
uint INFINITE = 0xFFFFFFFF;
_ = CoWaitForMultipleObjects(
CWMO_DEFAULT, INFINITE, 1,
new IntPtr[] { redirectEventHandle }, out uint handleIndex);
}
private static void OnActivated(object sender, AppActivationArguments args) {
ExtendedActivationKind kind = args.Kind;
// this for reassurance that I've got the right instance (original launch) doing the work.
AppActivationArguments thisArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
ExtendedActivationKind thisInstanceArgsKind = thisArgs.Kind;
logp($"Program.OnActivated() kind={kind}, thisInstanceArgsKind={thisInstanceArgsKind}"); // s/b, protocol & launch
if (args.Kind == ExtendedActivationKind.Protocol) {
ProtocolActivatedEventArgs dataProtActEvArgs = args.Data as ProtocolActivatedEventArgs;
logp($"Program.OnActivated() data= {dataProtActEvArgs.Uri}");
MainThread.BeginInvokeOnMainThread( ()=> { // hooray! this works! (12/30/22)
var openStr = dataProtActEvArgs.Uri.ToString();
logp($"Program.OnActivated() setting openStr: {openStr}");
MainPage.Inst.setOpeningString(openStr );
logp($"Program.OnActivated() openStr set");
});
}
}
}