Microsoft-ui-xaml: FileOpenPicker, FileSavePicker, and FolderPicker break in WinUI3 Desktop

Created on 19 Jun 2020  路  18Comments  路  Source: microsoft/microsoft-ui-xaml

Describe the bug

The FileOpenPicker, FileSavePicker, and FolderPicker in the WinUI3 Desktop sample solution break and close the application.

Steps to reproduce the bug

  1. Clone the WinUI3 Problems FilePicker repository.
  2. Go to the FilePickerWinUI folder.
  3. Open the FilePickerWinUI solution in Visual Studio 2019 Preview.
  4. Build and run with Debug x64.
  5. Test each button

    A. FileOpenPicker

    1. Click the FileOpenPicker button.
    2. Select one or more files.
    3. Click [Open].
    4. The application will immediately close.
    

    B. FileSavePicker

    1. Click the FileSavePicker button.
    2. The application should crash with an error. See Screenshot#1
    

    C. FolderPicker

    1. Click the FolderPicker button.
    2. Select one folder.
    3. Click [Select Folder].
    4. The application will immediately close.
    

Expected behavior

We expect the application to display the path of the selected file(s) or folder.

We expect the FileOpenPicker, FileSavePicker, and FolderPicker to allow the user to select files or a folder.

Screenshots

FilePickerError

Screenshot#1 - Current Behavior (Error Message)

FilePickerAppearance

Screenshot#2 - Application Appearance

Version Info

NuGet package version:
[Microsoft.VCRTForwarders.140 1.0.6]
[Microsoft.WinUI 3.0.0-preview1.200515.3]

Targeting:
Target: Universal Windows
Target version: Windows 10, version 1809 (10.0; Build 17763)
Min version: Windows 10, version 1809 (10.0; Build 17763)

| Windows 10 version | Saw the problem? |
| :--------------------------------- | :-------------------- |
| Insider Build (xxxxx) | |
| November 2019 Update (18363) | |
| May 2019 Update (18362) | |
| October 2018 Update (17763) | Yes |
| April 2018 Update (17134) | |
| Fall Creators Update (16299) | |
| Creators Update (15063) | |

| Device form factor | Saw the problem? |
| :-------------------- | :------------------- |
| Desktop | Yes |
| Mobile | |
| Xbox | |
| Surface Hub | |
| IoT | |

Additional context

We copied the related C# code from the microsoft/WinUI-3-Demos.

You will see this in App.xaml.cs and MainWindow.xaml.cs.

If we set the Debug -> Debugger Type -> Application proccess to Native Only, then the FolderPicker will work without crashing. However, the other two buttons will still not work.

Area-Desktop bug needs-triage team-Reach winui3preview

Most helpful comment

@akanieski the As method used in Xaml-Controls-Gallery refers to WinRT.CastExtensions.As(this object value).
Maybe you need to add
using WinRT;

All 18 comments

@stevenbrix and @Scottj1s, @llongley thinks this is a CSWinrt issue. FYI.

I can't tell from the documentation, it could be that these pickers don't work in a Desktop (hwnd rather than CoreWindow) app.

It works if no debugger is attached, or if the Native Only debugger is attached. This seems like a tooling issue, or a Dot Net Core runtime issue. I believe these pickers worked fine on Xaml Islands.

I can't get any pickers to work at all in a Desktop (HWND) Win32 app using C++/WinRT.

necore\shell\lib\calleridentity\callerwindow_twinapi.cpp(116)\twinui.appcore.dll!00007FF8D3EC0BDC: (caller: 00007FF8D3E91E10) ReturnHr(1) tid(cd18) 80040155 Interface not registered
CallContext:[\PickSingleFileAsync\SingleStorageItemOperation]
Exception thrown at 0x00007FF905DD226C (KernelBase.dll) in App2.exe: WinRT originate error - 0x80070578 : 'Invalid window handle.'.
Exception thrown at 0x00007FF905DD226C in App2.exe: Microsoft C++ exception: winrt::hresult_error at memory location 0x000000305EF8CEE8.

winrt::fire_and_forget MainWindow::ShowPicker()
{
FileOpenPicker open;
open.SuggestedStartLocation(PickerLocationId::DocumentsLibrary);
open.FileTypeFilter().Append(L".txt");
auto file = co_await open.PickSingleFileAsync();
if (file)
{
}
}

EDIT:
I was pointed to a solution:
https://github.com/microsoft/WinUI-3-Demos/blob/0bc934a6716235a7f55e3f2a90f4dbb045a0697d/DemoBuildCpp/DemoBuildCpp/DemoBuildCpp/MainWindow.cpp#L140-L162

Since WinUI3 allows multiple windows on the same thread, the pickers can no longer assume there's just one and use it as the owner. You will need to use the IInitializeWithWindow interface to give the hint. Looks like the documentation has been updated to give some clues about this now:

FileOpenPicker and IInitializeWithWindow.

This issue is closed but I still face the same exact issue and I can not find a solution in this thread.
The InitializeWithWindow was already used in the question (see screenshots).

The given workaround to "set the Debug -> Debugger Type -> Application proccess to Native Only" works but the hability to debug Managed code is considered essential in our development workflow so is not a long term solution.

I use
Visual studio 16.7.5
.Net SDK 5.0.100-preview.5.20279.10
WinUI 3.0.0-preview2.200713.0

@angelazhangmsft are you able to confirm if this issue has been fixed? I thought there was an associated C#/WinRT issue for this, but am not seeing it in this thread.

@Scottj1s @j0shuams do you know if this issue has been fixed?

@angelazhangmsft From what I could tell these are not C#/WinRT issues. When I encountered this it was with XCG and had to do with their implementation -- I made an issue there https://github.com/microsoft/Xaml-Controls-Gallery/issues/559

Doesn't look like it has been fixed. @stevenbrix is this the issue you are talking about? I think it is a different issue than the one discussed here.

@j0shuams the symptom of this issue is that debugging a .NET app with just the native debugger works, but when you attach the managed debugger, you get an issue. I can't tell from that linked issue whether that is the same issue as this one, but my gut is that it isn't (I could be wrong of course)

@stevenbrix No I don't think the two are related (the issue I linked and this one). My understanding of the issue of this thread was it had to do with providing a window handle hint to Picker objects (FileSavePicker, etc). I don't think there is a C#/WinRT issue about debugging with managed being broken -- is that a C#/WinRT issue? I don't think I know enough to make that call; if you think so then youcould open an issue on that repo. Let me know how else I can help

Apologies for closing this and missing that IInitializeWithWindow was already being used. I'll reopen this until folks figure out whether this is a WinUI3 or CSWinRT issue and route the bug report accordingly.

@j0shuams the symptom of this issue is that debugging a .NET app with just the native debugger works, but when you attach the managed debugger, you get an issue. I can't tell from that linked issue whether that is the same issue as this one, but my gut is that it isn't (I could be wrong of course)

@stevenbrix This is actually a different issue than I was talking about. They say that switching the debugger solves the problem for FilePicker but not FileOpenPicker and FileSavePicker. @RealTommyKlein and I have discussed this and think it is some kind of issue with Desktop apps and file pickers. We came to this after I found this in a test run of XCG.

Sorry for leaving this dormant for so long. We have confirmed this is fixed in WinUI 3 Preview 3 which will be coming out soon - when that comes out we will also be publishing a new version of the XAML Controls Gallery app to its GitHub, which will show how to do this so you can see the app code needed.

In short, it looks like this (but again, this may not work fully until WinUI 3 Preview 3). Note how this uses C#/WinRT's "As" method instead of Marshal, which is not supported as part of C#/WinRT's way of doing projections:

```C#
[ComImport, System.Runtime.InteropServices.Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInitializeWithWindow
{
void Initialize([In] IntPtr hwnd);
}

[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto, PreserveSig = true, SetLastError = false)]
public static extern IntPtr GetActiveWindow();

// Open a text file.
FileOpenPicker open = new FileOpenPicker();
open.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
open.FileTypeFilter.Add(".rtf");

// When running on win32, FileOpenPicker needs to know the top-level hwnd via IInitializeWithWindow::Initialize.
if (Window.Current == null)
{
IInitializeWithWindow initializeWithWindowWrapper = open.As();
IntPtr hwnd = GetActiveWindow();
initializeWithWindowWrapper.Initialize(hwnd);
}

StorageFile file = await open.PickSingleFileAsync();
```

Sorry for leaving this dormant for so long. We have confirmed this is fixed in WinUI 3 Preview 3 which will be coming out soon - when that comes out we will also be publishing a new version of the XAML Controls Gallery app to its GitHub, which will show how to do this so you can see the app code needed.

In short, it looks like this (but again, this may not work fully until WinUI 3 Preview 3). Note how this uses C#/WinRT's "As" method instead of Marshal, which is not supported as part of C#/WinRT's way of doing projections:

[ComImport, System.Runtime.InteropServices.Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInitializeWithWindow
{
    void Initialize([In] IntPtr hwnd);
}

[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto, PreserveSig = true, SetLastError = false)]
public static extern IntPtr GetActiveWindow();



// Open a text file.
FileOpenPicker open = new FileOpenPicker();
open.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
open.FileTypeFilter.Add(".rtf");

// When running on win32, FileOpenPicker needs to know the top-level hwnd via IInitializeWithWindow::Initialize.
if (Window.Current == null)
{
    IInitializeWithWindow initializeWithWindowWrapper = open.As<IInitializeWithWindow>();
    IntPtr hwnd = GetActiveWindow();
    initializeWithWindowWrapper.Initialize(hwnd);
}

StorageFile file = await open.PickSingleFileAsync();

When I try the above with Microsoft.WinUI 3.0.0-preview3.201113.0 I get the below error:

Member 'FileOpenPicker.As<GeneralPage.IInitializeWithWindow>()' cannot be accessed with an instance reference; qualify it with a type name instead

Am I using the right nuget that includes this fix?

WinUI3 Preview 3 is already available since yesterday.
I tested the XAML Controls Gallery app and the RichEditBoxPage that uses a FileOpenPicker now work correctly with c# debugger on.
So the issue is fixed.
I don't have the error @akanieski mention.

I installed Visual Studio 16.9 Preview 1 (with a fix for installation bug)
git pulled the winui3preview branch of Xaml-Controls-Gallery
I tested XamlControlsGallery.Desktop.sln

@akanieski the As method used in Xaml-Controls-Gallery refers to WinRT.CastExtensions.As(this object value).
Maybe you need to add
using WinRT;

Thanks everybody for participating on this issue. I have updated the WinUI 3 Demos to the Preview 3 and it seems that every scenario works now.

I'll close the issue.

Regards!

Was this page helpful?
0 / 5 - 0 ratings