Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileOpenPicker PickMultipleFilesAsync Break in WinUI3 Desktop #467

Closed
eleanorleffler opened this issue Feb 15, 2021 · 52 comments
Closed

FileOpenPicker PickMultipleFilesAsync Break in WinUI3 Desktop #467

eleanorleffler opened this issue Feb 15, 2021 · 52 comments
Assignees
Labels
area-Infrastructure Build, test, source layout, package construction (TODO: move to Deployment, DeveloperTools)

Comments

@eleanorleffler
Copy link

Describe the bug

The FileOpenPicker in WinUI3 Preview4 Desktop sample solution breaks and closes the application when trying to open multiple items. Exception details below in the last section.

Steps to reproduce the bug

  1. Clone the WinUI3 Preview4 Problems FilePicker repository.
  2. Go to the FilePickerWinUIPreview4 folder.
  3. Open the FilePickerWinUIPreview4 solution in Visual Studio 2019 Preview.
  4. Build and run with Debug x64.
  5. Click the second / bottom button "FileOpenPicker: Multiple Files". (The first button should work as expected.)
  6. Select one or more files.
  7. Click "Open". Crash should occur.

Expected behavior

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

We expect the FileOpenPicker to allow the user to select multiple files as it does in UWP.

Screenshots

ExpectedBehavior

CurrentBehavior2

Screenshot#1a and 1b - Current Behavior (Single File working and Crash Error Message)

CurrentBehavior1

Screenshot#2 - Expected Behavior (File paths of selected files)

Version Info

NuGet package version:

[Microsoft.WinUI 3.0.0-preview4.210210.4]

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

Windows app type:

UWP Win32
Yes
Windows 10 version Saw the problem?
Insider Build (xxxxx)
May 2020 Update (19041)
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
Xbox
Surface Hub
IoT

Additional context

Exception Details

System.Reflection.TargetInvocationException
HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=System.Private.CoreLib
StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at WinRT.SingleInterfaceOptimizedObject..ctor(Type type, IObjectReference objRef)
at Windows.Storage.Pickers.FilePickerSelectedFilesArray.<.ctor>b__8_1()
at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy1.CreateValue() at System.Lazy1.get_Value()
at Windows.Storage.Pickers.FilePickerSelectedFilesArray.AsInternal(InterfaceTag`1 _)
at Windows.Storage.Pickers.FilePickerSelectedFilesArray.GetEnumerator()
at FileOpenPickerWinUIPreview4.MainWindow.<fileOpenPickerMultipleButton_Click>d__2.MoveNext() in \FileOpenPickerWinUIPreview4\FileOpenPickerWinUIPreview4\MainWindow.xaml.cs:line 60

This exception was originally thrown at this call stack:
[External Code]

Inner Exception 1:
COMException: The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))

@eleanorleffler eleanorleffler changed the title [Preview 4] FileOpenPicker PickMultipleFilesAsync Break [Preview 4] FileOpenPicker PickMultipleFilesAsync Break in WinUI3 Desktop Feb 15, 2021
@StephenLPeters
Copy link

@Scottj1s and @stevenbrix is this cswinrt related?

@codendone
Copy link
Contributor

See #466 for more information on why this doesn't work and the workaround.

@eleanorleffler
Copy link
Author

eleanorleffler commented Feb 17, 2021

Hi @codendone, while the # 4192 workaround does work for the single file picker, the workaround not seem to work for the multiple file picker.

As soon as I changed it to this

        //var folder = await filePicker.PickSingleFileAsync();
        //myText.Text = folder != null ? folder.Path : string.Empty;

        var files = await filePicker.PickMultipleFilesAsync();
        foreach (StorageFile file in files)
        {
            myText.Text += file.Path;
        }

It crashes, just like my example solution that we provided as a Preview3 solution, and now as a Preview4 solution.

@marb2000
Copy link

@eleanorleffler thanks opening the bug and share the code. I could repro this.

I noticed that the doc of this API has the UWP label. I don't know if this means that this API won't work in Win32 apps.

Shows the file picker so that the user can pick multiple files. (UWP app)

I need help from the Project Reunion folks, this API is out of the WinUI domain. @jonwis, can you help us to know what is happening here?

We get:

COMException: The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))

Below you can find the code snipped:

 public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }

        private async void fileOpenPickerMultipleButton_Click(object sender, RoutedEventArgs e)
        {
            FileOpenPicker picker = new FileOpenPicker();

            IInitializeWithWindow initializeWithWindowWrapper = picker.As<IInitializeWithWindow>();
            var hwnd = this.As<IWindowNative>().WindowHandle;
            initializeWithWindowWrapper.Initialize(hwnd);

            picker.ViewMode = PickerViewMode.List;
            picker.SuggestedStartLocation = PickerLocationId.Desktop;
            picker.FileTypeFilter.Add(".txt");

            var filesToOpen = await picker.PickMultipleFilesAsync();
            string text = string.Empty;
            foreach (StorageFile storageFile in filesToOpen)
            {
                text += storageFile.Path + Environment.NewLine;
            }
            fileOpenPickerMultipleTextBlock.Text = text;
        }
        public static void InitializeWithWindow(Object obj, Window window)
        {
            // When running on win32, FileOpenPicker needs to know the top-level hwnd via IInitializeWithWindow::Initialize.
            if (Window.Current == null)
            {
                IInitializeWithWindow initializeWithWindowWrapper = obj.As<IInitializeWithWindow>();
                var hwnd = window.As<IWindowNative>().WindowHandle;
                initializeWithWindowWrapper.Initialize(hwnd);
            }
        }

    }

    [ComImport]
    [Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IInitializeWithWindow
    {
        void Initialize([In] IntPtr hwnd);
    }
    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("EECDBF0E-BAE9-4CB6-A68E-9598E1CB57BB")]
    internal interface IWindowNative
    {
        IntPtr WindowHandle { get; }
    }

@marb2000
Copy link

Transferring issue to the Project Reunion. It's not a WinUI issue.

@marb2000 marb2000 transferred this issue from microsoft/microsoft-ui-xaml Feb 20, 2021
@ghost ghost added the needs-triage label Feb 20, 2021
@andrewleader
Copy link
Contributor

Hey @BenJKuhn, gentle reminder to triage this bug 😊

@BenJKuhn BenJKuhn assigned BenJKuhn and j0shuams and unassigned BenJKuhn Mar 11, 2021
@BenJKuhn BenJKuhn added area-Infrastructure Build, test, source layout, package construction (TODO: move to Deployment, DeveloperTools) servicing-consider and removed needs-triage labels Mar 11, 2021
@andrewleader andrewleader changed the title [Preview 4] FileOpenPicker PickMultipleFilesAsync Break in WinUI3 Desktop FileOpenPicker PickMultipleFilesAsync Break in WinUI3 Desktop Apr 19, 2021
@AmSmart
Copy link

AmSmart commented May 12, 2021

I get a similar error with FolderPicker's PickSingleFolderAsync.

Any workarounds for now?

@andrewleader
Copy link
Contributor

Hi @AmSmart, for PickSingleFolderAsync, are you using IInitializeWithWindow? In desktop apps, you need to use IInitializeWithWindow to associate your HWND with the API before calling PickSingleFolderAsync, see this example: #466 (comment)

@AmSmart
Copy link

AmSmart commented May 12, 2021

Yeah, I used the IInitializeWithWindow interface. The issue was that I didn't specify a file type filter. Looking through the docs, I discovered that not specifying it generates an exception. It's all resolved now. Thanks for the swift response!

@freistli
Copy link

I got the same issue on PickMultipleFilesAsync, which crashes WinUI/Reunion WPF desktop app. But PickSingleFolderAsync works well. Do we have workaround or fix now? Thanks in advance.

@Aloento
Copy link

Aloento commented Jun 4, 2021

FileSavePicker also crashed even use InitializeWithWindow

@andrewleader
Copy link
Contributor

PickMultipleFilesAsync is unfortunately not supported right now. You can instead use the Win32 API GetOpenFileName, we're working on posting a workaround sample for that.

@Aloento make sure when you're calling this.As<IWindowNative>(), the this object is a Window object. If you're still seeing problems, you can open a new issue, and please provide a full example of the code you're calling, what specifically is failing, etc. Thanks!

@Aloento
Copy link

Aloento commented Jun 5, 2021

PickMultipleFilesAsync is unfortunately not supported right now. You can instead use the Win32 API GetOpenFileName, we're working on posting a workaround sample for that.

@Aloento make sure when you're calling this.As<IWindowNative>(), the this object is a Window object. If you're still seeing problems, you can open a new issue, and please provide a full example of the code you're calling, what specifically is failing, etc. Thanks!

#909

@freistli
Copy link

freistli commented Jun 5, 2021

I'd like to share the workaround of using Interop GetOpenFileName API call.

By researching several links and verifying some experiments:

https://docs.microsoft.com/en-us/windows/win32/dlgbox/open-and-save-as-dialog-boxes
https://stackoverflow.com/questions/9088227/using-getopenfilename-instead-of-openfiledialog
https://social.msdn.microsoft.com/forums/vstudio/en-US/2f4dd95e-5c7b-4f48-adfc-44956b350f38/getopenfilename-for-multiple-files

I can workaround this issue as below:

Notes: This works in Project Reunion 0.8 Preview. If you are using WinUI3 Preview or Project Reunion 0.5, may hit this bug:

microsoft/microsoft-ui-xaml#4952

And need to upgrade the project to 0.8 by going through:
https://docs.microsoft.com/en-us/windows/apps/project-reunion/update-existing-projects-to-the-latest-release

The helper class is as attached:
Libwrap.txt

The calling sample code snippet:
`
string[] files = LibWrap.ShowOpenFileDialog("Select Files","c:\users\freistli\documents", "All files\0 .\0", true, true);

        if (files != null)
        {
            FPS.Text = "";
            foreach (var file in files)
            {
                Debug.WriteLine("Selected file with full path: {0}", file);
                FPS.Text += file + "\r\n";
            }
        }

`

Hope this helps.

@tom-huntington
Copy link

Just confirming this is not an issue on cppwinrt after

picker.as<IInitializeWithWindow>()->Initialize(hwnd);

@manodasanW
Copy link
Member

The wrong thread exception in the repro app looks to be fixed with the CsWinRT update in .NET SDK 5.0.302. Specifically, the CsWinRT fix for calling non agile objects (microsoft/CsWinRT#844) resolves it.

@andrewleader
Copy link
Contributor

andrewleader commented Aug 18, 2021

Awesome @manodasanW, so can you confirm that PickMultipleFilesAsync is now functional for C# apps if you use .NET SDK 5.0.302 and the IInitializeWithWindow? If so, we can close this thread!

@abhisavadiya
Copy link

@castorix Getting error.

Screenshot 2023-10-30 145930

@castorix
Copy link

@castorix Getting error.

Screenshot 2023-10-30 145930

It is another error that some people met from Google
Did you build as Unpackaged ?
Do you have windows10.0.19041.0 SDK installed ?

@abhisavadiya
Copy link

@castorix No, I am trying with windows 11

@castorix
Copy link

@castorix No, I am trying with windows 11

Maybe try from a new WinUI 3 blank project, then set it Unpackaged, then add code by copy/paste...

@abhisavadiya
Copy link

@castorix Can we select multiple folders and multiple files at the same time?

@castorix
Copy link

@castorix Can we select multiple folders and multiple files at the same time?

Yes, with the custom Button added in the Dialog Box (that I named "Return selected items") :

IFileDialogTest

@abhisavadiya
Copy link

abhisavadiya commented Oct 31, 2023

@castorix Can we remot this button from picker?

image

want to remove open option from file picker

@castorix
Copy link

It can be hidden (test in OnFolderChange with Marshal.GetIUnknownForObject(pfd); + IUnknown_GetWindow + ShowWindow), but there is a space and it's not easy to move the custom Button to the location of the OK/Open Button :

image

@abhisavadiya
Copy link

abhisavadiya commented Oct 31, 2023

@castorix Can we change the position to return the selected item button?

OnFolderChange where should I call this function?
Can you please send the whole function code snippet?

@castorix
Copy link

castorix commented Oct 31, 2023

I copied-pasted CFileDialog.cs with quick changes to hide Open button and resize the custom button, to be improved : https://pastebin.com/a2Ntn335

IFileDialogTest_Resize

@abhisavadiya
Copy link

Working but it's giving expectation after select first time,

image

@abhisavadiya
Copy link

image

@castorix
Copy link

Yes, I made a last change that I did not test...
For quick fix (but not great because the button text is hardcoded atm) :
Remove static at
static ObservableCollection
Uncomment/Comment at :
IntPtr hWndButton = FindWindowEx(m_hWndDialog, IntPtr.Zero, null, " Return selected items ");
//IntPtr hWndButton = FindWindowEx(m_hWndDialog, IntPtr.Zero, null, m_Buttons[0].Label);

@abhisavadiya
Copy link

abhisavadiya commented Oct 31, 2023

It's perfectly working, now. Can we change the select button position?

image

@castorix
Copy link

Is it the custom button that you renamed ?
If yes, change the text " Return selected items " by your button text ("Select" or other) (in WindowSubClass)
or FindWindowEx won't find it to change its position with SetWindowPos

@abhisavadiya
Copy link

Like that,

image

@castorix
Copy link

castorix commented Oct 31, 2023

Yes, if the text is exactly "Select" (without spaces)
And for a cleaner code, a test should be added to check if hWndButton != IntPtr.Zero

@abhisavadiya
Copy link

Did it still not change select folder location,

image

image

@castorix
Copy link

castorix commented Oct 31, 2023

You have set 0, 0 for location in SetWindowPos, instead of
pt.x + (rcOpen.right - rcOpen.left) + 12, pt.y
And is hWndButton filled ? (by setting a BP on the test)

@abhisavadiya
Copy link

abhisavadiya commented Oct 31, 2023

Still not change position of that select button,

image

Can you share your code snippet if it's working at your side ?

@castorix
Copy link

In the main code :
cfd.AddPushButton(ID_PUSHBUTTON, "Select");

The class :
https://pastebin.com/a2Ntn335

Result :

image

@abhisavadiya
Copy link

@castorix All going perfectly but the files/folder picker is open in full screen. Can we change the size?

@castorix
Copy link

castorix commented Nov 2, 2023

@castorix All going perfectly but the files/folder picker is open in full screen. Can we change the size?

On my OS, Windows 10 22H2, it saves the position/dimensions and it is opened at the latest ones.
For example, if I double-click on caption to set it Fullscreen, it will be re-opened Fullscreen next time; if I set it at 50, 50 with 100*100, it will be re-opened exactly at same location/size next time, and so on...

@albus25
Copy link

albus25 commented Nov 20, 2023

@castorix I am using the Multiple Files and Directories picker, but when I click on the "Select" button, it does not return anything nor dialog close. But when I click the "Cancel" button, it closes the window. I copied your code to another custom page (HomePage.xaml and HomePage.xaml.cs), not in MainWindow, has it caused an issue?

image

When I debugged the code, I found that the selected line in the below screenshot returned nothing when I clicked on the "Select" button, but If I clicked on the "Cancel" button it did return an "E_CANCELLED" output.

image

@castorix
Copy link

Are you sure it is the same code ? (I don't see the test on bOpen for example)
I get S_OK as result when I click on Select button (Unpackaged, Windows 10 22H2)) :

image

@albus25
Copy link

albus25 commented Nov 20, 2023

@castorix Yes, it is the same code, as I don't need the bOpen, so I removed that variable.

@castorix
Copy link

Does the code go in WM_APP_FILEDIALOG where I fill the file names and return S_OK ? :

image

@albus25
Copy link

albus25 commented Nov 21, 2023

@castorix No, it does not go.

@castorix
Copy link

Is m_hWndOwner correct at :
(the window handle passed as 1st parameter of ShowDialog)

        public void OnButtonClicked([In][MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl)
        {
            IntPtr pClassPtr = Marshal.GetIUnknownForObject(this);
            SendMessage(parentCFD.m_hWndOwner, WM_APP_FILEDIALOG, (IntPtr)dwIDCtl, (IntPtr)pClassPtr);
            return;
        }

@abhisavadiya
Copy link

Hello @castorix  Brother, We have been getting unknown expectations for 7-10 days. I can't share the whole project with you due to the large dependency on a backend server and complexity. So, can we connect on a remote session for 15 min ( Link )? It will save a lot time of and it will be very helpful to us. I hope you can understand our situation. Thanks a lot in advance. 

error_1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Infrastructure Build, test, source layout, package construction (TODO: move to Deployment, DeveloperTools)
Projects
None yet
Development

No branches or pull requests