From 0968554be06cd4998b74b849d8bdea8e46a334c0 Mon Sep 17 00:00:00 2001 From: Symbai <14368203+Symbai@users.noreply.github.com> Date: Sat, 9 Jan 2021 02:34:00 +0100 Subject: [PATCH 1/2] Add folder dialog --- .../Microsoft/Win32/OpenFolderDialog.cs | 645 ++++++++++++++++++ .../PresentationFramework.csproj | 1 + .../ref/PresentationFramework.cs | 19 + 3 files changed, 665 insertions(+) create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs new file mode 100644 index 00000000000..7a3c0176f17 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs @@ -0,0 +1,645 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// +// Description: +// OpenFolderDialog is a sealed class derived from CommonDialog that +// implements Folder Open dialog-specific functions. +// + + +namespace PresentationFramework.Microsoft.Win32 +{ + using System; + using System.Runtime.InteropServices; + using System.Windows.Interop; + using System.Windows; + using System.IO; + using System.Linq; + using System.Runtime.CompilerServices; + + public sealed class OpenFolderDialog + { + + //--------------------------------------------------- + // + // Public methods + // + //--------------------------------------------------- + #region Public methods + public Nullable ShowDialog() => ShowDialog(null); + + public Nullable ShowDialog(Window window) + { + INativeFileOpenDialog openDialogCoClass = new INativeFileOpenDialog(); + try + { + ApplyNativeSettings(openDialogCoClass); + window ??= Helpers.GetDefaultOwnerWindow(); + int hresult = openDialogCoClass.Show(GetHandleFromWindow(window)); + if (ErrorHelper.Matches(hresult, Win32ErrorCode.ERROR_CANCELLED)) + return false; + + openDialogCoClass.GetResults(out IShellItemArray resultsArray); + resultsArray.GetCount(out uint count); + if (count <= 0) return true; + + resultsArray.GetItemAt(0, out IShellItem shellItem); + shellItem.GetDisplayName(NativeMethods.SIGDN.DESKTOPABSOLUTEPARSING, out string file); + FileName = file; + + FileNames = new string[count]; + for (uint i = 0; i < count; i++) + { + resultsArray.GetItemAt(i, out shellItem); + shellItem.GetDisplayName(NativeMethods.SIGDN.DESKTOPABSOLUTEPARSING, out file); + FileNames[i] = file; + } + return true; + } + finally + { + Marshal.ReleaseComObject(openDialogCoClass); + } + } + #endregion + + //--------------------------------------------------- + // + // Public Properties + // + //--------------------------------------------------- + #region Public Properties + /// + /// Gets or sets the dialog title. + /// + public string Title { get; set; } + + /// + /// Gets the selected file name. + /// + public string FileName { get; private set; } + + /// + /// Gets a collection of the selected file names. + /// + public string[] FileNames { get; private set; } + + /// + /// Gets or sets a value that determines whether the user can select more than one file. + /// + public bool Multiselect { get; set; } + + /// + /// Gets or sets a value that determines whether the file must exist beforehand. + /// + public bool EnsureFileExists { get; set; } + + /// + /// Gets or sets a value that specifies whether the returned file must be in an existing folder. + /// + public bool EnsurePathExists { get; set; } + + /// + /// Gets or sets a value that determines whether to validate file names. + /// + public bool EnsureValidNames { get; set; } + + /// + /// Gets or sets a value that determines whether read-only items are returned. + /// Default value is true (allow read-only files). + /// + public bool EnsureReadOnly { get; set; } = true; + + /// + /// Gets or sets a value that determines the restore directory. + /// + public bool RestoreDirectory { get; set; } + + /// + /// Gets or sets a value that controls whether to show or hide the list of pinned places that the user can choose. + /// Default value is true. + /// + public bool ShowPlacesList { get; set; } = true; + + /// + /// Gets or sets a value that controls whether to show or hide the list of places where the user has recently opened or saved items. + /// Default value is true. + /// + public bool AddToMruList { get; set; } = true; + + /// + /// Gets or sets a value that controls whether to show hidden items. + /// + public bool ShowHiddenItems { get; set; } + + /// + /// Gets or sets a value that controls whether shortcuts should be treated as their target items, allowing an application to open a .lnk file. + /// Default value is true. + /// + public bool NavigateToShortcut { get; set; } = true; + + /// + /// Gets or sets a value that determines whether the user can select non-filesystem items, + /// such as Library, Search Connectors, or Known Folders. + /// + public bool AllowNonFileSystem { get; set; } + + /// + /// Gets or sets the initial directory displayed when the dialog is shown. A null or empty string indicates that the dialog is using the default directory. + /// + public string InitialDirectory { get; set; } + #endregion + + //--------------------------------------------------- + // + // Private Methods + // + //--------------------------------------------------- + #region Private Methods + private void ApplyNativeSettings(IFileDialog dialog) + { + dialog.SetTitle(Title); + NativeMethods.FOS flags = ApplyNativeDialogFlags(); + dialog.SetOptions(flags); + + string directory = string.IsNullOrEmpty(InitialDirectory) ? null : Path.GetDirectoryName(InitialDirectory); + if (directory == null) return; + try + { + NativeMethods.SHCreateItemFromParsingName(InitialDirectory, IntPtr.Zero, new Guid(IIDGuid.IShellItem), out IShellItem folder); + if (folder != null) + dialog.SetFolder(folder); + } + catch + { } + } + + private NativeMethods.FOS ApplyNativeDialogFlags() + { + NativeMethods.FOS flags = NativeMethods.FOS.NOTESTFILECREATE | NativeMethods.FOS.PICKFOLDERS; + + flags |= AllowNonFileSystem ? NativeMethods.FOS.ALLNONSTORAGEITEMS : NativeMethods.FOS.FORCEFILESYSTEM; + + if (Multiselect) + { + flags |= NativeMethods.FOS.ALLOWMULTISELECT; + } + if (EnsureFileExists) + { + flags |= NativeMethods.FOS.FILEMUSTEXIST; + } + if (EnsurePathExists) + { + flags |= NativeMethods.FOS.PATHMUSTEXIST; + } + if (!EnsureValidNames) + { + flags |= NativeMethods.FOS.NOVALIDATE; + } + if (!EnsureReadOnly) + { + flags |= NativeMethods.FOS.NOREADONLYRETURN; + } + if (RestoreDirectory) + { + flags |= NativeMethods.FOS.NOCHANGEDIR; + } + if (!ShowPlacesList) + { + flags |= NativeMethods.FOS.HIDEPINNEDPLACES; + } + if (!AddToMruList) + { + flags |= NativeMethods.FOS.DONTADDTORECENT; + } + if (ShowHiddenItems) + { + flags |= NativeMethods.FOS.FORCESHOWHIDDEN; + } + if (!NavigateToShortcut) + { + flags |= NativeMethods.FOS.NODEREFERENCELINKS; + } + return flags; + } + + private static IntPtr GetHandleFromWindow(Window window) => + window == null ? NativeMethods.NO_PARENT : new WindowInteropHelper(window).Handle; + #endregion + } + static class IIDGuid + { + internal const string IModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; + internal const string IFileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; + internal const string IFileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960"; + internal const string IFileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; + internal const string IShellItem = "43826D1E-E718-42EE-BC55-A1E261C37BFE"; + internal const string IShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; + } + + static class CLSIDGuid + { + internal const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7"; + } + + static class ErrorHelper + { + private const int FACILITY_WIN32 = 7; + + internal static int HResultFromWin32(int win32ErrorCode) + { + if (win32ErrorCode > 0) + { + win32ErrorCode = (int)((win32ErrorCode & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000); + } + return win32ErrorCode; + } + + internal static int HResultFromWin32(Win32ErrorCode error) => HResultFromWin32((int)error); + + internal static bool Matches(int hresult, Win32ErrorCode win32ErrorCode) => hresult == HResultFromWin32(win32ErrorCode); + } + + internal enum Win32ErrorCode + { + ERROR_CANCELLED = 1223 + } + + internal static class Helpers + { + [DllImport("user32.dll")] + static extern IntPtr GetActiveWindow(); + internal static Window GetDefaultOwnerWindow() + { + Window defaultWindow = null; + + IntPtr active = GetActiveWindow(); + if (active != IntPtr.Zero && Application.Current != null) + { + defaultWindow = Application.Current.Windows.OfType() + .SingleOrDefault(window => new WindowInteropHelper(window).Handle == active); + } + return defaultWindow; + } + + } + internal static class NativeMethods + { + + internal static IntPtr NO_PARENT = IntPtr.Zero; + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] + internal struct COMDLG_FILTERSPEC + { + [MarshalAs(UnmanagedType.LPWStr)] + internal string pszName; + [MarshalAs(UnmanagedType.LPWStr)] + internal string pszSpec; + } + + internal enum FDAP + { + BOTTOM = 0x00000000, + TOP = 0x00000001, + } + + internal enum FDE_SHAREVIOLATION_RESPONSE + { + FDESVR_DEFAULT = 0x00000000, + FDESVR_ACCEPT = 0x00000001, + FDESVR_REFUSE = 0x00000002 + } + + internal enum FDE_OVERWRITE_RESPONSE + { + FDEOR_DEFAULT = 0x00000000, + FDEOR_ACCEPT = 0x00000001, + FDEOR_REFUSE = 0x00000002 + } + + internal enum SIATTRIBFLAGS + { + AND = 0x00000001, + OR = 0x00000002, + APPCOMPAT = 0x00000003, + } + + internal enum SIGDN : uint + { + NORMALDISPLAY = 0x00000000, + PARENTRELATIVEPARSING = 0x80018001, + DESKTOPABSOLUTEPARSING = 0x80028000, + PARENTRELATIVEEDITING = 0x80031001, + DESKTOPABSOLUTEEDITING = 0x8004c000, + FILESYSPATH = 0x80058000, + URL = 0x80068000, + PARENTRELATIVEFORADDRESSBAR = 0x8007c001, + PARENTRELATIVE = 0x80080001 + } + + [Flags] + internal enum FOS : uint + { + OVERWRITEPROMPT = 0x00000002, + STRICTFILETYPES = 0x00000004, + NOCHANGEDIR = 0x00000008, + PICKFOLDERS = 0x00000020, + FORCEFILESYSTEM = 0x00000040, + ALLNONSTORAGEITEMS = 0x00000080, + NOVALIDATE = 0x00000100, + ALLOWMULTISELECT = 0x00000200, + PATHMUSTEXIST = 0x00000800, + FILEMUSTEXIST = 0x00001000, + CREATEPROMPT = 0x00002000, + SHAREAWARE = 0x00004000, + NOREADONLYRETURN = 0x00008000, + NOTESTFILECREATE = 0x00010000, + HIDEMRUPLACES = 0x00020000, + HIDEPINNEDPLACES = 0x00040000, + NODEREFERENCELINKS = 0x00100000, + DONTADDTORECENT = 0x02000000, + FORCESHOWHIDDEN = 0x10000000, + DEFAULTNOMINIMODE = 0x20000000 + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct PROPERTYKEY + { + internal Guid fmtid; + internal uint pid; + } + + [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + internal static extern void SHCreateItemFromParsingName([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath, [In] IntPtr pbc, [In, MarshalAs(UnmanagedType.LPStruct)] Guid iIdIShellItem, [Out, MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellItem iShellItem); + } + + [ComImport, + Guid(IIDGuid.IModalWindow), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IModalWindow + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig] + int Show([In] IntPtr parent); + } + + [ComImport, + Guid(IIDGuid.IFileDialog), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IFileDialog : IModalWindow + { + // -------------------------------------------------------------------------------- + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig] + new int Show([In] IntPtr parent); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileTypes([In] uint cFileTypes, [In] ref NativeMethods.COMDLG_FILTERSPEC rgFilterSpec); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileTypeIndex([In] uint iFileType); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFileTypeIndex(out uint piFileType); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Unadvise([In] uint dwCookie); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetOptions([In] NativeMethods.FOS fos); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetOptions(out NativeMethods.FOS pfos); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, NativeMethods.FDAP fdap); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Close([MarshalAs(UnmanagedType.Error)] int hr); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetClientGuid([In] ref Guid guid); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ClearClientData(); + + // Not supported: IShellItemFilter is not defined, converting to IntPtr + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); + } + + [ComImport(), + Guid(IIDGuid.IFileOpenDialog), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IFileOpenDialog : IFileDialog + { + // Defined on IModalWindow - repeated here due to requirements of COM interop layer + // -------------------------------------------------------------------------------- + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), + PreserveSig] + new int Show([In] IntPtr parent); + + // Defined on IFileDialog - repeated here due to requirements of COM interop layer + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetFileTypes([In] uint cFileTypes, [In] ref NativeMethods.COMDLG_FILTERSPEC rgFilterSpec); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetFileTypeIndex([In] uint iFileType); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void GetFileTypeIndex(out uint piFileType); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void Unadvise([In] uint dwCookie); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetOptions([In] NativeMethods.FOS fos); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void GetOptions(out NativeMethods.FOS pfos); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, NativeMethods.FDAP fdap); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void Close([MarshalAs(UnmanagedType.Error)] int hr); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetClientGuid([In] ref Guid guid); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void ClearClientData(); + + // Not supported: IShellItemFilter is not defined, converting to IntPtr + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + new void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); + + // Defined by IFileOpenDialog + // --------------------------------------------------------------------------------- + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai); + } + + [ComImport, + Guid(IIDGuid.IFileDialogEvents), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IFileDialogEvents + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig] + long OnFileOk([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig] + long OnFolderChanging([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psiFolder); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnFolderChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnSelectionChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnShareViolation([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out NativeMethods.FDE_SHAREVIOLATION_RESPONSE pResponse); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnTypeChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void OnOverwrite([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out NativeMethods.FDE_OVERWRITE_RESPONSE pResponse); + } + + [ComImport, + Guid(IIDGuid.IShellItem), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IShellItem + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetDisplayName([In] NativeMethods.SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); + } + + [ComImport, + Guid(IIDGuid.IShellItemArray), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IShellItemArray + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, out IntPtr ppvOut); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetPropertyStore([In] int Flags, [In] ref Guid riid, out IntPtr ppv); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetPropertyDescriptionList([In] ref NativeMethods.PROPERTYKEY keyType, [In] ref Guid riid, out IntPtr ppv); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetAttributes([In] NativeMethods.SIATTRIBFLAGS dwAttribFlags, [In] uint sfgaoMask, out uint psfgaoAttribs); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCount(out uint pdwNumItems); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + // Not supported: IEnumShellItems (will use GetCount and GetItemAt instead) + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems); + } + + [ComImport, + Guid(IIDGuid.IFileOpenDialog), + CoClass(typeof(FileOpenDialogRCW))] + internal interface INativeFileOpenDialog : IFileOpenDialog { } + + [ComImport, + ClassInterface(ClassInterfaceType.None), + TypeLibType(TypeLibTypeFlags.FCanCreate), + Guid(CLSIDGuid.FileOpenDialog)] + internal class FileOpenDialogRCW { } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj index 23560c1efcf..28032a4c559 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj @@ -44,6 +44,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs index 534e2813c0d..645294edcc9 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs @@ -76,6 +76,25 @@ protected override void CheckPermissionsToShowDialog() { } public System.IO.Stream[] OpenFiles() { throw null; } public override void Reset() { } } + public sealed partial class OpenFolderDialog + { + public OpenFolderDialog() { } + public string Title { get { throw null; } set { } } + public string FileName { get { throw null; } private set { } } + public string[] FileNames { get { throw null; } private set { } } + public bool Multiselect { get { throw null; } set { } } + public bool EnsureFileExists { get { throw null; } set { } } + public bool EnsurePathExists { get { throw null; } set { } } + public bool EnsureValidNames { get { throw null; } set { } } + public bool EnsureReadOnly { get { throw null; } set { } } + public bool RestoreDirectory { get { throw null; } set { } } + public bool ShowPlacesList { get { throw null; } set { } } + public bool AddToMruList { get { throw null; } set { } } + public bool ShowHiddenItems { get { throw null; } set { } } + public bool NavigateToShortcut { get { throw null; } set { } } + public bool AllowNonFileSystem { get { throw null; } set { } } + public string InitialDirectory { get { throw null; } set { } } + } public sealed partial class SaveFileDialog : Microsoft.Win32.FileDialog { public SaveFileDialog() { } From b11f85b809b8d0d69f7c35d43f82bcf7b79b3de7 Mon Sep 17 00:00:00 2001 From: Symbai <14368203+Symbai@users.noreply.github.com> Date: Sat, 9 Jan 2021 02:40:12 +0100 Subject: [PATCH 2/2] Fix comment --- .../PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs index 7a3c0176f17..ed31eb044ac 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFolderDialog.cs @@ -5,7 +5,7 @@ // // // Description: -// OpenFolderDialog is a sealed class derived from CommonDialog that +// OpenFolderDialog is a sealed class that // implements Folder Open dialog-specific functions. //