4

在我的应用程序中,我希望 folderBrowserDialog 允许选择My Computer. My Computer但是从对话框中选择后,确定按钮会被禁用。

有什么方法可以选择My ComputerinBrowse Dialog吗?

4

3 回答 3

4

我的电脑(或更新的 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属性中定义的其他文件夹的特殊值。对于我的电脑,该值将始终为“ ::{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
    }
}
于 2015-11-19T22:50:45.760 回答
2

文档说:

如果用户选择没有物理路径的文件夹(例如,我的电脑),对话框上的确定按钮将被禁用。

你问:

有什么方法可以启用我的电脑的确定按钮吗?

那没有。

于 2013-05-19T20:31:32.037 回答
0

有一种可能:使用功能:

   [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-AC-customization-of-FolderB

于 2015-11-19T13:58:58.400 回答