自己遍历吧,也不难得,msdn里有例子的,
自己写的控制起来更容易

解决方案 »

  1.   

    用C# 实现 文件夹浏览对话框 .NET框架提供许多标准的对话框类,你可以直接产生一个对话框类的实例来实现一个标准的Windows对话框。然而,不知出于什么原因,微软在.NET框架的类中并没有提供文件夹浏览对话框。为了实现一个文件夹浏览对话框,你可以从头开始采用Windows Form控件来实现这个对话框,你也可以从网上搜集大量的图标来模拟标准文件夹浏览对话框的外观,然而这种“仿真”的对话框与真正的文件夹对话框总是有着一段距离。为了实现真正的文件夹浏览对话框,我们从调用本机API函数入手实现这个真正的文件夹对话框。  在我们使用C#实现这个文件夹浏览对话框之前,你首先需要知道实现这样的对话框需要调用那些Windows Platform SDK函数。Windows为实现这样的对话框提供了一个SHBrowseForFolder函数,通过它能够允许用户从一个显示的对话框中选择一个Shell文件夹。这个函数需要一个BROWSEINFO类型的结构,返回一个ITEMIDLIST结构指针,用于标识选中的文件夹相对于名称空间根部的位置。如果用户选择了取消按扭,这个函数则返回一个NULL值。  为了获得用户选择的文件夹路径,程序还需要调用SHGetPathFromIDList 函数,以便把一个项目标识的列表转化成一个文件系统的路径。  另外调用上述函数的应用程序还有义务释放PIDL项目列表占有的内存,释放的方法是通过调用Shell内存分配器的IMalloc接口的Free方法。为了获得这个IMalloc接口的句柄,你还需要调用SHGetMalloc函数。   这些函数均为Shell32.DLL的输出函数。   使用C#实现文件夹浏览对话框由于需要跨平台的调用,所以程序必须引用System.Runtime.InteropServices :名称空间。为了实现与OpenFileDialog 和 SaveFileDialog对话框的一致性,我们也可以实现一个BrowseForFolder函数,让其返回一个DialogResult类型的值。这要求我们在程序中引用System.Windows.Forms名称空间。另外在程序中还需要在函数中传入传出字符串参数,我们可以使用StringBuilder类,这需要我们引用System.Text名称空间。    实现这样一个对话框的关键在于使用C# 结构和函数定义封装这些win32 函数,把它们的参数类型转化成C#或者说是.NET框架认可的类型。大概声明需要下面几个步骤:定义Win32 系统常量。 public const int _MAX_PATH=260;public const uint BIF_EDITBOX=0x0010;public const uint BIF_NEWDIALOGSTYLE=0x0040;1.      定义一个浏览回调函数的代理    public delegate int BFFCALLBACK(IntPtr/*HWND*/ hwnd, uint/*UINT*/ uMsg, IntPtr/*LPARAM*/ lParam, IntPtr/*LPARAM*/ lpData);2.      定义SHBrowseInfo函数需要的参数结构。   [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]                  public struct BROWSEINFO             {                  public IntPtr/*HWND*/ _hwndOwner;                  public IntPtr/*LPCITEMIDLIST*/ _pidlRoot;                  [MarshalAs(UnmanagedType.LPStr)] public string/*LPTSTR*/ _szDirectory;                  [MarshalAs(UnmanagedType.LPStr)] public string/*LPCTSTR*/ _lpszTitle;                  public uint/*UINT*/ _ulFlags;                  [MarshalAs(UnmanagedType.FunctionPtr)] public BFFCALLBACK/*BFFCALLBACK*/ _lpfn;                  public IntPtr/*LPARAM*/ _lParam;                  public int/*int*/ _iImage;                  public BROWSEINFO(IntPtr parent, string title)                  {                      _hwndOwner=parent;                      _pidlRoot=(IntPtr)0;                      _szDirectory=null;                      _lpszTitle=title;                      _ulFlags=BIF_EDITBOX|BIF_NEWDIALOGSTYLE;                      _lpfn=(BFFCALLBACK)null;                      _lParam=(IntPtr)0;                      _iImage=0;                  }             }   3.      定义IMalloc接口                  [ComImport]                  [Guid("00000002-0000-0000-C000-000000000046")]                  [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]                  internal interface IMalloc             {                  [PreserveSig] IntPtr/*void * */ Alloc(ulong/*ULONG*/ cb);                  [PreserveSig] IntPtr/*void * */ Realloc(IntPtr/*void * */ pv, ulong/*ULONG*/ cb);                  [PreserveSig] void/*void*/ Free(IntPtr/*void * */ pv);                  [PreserveSig] ulong/*ULONG*/ GetSize(IntPtr/*void * */ pv);                  [PreserveSig] int/*int*/ DidAlloc(IntPtr/*void * */ pv);                  [PreserveSig] void/*void*/ HeapMinimize();             }4.      声明三个上述的API函数。[DllImport("shell32.dll")]             public static extern IntPtr/*LPITEMIDLIST*/ SHBrowseForFolder(ref BROWSEINFO/*LPBROWSEINFO*/ lpbi);             [DllImport("shell32.dll")]             public static extern bool/*BOOL*/ SHGetPathFromIDList(IntPtr/*LPCITEMIDLIST*/ pidl, StringBuilder/*LPTSTR*/ pszPath);             [DllImport("Shell32.dll")]             public static extern int/*HRESULT*/ SHGetMalloc([MarshalAs(UnmanagedType.IUnknown)] out object /*LPMALLOC * */ ppMalloc);5.      最后通过一个自己定义的函数实现上述整个过程。    public static DialogResult BrowseForFolder(IntPtr parent, string title, out string path)        {             path=null;             Win32.BROWSEINFO browseInfo=new Win32.BROWSEINFO(parent, title);             IntPtr pidl=Win32.SHBrowseForFolder(ref browseInfo);             if (pidl==IntPtr.Zero) {return DialogResult.Cancel;}             try             {                  StringBuilder stringBuilder=new StringBuilder(Win32._MAX_PATH);                  if (Win32.SHGetPathFromIDList(pidl, stringBuilder))                  {                      path=stringBuilder.ToString();                      return DialogResult.OK;                  }                  else                  {                      return DialogResult.Cancel;                 }             }             finally             {                  // Free memory allocated by shell.                  object pMalloc=null;                  // Get the IMalloc interface and free the block of memory.                  if (Win32.SHGetMalloc(out pMalloc)==0/*NOERROR*/)                  {                      ((Win32.IMalloc)pMalloc).Free(pidl);                 }             }        }6.      调用方法。首先要包含上述全部定义的名称空间,比如:using ShellPlatformInvokeDemo; 然后就可以通过下面的代码实现一个对话框了。string path;             if (Shell.BrowseForFolder("Select a folder...", out path)==DialogResult.OK)             {                  Console.WriteLine("You selected \"{0}\".", path);             }             else             {                  Console.WriteLine("You cancelled the browse operation.");             }    以上程序在WindowsXP环境下用Visual Studio.NET调试通过,如果你觉得上述过程太烦琐,你可以编写使用Visual C++编写一个动态链接库或者创建一个ATL COM组件,把这些API函数直接使用C++代码调用,对外部只提供一个简单的用户接口。C#可以通过平台互操作调用这些动态链接库输出函数或者组件接口方法。使用C#实现的好处是不依赖其它组件或者动态链接库。