0

We encounter a problem using Microsoft.Win32.OpenFileDialog in a WPF app (targeting .NET Framework 4.7.2).

We want to be able to import multiple files from a smartphone connected to a computer via USB connection. However, it seems impossible to do so using the OpenFileDialog, because it fires message box "Cannot open multiple items from this location. Try selecting a single item instead.". You can reproduce it using this simple code and selecting at least 2 pictures from your smartphone:

var openFileDialog = new Microsoft.Win32.OpenFileDialog();
openFileDialog.Multiselect = true;
openFileDialog.ShowDialog();

This problem is known (see here and here) and related to the MTP protocol. The problem does not occur with a smartphone connected using the alternative "USB Mas Storage" (UMS), but this option is not available on modern smartphones.

The UWP FileOpenPicker seems to handle better the selection of multiple items (see here to see how to use it in a WPF app) but we accounter an InvalidCastException when using PickMultipleFilesAsync. The problem is described here and the answers suggest that FileOpenPicker cannot be used in WPF .NET Framework apps.

As said in the comments, an other way to achieve this would be to implement a file picker from skratch, using the MTP protocol for the smartphone devices. The downside of this approach is that the .NET and UWP file pickers offer a lots of great features and are fully integrated to the OS.

We have run out of ideas to solve this problem, so my question is:

Is there a way to import multiple files from a smartphone using the Windows file picker in a WPF app targeting .NET Framework?

The same question has been asked on the Microsoft Q&A.

Max
  • 1,810
  • 3
  • 26
  • 37
  • it sounds like you're stuck but you can always implement your own file open dialog and handle multiple files, even in serial if the issue is higher than just the open file dialog. – XAMlMAX Nov 28 '20 at 23:50
  • @XAMlMAX Yes implementing a new file open dialog can be a solution, but it would mean having a dedicated windows for smartphone import, which is not the best for us. I hoped to find an "official" solution. For the record, Microsft Edge has the same limitation (when importing files in a web form) while Microsoft Word handles it (I guess it uses the UWP pciker). – Max Nov 30 '20 at 11:10
  • Actually, once you implement that File picker yourself, you can then use it through ought of your app. It won't affect anything apart from adding you functionality to handle those edge cases. I know what you mean by "official" but I think this has more to do with how og was implemented and to make that work you would probably have to do some PInvoke magic. I am assuming you have the file picker behind a service. – XAMlMAX Nov 30 '20 at 11:40
  • Yes, I would have a custom file picker for the all app. The main cons I see with this approch is that the Windows default file picker have a lot of great features (access to the Quick Access folders, the address bar, the ribbon, the search bar, etc.), which works great and evolve with Windows. Implementing all of them is not a simple task. – Max Dec 01 '20 at 10:56
  • @XAMlMAX I found an answer to my question using the IFileOpenDialog interface. I'm reading back your comments, maybe that what you had in mind? I did not know that you could customize the Windows file picker that way. – Max Sep 02 '21 at 14:59

1 Answers1

1

I'm a bit late to reply but I found the solution thanks to the Microsoft Q&A thread.

As far as I know, it's not possible to select multiple files from a MTP device using the Microsoft.Win32.OpenFileDialog because you can not set all the IFileOpenDialog options.

As a result, you need to use your own IFileOpenDialog to set the options: be sure to add the FOS_ALLOWMULTISELECT option and remove the FOS_FORCEFILESYSTEM:

ComFileDialog.IFileOpenDialog fileOpenDialog = null;
ComFileDialog.IShellItemArray shellItemArray = null;
ComFileDialog.IShellItem shellItem = null;
try
{
    // Set options
    fileOpenDialog = (ComFileDialog.IFileOpenDialog)new ComFileDialog.FileOpenDialogRCW();
    fileOpenDialog.GetOptions(out var options);
    options |= ComFileDialog.FOS_ALLOWMULTISELECT | ComFileDialog.FOS_FILEMUSTEXIST | ComFileDialog.FOS_PATHMUSTEXIST;
    fileOpenDialog.SetOptions(options);

    // Show window
    if (fileOpenDialog.Show() != ComFileDialog.S_OK)
    {
        return;
    }

    // Get results
    if (fileOpenDialog.GetResults(out shellItemArray) != ComFileDialog.S_OK)
    {
        return;
    }

    uint items = 0;
    if (shellItemArray.GetCount(out items) != ComFileDialog.S_OK)
    {
        return;
    }

    // Result loop
    for (uint item = 0; item < items; item++)
    {
        try
        {
            if (shellItemArray.GetItemAt(item, out shellItem) != ComFileDialog.S_OK)
            {
                continue;
            }

            // Use the IShellItem
        }
        finally
        {
            if (shellItem != null)
            {
                Marshal.ReleaseComObject(shellItem);
                shellItem = null;
            }
        }
    }
}
finally
{
    if (fileOpenDialog != null)
    {
        Marshal.ReleaseComObject(fileOpenDialog);
    }
    if (shellItemArray != null)
    {
        Marshal.ReleaseComObject(shellItemArray);
    }
    if (shellItem != null)
    {
        Marshal.ReleaseComObject(shellItem);
    }
}

You can find find the Window Shell API Interfaces on pinvoke.net:

Max
  • 1,810
  • 3
  • 26
  • 37