Search code examples
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 https://stackoverflow.com/a/66187224/403671).