WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

Trying to use a FileOpenPicker while running the app as Administrator will crash the app

Open bogdan-patraucean opened this issue 2 years ago • 64 comments

Describe the bug

I am trying to open a File Picker but it works only if I am not using the app in elevation mode.

I'm getting the following error:

System.Runtime.InteropServices.COMException: 'Error HRESULT E_FAIL has been returned from a call to a COM component.'

The error appears when the code tries to execute the following line of code:

var file = await picker.PickSingleFileAsync();

Steps to reproduce the bug

  1. Create a WASDK app using version 1.4.2 and .NET 7
  2. Create an extension method so you can get the Window Handle

AppWindowExtension.cs

public static IntPtr GetHandle(this Microsoft.UI.Xaml.Window window)
{
    return WinRT.Interop.WindowNative.GetWindowHandle(window);
}
  1. Make the MainWindow available outside the App class

App.xaml.cs

public static Window MainWindow { get; private set; }
  1. Use the generated Button_Click event method to open the File Picker

MainWindow.xaml.cs

var picker = new FileOpenPicker();
picker.FileTypeFilter.Add("*");

InitializeWithWindow.Initialize(picker, App.MainWindow.GetHandle());

var file = await picker.PickSingleFileAsync();
  1. Build the app and try to Run as Administrator (it's not neccesary to configure elevation, just right click on the app works)
  2. Click the button to open the File Picker
  3. The app will crash :(

Expected behavior

I would expect this basic feature of picking a file to work even if I run the app as admin. My app has a lot of features that require elevation so getting rid of elevation is not an option for me.

Screenshots

No response

NuGet package version

1.4.2

Packaging type

Packaged (MSIX)

Windows version

Insider Build (xxxxx) (only on Windows 11)

IDE

Visual Studio 2022

Additional context

The same for FolderPicker

bogdan-patraucean avatar May 12 '22 20:05 bogdan-patraucean

I can confirm this bug. Any temporary workground for this?

Petrarca181 avatar May 20 '22 06:05 Petrarca181

@Petrarca181 yes, you can use directly PInvoke with CsWin32, but it's too much overhead if you ask me.

bogdan-patraucean avatar May 20 '22 12:05 bogdan-patraucean

我在WindowsAppSDK 1.1 Preview 3中使用FolderPicker时遇到了同样的问题,但是我的程序需要提升的权限 I had the same problem using FolderPicker under WindowsAppSDK 1.1 Preview 3, but my program required elevated privileges

qianchen36 avatar May 30 '22 15:05 qianchen36

@Petrarca181 I had to write my own with P/Invoke as well, It's basic and blocking / non-async, but gets the job done. Mostly copied from here.

using System;
using System.Runtime.InteropServices;

namespace Namespace
{

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct OpenFileName
    {
        public int lStructSize;
        public IntPtr hwndOwner;
        public IntPtr hInstance;
        public string lpstrFilter;
        public string lpstrCustomFilter;
        public int nMaxCustFilter;
        public int nFilterIndex;
        public string lpstrFile;
        public int nMaxFile;
        public string lpstrFileTitle;
        public int nMaxFileTitle;
        public string lpstrInitialDir;
        public string lpstrTitle;
        public int Flags;
        public short nFileOffset;
        public short nFileExtension;
        public string lpstrDefExt;
        public IntPtr lCustData;
        public IntPtr lpfnHook;
        public string lpTemplateName;
        public IntPtr pvReserved;
        public int dwReserved;
        public int flagsEx;
    }
    public static class FilePicker
    {

        [DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern bool GetOpenFileName(ref OpenFileName ofn);

        // usage: string filename = FilePicker.ShowDialog("C:\\", new string[] { "png", "jpeg", "jpg" }, "Image Files", "Select an Image File...");
        public static string ShowDialog(string startingDirectory, string[] filters, string filterName, string dialogTitle)
        {
            var ofn = new OpenFileName();
            ofn.lStructSize = Marshal.SizeOf(ofn);

            ofn.lpstrFilter = filterName;
            foreach (string filter in filters)
            {
                ofn.lpstrFilter += $"\0*.{filter}";
            }
            ofn.lpstrFile = new string(new char[256]);
            ofn.nMaxFile = ofn.lpstrFile.Length;
            ofn.lpstrFileTitle = new string(new char[64]);
            ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length;
            ofn.lpstrTitle = dialogTitle;
            if (GetOpenFileName(ref ofn))
                return ofn.lpstrFile;
            return string.Empty;
        }
    }
}

Then, you can call it like so:

string filename = FilePicker.ShowDialog("C:\\", new string[] { "png", "jpeg", "jpg" }, "Image Files", "Select an Image File...");

Or, if you must use naitive, you can work around this bug by running the rest of your code as admin, and this not as admin using impersonation.

lukedukeus avatar May 31 '22 23:05 lukedukeus

@manodasanW - crashes right at the PickSingleFileAsync() call.

AdamBraden avatar Jun 10 '22 00:06 AdamBraden

Yes, the problem still exist in WinUI3 with admin right. Please fix this!

derekhe avatar Aug 11 '22 14:08 derekhe

After discussing this with the filesystem team, the recommendation is to use the IFileOpenDialog apis from CSWin32. Here is a recent thread discussing this very topic - FileOpenDialog in CsWin32.

AdamBraden avatar Aug 29 '22 16:08 AdamBraden

@AdamBraden thank you for oferring this workaround. Any updates related to fixing the issue?

bogdan-patraucean avatar Aug 29 '22 17:08 bogdan-patraucean

What we could consider is creating a WinAppSDK wrapper around IFileDialog apis that provide an equivalent to the Picker apis. There are some opportunities to improve as well - StorageFiles are very heavyweight objects, and so we could consider returning something more optimized.

AdamBraden avatar Aug 29 '22 17:08 AdamBraden

@manodasanW, @MikeHillberg, @AdamBraden, hi! Any progress on this? I would appreciate an update. I'm curious how it goes.

bogdan-patraucean avatar Dec 04 '22 18:12 bogdan-patraucean

https://github.com/OpenKneeboard/OpenKneeboard/blob/e45bbfd46d953a562a9aaa59f38607472d9ea830/src/app/app-winui3/FilePicker.h and https://github.com/OpenKneeboard/OpenKneeboard/blob/e45bbfd46d953a562a9aaa59f38607472d9ea830/src/app/app-winui3/FilePicker.cpp are an example of using the IFileDialog workaround with modern C++ and cppwinrt

fredemmott avatar Dec 08 '22 04:12 fredemmott

WinUI3 makes me crazy for even basic stuff is not working. I return back to use electron.

derekhe avatar Dec 08 '22 11:12 derekhe

Indeed, such a simple thing like a FilePicker requires advanced knowledge and years of experience to understand. I'm a C# developer and I need to use unmanaged code with C++ to open a file picker...this is not how developement experience for WASDK should be.

bogdan-patraucean avatar Dec 13 '22 09:12 bogdan-patraucean

I just discovered that on Windows 10 it works. The problem is only on Windows 11.

bogdan-patraucean avatar Jan 07 '23 23:01 bogdan-patraucean

Same problem on windows 10 here.

fredemmott avatar Jan 08 '23 00:01 fredemmott

Same problem on windows 10 here.

what version do you have?

bogdan-patraucean avatar Jan 13 '23 23:01 bogdan-patraucean

same issue here on Win11

ivberg avatar Jan 20 '23 19:01 ivberg

It's been 9 months since the issue was reported, any hopes it will be fixed in WASDK 1.3?

bogdan-patraucean avatar Jan 25 '23 22:01 bogdan-patraucean

@fredemmott tested again on a clean installation of Windows 10 and no longer works

bogdan-patraucean avatar Jan 26 '23 22:01 bogdan-patraucean

The workaround is to use IFileDialog. For example:

        try 
        {
            PInvoke.CoCreateInstance(
                typeof(FileOpenDialog).GUID,
                null,
                CLSCTX.CLSCTX_INPROC_SERVER,
                out IFileDialog fileOpenDialog).ThrowOnFailure();
            fileOpenDialog.Show((HWND)App.MainWindow.GetHandle());

            fileOpenDialog.GetResult(out IShellItem item);
            item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out PWSTR name);
            Console.WriteLine(name.ToString());
            Marshal.FreeCoTaskMem(new IntPtr(name.Value));
        }
        catch (COMException)
        {
            // Handle canceled.
        }

AdamBraden avatar Feb 22 '23 16:02 AdamBraden

@AdamBraden what if you want to filter the file types? I tried to use IFileDialog but I did not manage to use filters.

bogdan-patraucean avatar Feb 22 '23 16:02 bogdan-patraucean

You tried SetFilter? https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfilter

AdamBraden avatar Feb 22 '23 16:02 AdamBraden

@AdamBraden yes, thank you for answering, but I couldn't understand what values to pass as parameters. If you could give me an example, I would really apreciate it. I'm new to unmanaged code.

bogdan-patraucean avatar Feb 22 '23 16:02 bogdan-patraucean

https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfiletypes might be what you want instead

https://github.com/OpenKneeboard/OpenKneeboard/blob/e45bbfd46d953a562a9aaa59f38607472d9ea830/src/app/app-winui3/FilePicker.cpp#L50 is a C++ example; I don't have a C# one.

In short, "name" in the struct is user-visible name (e.g. "Text File"), "pattern" is semicolon-separated globs, e.g. *.txt;*.log

fredemmott avatar Feb 22 '23 16:02 fredemmott

@fredemmott yes, that'a exactly how I tried I just wasn't able to find a fix for all the type errors I got. Those types don't exactly match with C# ones.

bogdan-patraucean avatar Feb 22 '23 16:02 bogdan-patraucean

You tried SetFilter? https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfilter

Replaced by SetFileTypes (I had posted samples for IFileDialog on MS forums, in C# and VB.NET)

castorix avatar Feb 22 '23 17:02 castorix

@castorix link please?

bogdan-patraucean avatar Feb 22 '23 17:02 bogdan-patraucean

@castorix link please?

I found old links... but they cutted the code :-( I will try to re-post, but you can find various implementations by typing for example in Google "IFileOpenDialog comimport github"

castorix avatar Feb 22 '23 17:02 castorix

@AdamBraden I noticed even WinUI 3 Gallery has the same problem in their FilePicker example - up til now. Running the app as Admin makes the function break. Conclusion: it's a WinUI/SDK bug. When will the actual problem be solved? :)

Jay-o-Way avatar Mar 21 '23 11:03 Jay-o-Way

@AdamBraden I noticed even WinUI 3 Gallery has the same problem in their FilePicker example - up til now. Running the app as Admin makes the function break. Conclusion: it's a WinUI/SDK bug. When will the actual problem be solved? :)

Probably in 2-3 years.

Petrarca181 avatar Mar 21 '23 13:03 Petrarca181