c#如何允许选择我的电脑与文件夹浏览器对话框
本文关键字:文件夹 浏览器 对话框 电脑 我的 何允许 选择 选择我 | 更新日期: 2023-09-27 18:14:34
在我的应用程序中,我希望folderBrowserDialog允许选择My Computer
。但是,在对话框中选择My Computer
后,OK按钮被禁用。
是否有办法允许在Browse Dialog
中选择My Computer
?
我的电脑(或这台电脑在最近的Windows版本)是一个特殊的文件夹(不是文件系统文件夹),标准的FolderBrowserDialog类不支持它。
下面是一个FolderBrowser
类的替换样例,它允许用户选择任何文件夹。这是一个在Windows表单应用程序中使用它的例子:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// other special GUIDs are defined in Windows SDK's ShlGuid.h
Guid CLSID_MyComputer = new Guid("20D04FE0-3AEA-1069-A2D8-08002B30309D");
FolderBrowser dlg = new FolderBrowser();
dlg.Title = "Choose any folder you want";
// optionally uncomment the following line to start from a folder
//dlg.SelectedPath = @"c:'temp";
// optionally uncomment the following line to start from My Computer/This PC
//dlg.SelectedDesktopAbsoluteParsing = "::" + CLSID_MyComputer.ToString("B");
if (dlg.ShowDialog(null) == DialogResult.OK)
{
MessageBox.Show(dlg.SelectedDesktopAbsoluteParsing + Environment.NewLine +
dlg.SelectedNormalDisplay + Environment.NewLine +
dlg.SelectedPath + Environment.NewLine +
dlg.SelectedUrl);
if (dlg.SelectedDesktopAbsoluteParsing == "::" + CLSID_MyComputer.ToString("B").ToUpperInvariant())
{
MessageBox.Show("My Computer was selected!");
}
}
}
}
在这个答案的底部,你会发现FolderBrowser
替代类。有趣的部分是这一行:
dialog.SetOptions(FOS.FOS_PICKFOLDERS | FOS.FOS_ALLNONSTORAGEITEMS);
指示代码只选择文件夹,并允许非文件系统项。
对于普通文件夹,返回的SelectedPath
属性将包含文件夹路径。对于没有存储空间的特殊文件夹,它将为空。但是shell为我们提供了一个规范的名称,其中包含普通文件夹的文件夹路径和其他文件夹的特殊值,这些值将在SelectedDesktopAbsoluteParsing
属性中定义。在My Computer的情况下,该值将始终为" ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}
"。
这个特殊的语法在这里有一些正式的定义:指定一个命名空间扩展的位置。
public class FolderBrowser
{
public string SelectedPath { get; set; }
public string SelectedDesktopAbsoluteParsing { get; set; }
public string Title { get; set; }
public string SelectedNormalDisplay { get; private set; }
public string SelectedUrl { get; private set; }
public DialogResult ShowDialog(IWin32Window owner)
{
var dialog = (IFileOpenDialog)new FileOpenDialog();
if (!string.IsNullOrEmpty(SelectedPath))
{
SelectInitialPath(dialog, SelectedPath);
}
else if (!string.IsNullOrEmpty(SelectedDesktopAbsoluteParsing))
{
SelectInitialPath(dialog, SelectedDesktopAbsoluteParsing);
}
if (!string.IsNullOrWhiteSpace(Title))
{
dialog.SetTitle(Title);
}
dialog.SetOptions(FOS.FOS_PICKFOLDERS | FOS.FOS_ALLNONSTORAGEITEMS);
uint hr = dialog.Show(owner != null ? owner.Handle : IntPtr.Zero);
if (hr == ERROR_CANCELLED)
return DialogResult.Cancel;
if (hr != 0)
return DialogResult.Abort;
dialog.GetResult(out IShellItem result);
SelectedPath = GetDisplayName(result, SIGDN.SIGDN_FILESYSPATH);
SelectedNormalDisplay = GetDisplayName(result, SIGDN.SIGDN_NORMALDISPLAY);
SelectedDesktopAbsoluteParsing = GetDisplayName(result, SIGDN.SIGDN_DESKTOPABSOLUTEPARSING);
SelectedUrl = GetDisplayName(result, SIGDN.SIGDN_URL);
return DialogResult.OK;
}
private static string GetDisplayName(IShellItem item, SIGDN sigdnName)
{
item.GetDisplayName(sigdnName, out var ptr);
var name = Marshal.PtrToStringUni(ptr);
Marshal.FreeCoTaskMem(ptr);
return name;
}
private void SelectInitialPath(IFileOpenDialog dialog, string path)
{
uint atts = 0;
IntPtr idl = IntPtr.Zero;
if (SHILCreateFromPath(path, out idl, ref atts) == 0)
{
if (SHCreateShellItem(IntPtr.Zero, IntPtr.Zero, idl, out IShellItem initial) == 0)
{
dialog.SetFolder(initial);
}
Marshal.FreeCoTaskMem(idl);
}
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SHILCreateFromPath(string pszPath, out IntPtr ppIdl, ref uint rgflnOut);
[DllImport("shell32.dll")]
private static extern int SHCreateShellItem(IntPtr pidlParent, IntPtr psfParent, IntPtr pidl, out IShellItem ppsi);
private const uint ERROR_CANCELLED = 0x800704C7;
[ComImport]
[Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")]
private class FileOpenDialog
{
}
[Guid("42f85136-db7e-439c-85f1-e4075d135fc8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IFileOpenDialog
{
[PreserveSig]
uint Show(IntPtr parent); // IModalWindow
void SetFileTypes(); // not fully defined
void SetFileTypeIndex(uint iFileType);
void GetFileTypeIndex(out uint piFileType);
void Advise(); // not fully defined
void Unadvise();
void SetOptions(FOS fos);
void GetOptions(out FOS pfos);
void SetDefaultFolder(IShellItem psi);
void SetFolder(IShellItem psi);
void GetFolder(out IShellItem ppsi);
void GetCurrentSelection(out IShellItem ppsi);
void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
void GetFileName(out IntPtr pszName);
void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
void GetResult(out IShellItem ppsi);
void AddPlace(IShellItem psi, int alignment);
void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
void Close(int hr);
void SetClientGuid(); // not fully defined
void ClearClientData();
void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
void GetResults([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenum); // not fully defined
void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppsai); // not fully defined
}
[Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IShellItem
{
void BindToHandler(); // not fully defined
void GetParent(); // not fully defined
[PreserveSig]
int GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);
void GetAttributes(); // not fully defined
void Compare(); // not fully defined
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb762544.aspx
private enum SIGDN : uint
{
SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
SIGDN_FILESYSPATH = 0x80058000,
SIGDN_NORMALDISPLAY = 0,
SIGDN_PARENTRELATIVE = 0x80080001,
SIGDN_PARENTRELATIVEEDITING = 0x80031001,
SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001,
SIGDN_PARENTRELATIVEPARSING = 0x80018001,
SIGDN_URL = 0x80068000
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282.aspx
[Flags]
private enum FOS
{
FOS_ALLNONSTORAGEITEMS = 0x80,
FOS_ALLOWMULTISELECT = 0x200,
FOS_CREATEPROMPT = 0x2000,
FOS_DEFAULTNOMINIMODE = 0x20000000,
FOS_DONTADDTORECENT = 0x2000000,
FOS_FILEMUSTEXIST = 0x1000,
FOS_FORCEFILESYSTEM = 0x40,
FOS_FORCESHOWHIDDEN = 0x10000000,
FOS_HIDEMRUPLACES = 0x20000,
FOS_HIDEPINNEDPLACES = 0x40000,
FOS_NOCHANGEDIR = 8,
FOS_NODEREFERENCELINKS = 0x100000,
FOS_NOREADONLYRETURN = 0x8000,
FOS_NOTESTFILECREATE = 0x10000,
FOS_NOVALIDATE = 0x100,
FOS_OVERWRITEPROMPT = 2,
FOS_PATHMUSTEXIST = 0x800,
FOS_PICKFOLDERS = 0x20,
FOS_SHAREAWARE = 0x4000,
FOS_STRICTFILETYPES = 4
}
}
文档说:
你问:如果用户选择一个文件夹没有物理路径(例如,"我的计算机"),对话框上的OK按钮将被禁用。
有什么方法可以启用我的电脑的OK按钮吗?
有可能:使用函数:
[StructLayout(LayoutKind.Sequential)]
public struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
//public IntPtr pszDisplayName;
public string pszDisplayName;
public string lpszTitle;
public uint ulFlags;
public BrowseCallbackProc lpfn;
public IntPtr lParam;
public int iImage;
}
[DllImport("shell32.dll")]
public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi);
[DllImport("shell32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SHGetPathFromIDListW(IntPtr pidl, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszPath);
[DllImport("shell32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SHGetPathFromIDListW(IntPtr pidl, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszPath);
回呼可以设置为:
private int _callback(IntPtr hDlg, int msg, IntPtr lParam, IntPtr lpData)
{
switch (msg)
{
case 2://BFFM_SELCHANGED:
StringBuilder sb1 = new StringBuilder();
Win32.SHGetPathFromIDListW((IntPtr)lParam, sb);
Win32.EnableWindow(Win32.GetDlgItem(hDlg, CtlIds.IDOK), true);
break;
}
return 0;
}
调用:
BROWSEINFO bi = new Win32.BROWSEINFO();
bi.lpfn = new Win32.BrowseCallbackProc(callback);
string selected = SHBrowseForFolder(ref bi);
OK将被点击。唯一的问题,我还没有发现,是如何确保我的计算机被选中。
部分资料来源:http://www.codeproject.com/Articles/159352/FolderBrowserDialogEx-A-C-customization-of-FolderB