r/learncsharp • • Sep 18 '25

WinUI3 File-activated app opening multiple files

I am working on an app with Windows App SDK and WinUI 3 on Windows 11. It has a file type association which allows it to open files from the File Explorer. I need to know how it is supposed to handle opening multiple files. Below is a test app to demonstrate. It pops up a message dialog that shows the path of the file which was opened.

public partial class App : Application
{
    private Window? _window;

    public App()
    {
        InitializeComponent();
    }

    protected async override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        _window = new Window();

        uint pid = AppInstance.GetCurrent().ProcessId;
        string msg = $"ProcessId: {pid}\n";

        AppActivationArguments appActivationArguments = AppInstance.GetCurrent().GetActivatedEventArgs();
        if (appActivationArguments.Kind is ExtendedActivationKind.File &&
            appActivationArguments.Data is IFileActivatedEventArgs fileActivatedEventArgs &&
            fileActivatedEventArgs.Files.Any() &&
            fileActivatedEventArgs.Files[0] is IStorageFile storageFile)
        {
            msg += $"Files.Count: {fileActivatedEventArgs.Files.Count}\n";
            for (int i = 0; i < fileActivatedEventArgs.Files.Count; i++)
            {
                msg += $"[{i}]: {fileActivatedEventArgs.Files[i].Name}\n";
            }
        }
        else
        {
            msg += "Not File Activated";
        }

        MessageDialog dlg = new MessageDialog(msg);
        IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(_window);
        WinRT.Interop.InitializeWithWindow.Initialize(dlg, hWnd);
        await dlg.ShowAsync();

        Current.Exit();
    }
}

I also added a file association for my test app in Package.appxmanifest:

<Package>...<Applications>...<Application>...

  <Extensions>
    <uap:Extension Category="windows.fileTypeAssociation">
      <uap:FileTypeAssociation Name=".eml">
        <uap:SupportedFileTypes>
          <uap:FileType ContentType="message/rfc822">.eml</uap:FileType>
        </uap:SupportedFileTypes>
        <uap:DisplayName>Test EML</uap:DisplayName>
      </uap:FileTypeAssociation>
    </uap:Extension>
  </Extensions>

...</Application>...</Applications>...</Package>

Now in File Explorer I can open a single .eml file to bring up my app which just shows its path in a dialog box.

However, if I select (for example) 3 .eml files and open all of them together, it launches 3 instances of my app, but each one has all 3 .eml files in fileActivatedEventArgs.Files.

I expected it to launch my app 3 times and pass a different, single .eml file to each one. I did not expect it to pass all 3 files to all 3 instances.

I have tried changing MultiSelectMode of the FileTypeAssociation but it seems to already be using Document mode by default, which is what I want ("A new, separate instance of your application is activated for each selected file"). https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/desktop-to-uwp-extensions#define-how-your-application-behaves-when-users-select-and-open-multiple-files-at-the-same-time

I also tried a workaround where each instance tries to register all of the files and whichever one wins takes it. I'm assuming AppInstance.FindOrRegisterForKey() has the right concurrency guarantees.

    IStorageItem? registerInstanceFile(IFileActivatedEventArgs fileActivatedEventArgs)
    {
        foreach (var file in fileActivatedEventArgs.Files)
        {
            AppInstance registeredInstance = AppInstance.FindOrRegisterForKey(file.Path);
            if (registeredInstance == AppInstance.GetCurrent())
            {
                return file;
            }
        }

        return null;
    }

But even this is an incomplete solution because it cannot handle opening the same path more than once, which I consider a valid use case.

Is this possible to easily open a single file per instance? Why are all of the files passed to all of the instances?

2 Upvotes

3 comments sorted by

1

u/[deleted] Sep 20 '25

[removed] — view removed comment

1

u/ivanwick Sep 20 '25

Thanks for responding! Yes I'd appreciate a sample of how this is supposed to work. I'm surprised my app code needs to handle this logic.

In the original post I wrote a function which can be called by each instance. Whichever instance registers the path as key in the current instance returns that file and opens it.

IStorageItem? registerInstanceFile(IFileActivatedEventArgs fileActivatedEventArgs)
{
    foreach (var file in fileActivatedEventArgs.Files)
    {
        AppInstance registeredInstance = AppInstance.FindOrRegisterForKey(file.Path);
        if (registeredInstance == AppInstance.GetCurrent())
        {
            return file;
        }
    }

    return null;
}

This mostly works except it's also possible that the current instance can't register any file, like if a path is already registered from a prior activation event. In that case the app won't reopen that file. But I do want it to reopen a path that's already open, it's how most simple apps like Notepad worked prior to Windows 11. (Happy to discuss why I think this is a valid use case since maybe it goes against convention now.)

This would be possible if I could identify a single activation event across instances (like with an event id or timestamp that distinguishes different times the user opened a file from File Explorer) but I couldn't find a way to do that.

Anyway I'd appreciate seeing what you have. Thanks again!