using Microsoft.Win32; using System; using System.Runtime.InteropServices; namespace WPFluent.Controls { public sealed class VistaFolderBrowserDialog { private IFileOpenDialog CreateNativeDialog() { return (IFileOpenDialog)new FileOpenDialog(); } private Fos GetDialogOptions() { Fos options = Fos.Pickfolders; if(Multiselect) { options |= Fos.Allowmultiselect; } if(!AllowNonStoragePlaces) { options |= Fos.Forcefilesystem; } return options; } private void GetPathAndElementName(IShellItem item, out string path, out string elementName) { item.GetDisplayName(Sigdn.Parentrelativeforaddressbar, out elementName); try { item.GetDisplayName(Sigdn.Filesyspath, out path); } catch(ArgumentException ex) when (ex.HResult == -2147024809) { path = null; } } private void SetDialogResults(IFileOpenDialog dialog) { IShellItem item; if(!Multiselect) { dialog.GetResult(out item); string path, value; GetPathAndElementName(item, out path, out value); SelectedPath = path; SelectedPaths = new[] { path }; SelectedElementName = value; SelectedElementNames = new[] { value }; } else { IShellItemArray items; dialog.GetResults(out items); uint count; items.GetCount(out count); SelectedPaths = new string[count]; SelectedElementNames = new string[count]; for(uint i = 0; i < count; ++i) { items.GetItemAt(i, out item); string path, value; GetPathAndElementName(item, out path, out value); SelectedPaths[i] = path; SelectedElementNames[i] = value; } SelectedPath = null; SelectedElementName = null; } } private void SetInitialFolder(IFileOpenDialog dialog) { IShellItem item; if(!string.IsNullOrEmpty(SelectedPath)) { IntPtr idl; uint atts = 0; if(NativeMethods.SHILCreateFromPath(SelectedPath, out idl, ref atts) == 0 && NativeMethods.SHCreateShellItem(IntPtr.Zero, IntPtr.Zero, idl, out item) == 0) { dialog.SetFolder(item); } } } private void SetOptions(IFileOpenDialog dialog) { dialog.SetOptions(GetDialogOptions()); } public bool ShowDialog() { return ShowDialog(IntPtr.Zero); } public bool ShowDialog(Window owner) { return ShowDialog(owner == null ? IntPtr.Zero : new WindowInteropHelper(owner).Handle); } public bool ShowDialog(IWin32Window owner) { return ShowDialog(owner == null ? IntPtr.Zero : owner.Handle); } public bool ShowDialog(IntPtr owner) { if(Environment.OSVersion.Version.Major < 6) { throw new InvalidOperationException("对话框需要至少在Visia系统以上才能使用"); } IFileOpenDialog dialog = CreateNativeDialog(); try { SetInitialFolder(dialog); SetOptions(dialog); if(dialog.Show(owner) != 0) { return false; } SetDialogResults(dialog); return true; } finally { Marshal.ReleaseComObject(dialog); } } public bool AllowNonStoragePlaces { get; set; } public bool Multiselect { get; set; } public string SelectedElementName { get; private set; } public string[] SelectedElementNames { get; private set; } public string SelectedPath { get; set; } public string[] SelectedPaths { get; private set; } [ComImport] [Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")] private class FileOpenDialog { } private class NativeMethods { [DllImport("user32.dll")] public static extern IntPtr GetActiveWindow(); [DllImport("shell32.dll")] public static extern int SHCreateShellItem( IntPtr pidlParent, IntPtr psfParent, IntPtr pidl, out IShellItem ppsi); [DllImport("shell32.dll")] public static extern int SHILCreateFromPath( [MarshalAs(UnmanagedType.LPWStr)] string pszPath, out IntPtr ppIdl, ref uint rgflnOut); } [Flags] private enum Fos { Allnonstorageitems = 0x80, Allowmultiselect = 0x200, Createprompt = 0x2000, Defaultnominimode = 0x20000000, Dontaddtorecent = 0x2000000, Filemustexist = 0x1000, Forcefilesystem = 0x40, Forceshowhidden = 0x10000000, Hidemruplaces = 0x20000, Hidepinnedplaces = 0x40000, Nochangedir = 8, Nodereferencelinks = 0x100000, Noreadonlyreturn = 0x8000, Notestfilecreate = 0x10000, Novalidate = 0x100, Overwriteprompt = 2, Pathmustexist = 0x800, Pickfolders = 0x20, Shareaware = 0x4000, Strictfiletypes = 4 } [ComImport] [Guid("d57c7288-d4ad-4768-be02-9d969532d960")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [CoClass(typeof(FileOpenDialog))] private interface IFileOpenDialog { [PreserveSig] int Show([In] IntPtr parent); void SetFileTypes([In] uint cFileTypes, [In][MarshalAs(UnmanagedType.Struct)] ref IntPtr rgFilterSpec); void SetFileTypeIndex([In] uint iFileType); void GetFileTypeIndex(out uint piFileType); void Advise([In][MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie); void Unadvise([In] uint dwCookie); void SetOptions([In] Fos fos); void GetOptions(out Fos pfos); void SetDefaultFolder([In][MarshalAs(UnmanagedType.Interface)] IShellItem psi); void SetFolder([In][MarshalAs(UnmanagedType.Interface)] IShellItem psi); void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); void SetFileName([In][MarshalAs(UnmanagedType.LPWStr)] string pszName); void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); void SetTitle([In][MarshalAs(UnmanagedType.LPWStr)] string pszTitle); void SetOkButtonLabel([In][MarshalAs(UnmanagedType.LPWStr)] string pszText); void SetFileNameLabel([In][MarshalAs(UnmanagedType.LPWStr)] string pszLabel); void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); void AddPlace([In][MarshalAs(UnmanagedType.Interface)] IShellItem psi, FileDialogCustomPlace fdcp); void SetDefaultExtension([In][MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); void Close([MarshalAs(UnmanagedType.Error)] int hr); void SetClientGuid([In] ref Guid guid); void ClearClientData(); void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); void GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum); void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai); } [ComImport] [Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IShellItem { void BindToHandler( [In][MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv); void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); void GetDisplayName([In] Sigdn sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); void Compare([In][MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); } [ComImport] [Guid("B63EA76D-1F85-456F-A19C-48159EFA858B")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IShellItemArray { void BindToHandler( [In][MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, out IntPtr ppvOut); void GetPropertyStore([In] int flags, [In] ref Guid riid, out IntPtr ppv); void GetPropertyDescriptionList( [In][MarshalAs(UnmanagedType.Struct)] ref IntPtr keyType, [In] ref Guid riid, out IntPtr ppv); void GetAttributes( [In][MarshalAs(UnmanagedType.I4)] IntPtr dwAttribFlags, [In] uint sfgaoMask, out uint psfgaoAttribs); void GetCount(out uint pdwNumItems); void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems); } private enum Sigdn : uint { Desktopabsoluteediting = 0x8004c000, Desktopabsoluteparsing = 0x80028000, Filesyspath = 0x80058000, Normaldisplay = 0, Parentrelative = 0x80080001, Parentrelativeediting = 0x80031001, Parentrelativeforaddressbar = 0x8007c001, Parentrelativeparsing = 0x80018001, Url = 0x80068000 } } }