我想添加多选到这个自定义文件对话框。我添加了“FOS_ALLOWMULTISELECT”,我可以选择多个文件夹。但是当我想以同样的方式获取文件夹名称时,当Multiselect=false时,shellItemArray将为null,而不是System._ComObject。我不知道该怎么做,是有人能帮我我会很感激的。
需求:
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
要使用代码,请添加:
using (OpenFolderDialog dialog = new OpenFolderDialog())
{
dialog.Multiselect = true;
if (dialog.ShowDialog(this) == DialogResult.OK)
{
}
}
验证码:
internal class OpenFolderDialog : IDisposable
{
/// <summary>
/// Gets/sets folder in which dialog will be open.
/// </summary>
public string InitialFolder { get; set; }
/// <summary>
/// Gets/sets directory in which dialog will be open if there is no recent directory available.
/// </summary>
public string DefaultFolder { get; set; }
/// <summary>
/// Gets selected folder.
/// </summary>
public string Folder { get; private set; }
public bool Multiselect { get; set; }
public string Title { get; set; }
public string OkButtonLabel { get; set; }
public string FileNameLabel { get; set; }
internal DialogResult ShowDialog(IWin32Window owner)
{
if (Environment.OSVersion.Version.Major >= 6)
{
return ShowVistaDialog(owner);
}
else
{
return ShowLegacyDialog(owner);
}
}
private DialogResult ShowVistaDialog(IWin32Window owner)
{
var frm = (NativeMethods.IFileDialog)(new NativeMethods.FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
if (Multiselect)
{
options |= NativeMethods.FOS_ALLOWMULTISELECT;
}
frm.SetOptions(options);
if (Title != null)
{
frm.SetTitle(Title);
}
if (OkButtonLabel != null)
{
frm.SetOkButtonLabel(OkButtonLabel);
}
if (FileNameLabel != null)
{
frm.SetFileName(FileNameLabel);
}
if (!string.IsNullOrEmpty(InitialFolder))
{
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.InitialFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK)
{
frm.SetFolder(directoryShellItem);
}
}
if (!string.IsNullOrEmpty(DefaultFolder))
{
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.DefaultFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK)
{
frm.SetDefaultFolder(directoryShellItem);
}
}
if (frm.Show(owner.Handle) == NativeMethods.S_OK)
{
if (!Multiselect)
{
NativeMethods.IShellItem shellItem;
if (frm.GetResult(out shellItem) == NativeMethods.S_OK)
{
IntPtr pszString;
if (shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH, out pszString) == NativeMethods.S_OK)
{
if (pszString != IntPtr.Zero)
{
try
{
this.Folder = Marshal.PtrToStringAuto(pszString);
return DialogResult.OK;
}
finally
{
Marshal.FreeCoTaskMem(pszString);
}
}
}
}
}
else
{
NativeMethods.IShellItemArray shellItemArray;
if (frm.GetResults(out shellItemArray) == NativeMethods.S_OK)
{
uint items;
if (shellItemArray.GetCount(out items) == NativeMethods.S_OK)
{
}
}
}
}
return DialogResult.Cancel;
}
private DialogResult ShowLegacyDialog(IWin32Window owner)
{
using (var frm = new SaveFileDialog())
{
frm.CheckFileExists = false;
frm.CheckPathExists = true;
frm.CreatePrompt = false;
frm.Filter = "|" + Guid.Empty.ToString();
frm.FileName = "any";
if (this.InitialFolder != null) { frm.InitialDirectory = this.InitialFolder; }
frm.OverwritePrompt = false;
frm.Title = "Select Folder";
frm.ValidateNames = false;
if (frm.ShowDialog(owner) == DialogResult.OK)
{
this.Folder = Path.GetDirectoryName(frm.FileName);
return DialogResult.OK;
}
else
{
return DialogResult.Cancel;
}
}
}
public void Dispose() { } //just to have possibility of Using statement.
}
internal static class NativeMethods
{
#region Constants
public const uint FOS_OVERWRITEPROMPT = 0x00000002;
public const uint FOS_STRICTFILETYPES = 0x00000004;
public const uint FOS_NOCHANGEDIR = 0x00000008;
public const uint FOS_PICKFOLDERS = 0x00000020;
public const uint FOS_FORCEFILESYSTEM = 0x00000040;
public const uint FOS_ALLNONSTORAGEITEMS = 0x00000080;
public const uint FOS_NOVALIDATE = 0x00000100;
public const uint FOS_ALLOWMULTISELECT = 0x00000200;
public const uint FOS_PATHMUSTEXIST = 0x00000800;
public const uint FOS_FILEMUSTEXIST = 0x00001000;
public const uint FOS_CREATEPROMPT = 0x00002000;
public const uint FOS_SHAREAWARE = 0x00004000;
public const uint FOS_NOREADONLYRETURN = 0x00008000;
public const uint FOS_NOTESTFILECREATE = 0x00010000;
public const uint FOS_HIDEMRUPLACES = 0x00020000;
public const uint FOS_HIDEPINNEDPLACES = 0x00040000;
public const uint FOS_NODEREFERENCELINKS = 0x00100000;
public const uint FOS_OKBUTTONNEEDSINTERACTION = 0x00200000;
public const uint FOS_DONTADDTORECENT = 0x02000000;
public const uint FOS_FORCESHOWHIDDEN = 0x10000000;
public const uint FOS_DEFAULTNOMINIMODE = 0x20000000;
public const uint FOS_FORCEPREVIEWPANEON = 0x40000000;
public const uint FOS_SUPPORTSTREAMABLEITEMS = unchecked(0x80000000);
public const uint S_OK = 0x0000;
public const uint SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000;
public const uint SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000;
public const uint SIGDN_FILESYSPATH = 0x80058000;
public const uint SIGDN_NORMALDISPLAY = 0;
public const uint SIGDN_PARENTRELATIVE = 0x80080001;
public const uint SIGDN_PARENTRELATIVEEDITING = 0x80031001;
public const uint SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001;
public const uint SIGDN_PARENTRELATIVEPARSING = 0x80018001;
public const uint SIGDN_URL = 0x80068000;
#endregion
#region COM
[ComImport, ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
internal class FileOpenDialogRCW { }
[ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileDialog
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig()]
uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOptions([In] uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetOptions(out uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint ClearClientData();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai);
}
[ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItem
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint BindToHandler([In] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IntPtr ppvOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
}
[ComImport, Guid("b63ea76d-1f85-456f-a19c-48159efa858b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItemArray
{
// Not supported: IBindCtx
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, out IntPtr ppvOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetPropertyStore([In] int Flags, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetPropertyDescriptionList([In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCount(out uint pdwNumItems);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint 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)]
uint EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems);
}
#endregion
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
}
1条答案
按热度按时间8oomwypt1#
更改IFileDialog的Guid编号可启用多选。感谢Simon Mourier(https://stackoverflow.com/a/66187224/8458887)的想法,通过列表到字符串。