uwpwinui-3

WinUI FileOpenPicker Throw Exception When Run Application In Administrator


Recently, I'm developing a tool with WinUI, but now I view a problem when using FileOpenPicker throw exception In Administrator model, you guys can reproduce this problem with following code.

private async void myButton_Click(object sender, RoutedEventArgs e)
{
    myButton.Content = "Clicked";
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();

    // See the sample code below for how to make the window accessible from the App class.
    var window = App.Current.m_window;

    // Retrieve the window handle (HWND) of the current WinUI 3 window.
    var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);

    // Initialize the file picker with the window handle (HWND).
    WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);

    // Set options for your file picker
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.FileTypeFilter.Add("*");

    // Open the picker for the user to pick a file
    var file = await openPicker.PickSingleFileAsync();
    if (file != null)
    {
        
         await Windows.Storage.FileIO.ReadTextAsync(file);
    }
    else
    {
        throw new Exception("file is null");
    }
}

For making sure the app run in Administrator, please edit project profile like this answer .


Solution

  • This doesn't work because FilePicker was designed in the UWP era for apps that only had an access to the local files through a sandbox in a enduser-controlled manner, so it's some sort of a by-design-limited thing. I don't see it as adding any value to developers when you're not running in the UWP sandbox, as administrator or not.

    What you can do though is reference a class library dll and use Windows forms (or WPF) OpenFileDialog from there.

    In fact, to enable Windows Forms usage from WinUI you can just create a class library project with nothing in it, like this for example (UseWindowsForms is the important thing here, adapt TargetFramework to your needs):

    enter image description here

    <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
            <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
            <UseWindowsForms>true</UseWindowsForms>
        </PropertyGroup>
    </Project>
    

    Now you can do this from your WinUI project running as admin:

    using System.Windows.Forms; // needs a reference on ClassLibrary1
    using Microsoft.UI;
    using Microsoft.UI.Xaml;
    
    namespace WithAdminApp
    {
        public sealed partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void myButton_Click(object sender, RoutedEventArgs e)
            {
                var ofd = new OpenFileDialog();
                if (ofd.ShowDialog(new Win32Window(Win32Interop.GetWindowFromWindowId(AppWindow.Id))) == DialogResult.OK)
                {
                    MessageBox.Show(ofd.FileName);
                }
            }
        }
    
        public class Win32Window(nint handle) : IWin32Window
        {
            public nint Handle => handle;
        }
    }
    

    PS: you can also write a wrapper (or reuse some existing one) over the IFileDialog interface wich is the root interface of Windows file dialogs implementation, but IMHO this is completely overkill in most cases (except maybe for nice folder browsing https://stackoverflow.com/a/66187224/403671).