.net环境中使用FolderBrowser

类别:.NET开发 点击:0 评论:0 推荐:

好久没有动手写东西了(其实以前什么也没写过;-)),今天要写的可能已经有哪位前辈完成了。拙作实在不敢拿出来现丑,高手看标题和上面的贴图就可以决定要不要看下去。不浪费大家时间。

客户的要求:有一个winform程序,用户要求可以自己选择数据文件存放的位置,简单点说就是在硬盘上选择一个目录。

最初的想法: Win32 SDK中有一个SHBrowseForFolder API,这也是平时使用最频繁的方法,既然用.net开发程序当然想尽量用.net framework提供的managed代码。

问题:  查阅MSDN,发现FolderBrowser类与SHBrowseForFolder的一样的功能,但是帮助文件提示:FolderNameEditor.FolderBrowser 类型支持 .NET 框架结构,因此不适用于直接从代码中使用。 ms似乎并不希望开发人员直接利用这个类,文档中没有关于这个类成员的任何说明。FolderBrowser类的申明如下:[C#]
protected sealed class FolderNameEditor.FolderBrowser : Component 属性是protected和sealed. 

解决方法:FolderBrowser嵌套地定义在类FolderNameEditor中,还好ms没有做绝把它也做成protected和sealed,这样通过继承FolderNameEditor,再在继承类中实例化一个FolderBrowser类就可以调用这个对话框了。至于FolderBrowser的成员可以通过其它查看.net汇编的小工具获得,推荐 使用lutz Roader's .net reflector,在下面的截图可以看到FolderBrowser的所有成员。


该类实际上只有一个方法ShowDialog,反汇编以后差一点吐血。大家看看下面的就明白了。

FolderBrowser.ShowDialog

.maxstack 3
.locals (IntPtr V_0, IntPtr V_1, int V_2, IntPtr V_3, BROWSEINFO V_4, IntPtr V_5, IMalloc V_6, DialogResult V_7)
.try L_0056 to L_00f0 finally L_00f0 to L_0115
L_0000: ldsfld IntPtr.Zero
L_0005: stloc.0
L_0006: ldarg.1
L_0007: brfalse.s L_0012
L_0009: ldarg.1
L_000a: callvirt IWin32Window.get_Handle
L_000f: stloc.1
L_0010: br.s L_0018
L_0012: call UnsafeNativeMethods.GetActiveWindow
L_0017: stloc.1
L_0018: ldloc.1
L_0019: ldarg.0
L_001a: ldfld FolderBrowser.startLocation
L_001f: ldloca.s V_0
L_0021: call Shell32.SHGetSpecialFolderLocation
L_0026: pop
L_0027: ldloc.0
L_0028: ldsfld IntPtr.Zero
L_002d: call IntPtr.op_Equality
L_0032: brfalse.s L_0036
L_0034: ldc.i4.2
L_0035: ret
L_0036: ldarg.0
L_0037: ldfld FolderBrowser.publicOptions
L_003c: ldarg.0
L_003d: ldfld FolderBrowser.privateOptions
L_0042: or
L_0043: stloc.2
L_0044: ldloc.2
L_0045: ldc.i4.s 64
L_0047: and
L_0048: brfalse.s L_0050
L_004a: call Application.OleRequired
L_004f: pop
L_0050: ldsfld IntPtr.Zero
L_0055: stloc.3
L_0056: newobj BROWSEINFO..ctor
L_005b: stloc.s V_4
L_005d: ldsfld FolderBrowser.MAX_PATH
L_0062: call Marshal.AllocHGlobal
L_0067: stloc.s V_5
L_0069: ldloc.s V_4
L_006b: ldloc.0
L_006c: stfld BROWSEINFO.pidlRoot
L_0071: ldloc.s V_4
L_0073: ldloc.1
L_0074: stfld BROWSEINFO.hwndOwner
L_0079: ldloc.s V_4
L_007b: ldloc.s V_5
L_007d: stfld BROWSEINFO.pszDisplayName
L_0082: ldloc.s V_4
L_0084: ldarg.0
L_0085: ldfld FolderBrowser.descriptionText
L_008a: stfld BROWSEINFO.lpszTitle
L_008f: ldloc.s V_4
L_0091: ldloc.2
L_0092: stfld BROWSEINFO.ulFlags
L_0097: ldloc.s V_4
L_0099: ldsfld IntPtr.Zero
L_009e: stfld BROWSEINFO.lpfn
L_00a3: ldloc.s V_4
L_00a5: ldsfld IntPtr.Zero
L_00aa: stfld BROWSEINFO.lParam
L_00af: ldloc.s V_4
L_00b1: ldc.i4.0
L_00b2: stfld BROWSEINFO.iImage
L_00b7: ldloc.s V_4
L_00b9: call Shell32.SHBrowseForFolder
L_00be: stloc.3
L_00bf: ldloc.3
L_00c0: ldsfld IntPtr.Zero
L_00c5: call IntPtr.op_Equality
L_00ca: brfalse.s L_00d1
L_00cc: ldc.i4.2
L_00cd: stloc.s V_7
L_00cf: leave.s L_0117
L_00d1: ldloc.3
L_00d2: ldloc.s V_5
L_00d4: call Shell32.SHGetPathFromIDList
L_00d9: pop
L_00da: ldarg.0
L_00db: ldloc.s V_5
L_00dd: call Marshal.PtrToStringAuto
L_00e2: stfld FolderBrowser.directoryPath
L_00e7: ldloc.s V_5
L_00e9: call Marshal.FreeHGlobal
L_00ee: leave.s L_0115
L_00f0: call FolderBrowser.GetSHMalloc
L_00f5: stloc.s V_6
L_00f7: ldloc.s V_6
L_00f9: ldloc.0
L_00fa: callvirt IMalloc.Free
L_00ff: ldloc.3
L_0100: ldsfld IntPtr.Zero
L_0105: call IntPtr.op_Inequality
L_010a: brfalse.s L_0114
L_010c: ldloc.s V_6
L_010e: ldloc.3
L_010f: callvirt IMalloc.Free
L_0114: endfinally
L_0115: ldc.i4.1
L_0116: ret
L_0117: ldloc.s V_7
L_0119: ret
费了那么多劲原来它自己也是通过interop调用SHBrowseForFolder,那还不如直接调用这个API。

完整的FolderBrowser类

using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections;
namespace FolderBrowser 
{
 /// <summary>
 /// Summary description for FolderBrowser.
 /// </summary>
 ///

 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
 [ComVisible(true)]
 public class BROWSEINFO {
  public IntPtr hwndOwner;
  public IntPtr pidlRoot;
  public IntPtr pszDisplayName;
  public string lpszTitle;
  public int ulFlags;
  public IntPtr lpfn;
  public IntPtr lParam;
  public int iImage;
 }

 [Flags, Serializable]
 public enum BrowseFlags {
  BIF_DEFAULT    = 0x0000,

  BIF_BROWSEFORCOMPUTER = 0x1000,

  BIF_BROWSEFORPRINTER = 0x2000,

  BIF_BROWSEINCLUDEFILES = 0x4000,

  BIF_BROWSEINCLUDEURLS = 0x0080,

  BIF_DONTGOBELOWDOMAIN = 0x0002,

  BIF_EDITBOX    = 0x0010,

  BIF_NEWDIALOGSTYLE  = 0x0040,

  BIF_NONEWFOLDERBUTTON = 0x0200,

  /// </summary>
  BIF_RETURNFSANCESTORS = 0x0008,

  BIF_RETURNONLYFSDIRS = 0x0001,

  BIF_SHAREABLE   = 0x8000,

  BIF_STATUSTEXT   = 0x0004,

  BIF_UAHINT    = 0x0100,

  BIF_VALIDATE   = 0x0020,

  BIF_NOTRANSLATETARGETS = 0x0400,
 }

 


 public class API {
  [DllImport("shell32.dll", PreserveSig=true, CharSet=CharSet.Auto)]
  public static extern IntPtr SHBrowseForFolder(BROWSEINFO bi);

  [DllImport("shell32.dll", PreserveSig=true, CharSet=CharSet.Auto)]
  public static extern bool SHGetPathFromIDList(IntPtr pidl, IntPtr pszPath);

  [DllImport("shell32.dll", PreserveSig=true, CharSet=CharSet.Auto)]
  public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, ref IntPtr ppidl);
 }


 public class FolderBrowser
 {
  private string m_strDirectoryPath;
  private string m_strTitle;
  private string m_strDisplayName;
  private BrowseFlags m_Flags;
  public FolderBrowser()
  {
   //
   // TODO: Add constructor logic here
   //
   m_Flags = BrowseFlags.BIF_DEFAULT;
   m_strTitle = "";

  }

  public string DirectoryPath {
   get{return this.m_strDirectoryPath;}
  }


  public string DisplayName {
   get{return this.m_strDisplayName;}
  }


  public string Title {
   set{this.m_strTitle = value;}
  }


  public BrowseFlags Flags {
   set{this.m_Flags = value;}
  }
  public DialogResult ShowFolderBrowser() {
   
   BROWSEINFO bi = new BROWSEINFO();
   bi.pszDisplayName = IntPtr.Zero;
   bi.lpfn = IntPtr.Zero;
   bi.lParam = IntPtr.Zero;
   bi.lpszTitle = "Select Folder";
   IntPtr idListPtr = IntPtr.Zero;
   IntPtr pszPath = IntPtr.Zero;
   try {
    if (this.m_strTitle.Length != 0) {
     bi.lpszTitle = this.m_strTitle;
    }
    bi.ulFlags = (int)this.m_Flags;
    bi.pszDisplayName = Marshal.AllocHGlobal(256);
   
    idListPtr = API.SHBrowseForFolder(bi);
  
    if (idListPtr == IntPtr.Zero) {
     return DialogResult.Cancel;
    }

  
    pszPath = Marshal.AllocHGlobal(256);
  
    bool bRet = API.SHGetPathFromIDList(idListPtr, pszPath);
  
    m_strDirectoryPath = Marshal.PtrToStringAuto(pszPath);
    this.m_strDisplayName = Marshal.PtrToStringAuto(bi.pszDisplayName);
   }
   catch (Exception ex) {
    Trace.WriteLine(ex.Message);
    return DialogResult.Abort;
   }
   finally {
   
    if (idListPtr != IntPtr.Zero) {
     Marshal.FreeHGlobal(idListPtr);
    }
    if (pszPath != IntPtr.Zero) {
     Marshal.FreeHGlobal(pszPath);
    }
    if (bi != null) {
     Marshal.FreeHGlobal(bi.pszDisplayName);
    }
   }
   return DialogResult.OK;
         }
 }
}

如何调用这个类:

FolderBrowser aFolderBrowser = new FolderBrowser();
   aFolderBrowser.Title = "Select a Folder";
   aFolderBrowser.Flags = BrowseFlags.BIF_NEWDIALOGSTYLE|BrowseFlags.BIF_EDITBOX|BrowseFlags.BIF_STATUSTEXT;
   DialogResult result = aFolderBrowser.ShowFolderBrowser();
   if (result == DialogResult.OK ) {
   textBox1.Text = aFolderBrowser.DirectoryPath;

本文地址:http://com.8s8s.com/it/it45804.htm