这个控件其实是 .NET 1.1 新增的一个控件,可以用来浏览文件夹。
对于 1.0 我写过一片文章来介绍如何做这样的一个控件 http://dev.csdn.net/Develop/article/21/article/17/17635.shtm
今天一个同事碰到了一个奇怪的问题,很简单的代码
FolderBrowserDialog dlg=new FolderBrowserDialog();
dlg.ShowDialog();
dlg.ShowDialog();
结果 文件夹选择窗体,显示不正确。结果如图所示
这个问题,其实很容易修复。只要把你当前进程的Appartment State 设置为 STA 就可以了,或者给 Main 函数加上一个属性
[STAThread]
public static void Main()
{
}
public static void Main()
{
}
出现这个问题,主要是跟 FolderBrowserDialog 的实现有关系,这个.NET 控件其实是 win32 Shell Ole 控件的一个重新包装,你可以通过reflector看到具体的代码
protected override bool RunDialog(IntPtr hWndOwner)
{
IntPtr ptr1 = IntPtr.Zero;
bool flag1 = false;
UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, (int) this.rootFolder, ref ptr1);
if (ptr1 == IntPtr.Zero)
{
UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, 0, ref ptr1);
if (ptr1 == IntPtr.Zero)
{
throw new Exception(SR.GetString("FolderBrowserDialogNoRootFolder"));
}
}
int num1 = 0x40;
if (!this.showNewFolderButton)
{
num1 += 0x200;
}
Application.OleRequired();
IntPtr ptr2 = IntPtr.Zero;
try
{
UnsafeNativeMethods.BROWSEINFO browseinfo1 = new UnsafeNativeMethods.BROWSEINFO();
IntPtr ptr3 = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
IntPtr ptr4 = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
UnsafeNativeMethods.BrowseCallbackProc proc1 = new UnsafeNativeMethods.BrowseCallbackProc(this.FolderBrowserDialog_BrowseCallbackProc);
browseinfo1.pidlRoot = ptr1;
browseinfo1.hwndOwner = hWndOwner;
browseinfo1.pszDisplayName = ptr3;
browseinfo1.lpszTitle = this.descriptionText;
browseinfo1.ulFlags = num1;
browseinfo1.lpfn = proc1;
browseinfo1.lParam = IntPtr.Zero;
browseinfo1.iImage = 0;
ptr2 = UnsafeNativeMethods.Shell32.SHBrowseForFolder(browseinfo1);
if (ptr2 != IntPtr.Zero)
{
UnsafeNativeMethods.Shell32.SHGetPathFromIDList(ptr2, ptr4);
this.selectedPathNeedsCheck = true;
this.selectedPath = Marshal.PtrToStringAuto(ptr4);
Marshal.FreeHGlobal(ptr4);
Marshal.FreeHGlobal(ptr3);
flag1 = true;
}
}
finally
{
UnsafeNativeMethods.IMalloc malloc1 = FolderBrowserDialog.GetSHMalloc();
malloc1.Free(ptr1);
if (ptr2 != IntPtr.Zero)
{
malloc1.Free(ptr2);
}
}
return flag1;
}
{
IntPtr ptr1 = IntPtr.Zero;
bool flag1 = false;
UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, (int) this.rootFolder, ref ptr1);
if (ptr1 == IntPtr.Zero)
{
UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, 0, ref ptr1);
if (ptr1 == IntPtr.Zero)
{
throw new Exception(SR.GetString("FolderBrowserDialogNoRootFolder"));
}
}
int num1 = 0x40;
if (!this.showNewFolderButton)
{
num1 += 0x200;
}
Application.OleRequired();
IntPtr ptr2 = IntPtr.Zero;
try
{
UnsafeNativeMethods.BROWSEINFO browseinfo1 = new UnsafeNativeMethods.BROWSEINFO();
IntPtr ptr3 = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
IntPtr ptr4 = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
UnsafeNativeMethods.BrowseCallbackProc proc1 = new UnsafeNativeMethods.BrowseCallbackProc(this.FolderBrowserDialog_BrowseCallbackProc);
browseinfo1.pidlRoot = ptr1;
browseinfo1.hwndOwner = hWndOwner;
browseinfo1.pszDisplayName = ptr3;
browseinfo1.lpszTitle = this.descriptionText;
browseinfo1.ulFlags = num1;
browseinfo1.lpfn = proc1;
browseinfo1.lParam = IntPtr.Zero;
browseinfo1.iImage = 0;
ptr2 = UnsafeNativeMethods.Shell32.SHBrowseForFolder(browseinfo1);
if (ptr2 != IntPtr.Zero)
{
UnsafeNativeMethods.Shell32.SHGetPathFromIDList(ptr2, ptr4);
this.selectedPathNeedsCheck = true;
this.selectedPath = Marshal.PtrToStringAuto(ptr4);
Marshal.FreeHGlobal(ptr4);
Marshal.FreeHGlobal(ptr3);
flag1 = true;
}
}
finally
{
UnsafeNativeMethods.IMalloc malloc1 = FolderBrowserDialog.GetSHMalloc();
malloc1.Free(ptr1);
if (ptr2 != IntPtr.Zero)
{
malloc1.Free(ptr2);
}
}
return flag1;
}
而shell32 的申明如下:
[SuppressUnmanagedCodeSecurity, ComVisible(false)]
internal class Shell32
{
// Methods
public Shell32();
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHBrowseForFolder([In] UnsafeNativeMethods.BROWSEINFO lpbi);
[DllImport("shell32.dll")]
public static extern int SHGetMalloc([Out, MarshalAs(UnmanagedType.LPArray)] UnsafeNativeMethods.IMalloc[] ppMalloc);
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern bool SHGetPathFromIDList(IntPtr pidl, IntPtr pszPath);
[DllImport("shell32.dll")]
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, ref IntPtr ppidl);
}
internal class Shell32
{
// Methods
public Shell32();
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHBrowseForFolder([In] UnsafeNativeMethods.BROWSEINFO lpbi);
[DllImport("shell32.dll")]
public static extern int SHGetMalloc([Out, MarshalAs(UnmanagedType.LPArray)] UnsafeNativeMethods.IMalloc[] ppMalloc);
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern bool SHGetPathFromIDList(IntPtr pidl, IntPtr pszPath);
[DllImport("shell32.dll")]
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, ref IntPtr ppidl);
}