How to import multiple files from a smartphone in a WPF app?

Max 96 Reputation points
2020-12-21T09:08:07.257+00:00

We encounter a problem using Microsoft.Win32.OpenFileDialog in a WPF app (targeting .NET Framework 4.7.2). I already asked the same question on stackoverflow.

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.

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?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,660 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,164 questions
{count} votes

Accepted answer
  1. Max 96 Reputation points
    2021-08-31T09:54:52.377+00:00

    I'm a bit late to reply but I found the solution thanks to @Castorix31 comments and samples.

    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:

    0 comments No comments

0 additional answers

Sort by: Most helpful