WinForms:为什么在显示文件夹浏览器对话框时会出现InvalidCastException?

Mar*_*rek 6 c# folderbrowserdialog .net-2.0 winforms

我在显示FolderBrowserDialog时随机获取InvalidCastException,并且许多客户端都报告了此情况.

我无法在互联网上找到任何相关内容.有谁知道是什么导致这个/如何解决这个问题?

我的代码:

        using (FolderBrowserDialog fbd = new FolderBrowserDialog())
        {
            fbd.ShowNewFolderButton = false;
            if (fbd.ShowDialog() == DialogResult.OK)
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪:

Error: System.InvalidCastException: 
'Unable to cast object of type 'System.__ComObject' to type 'IMalloc'.'.

    Stack trace:    
at System.Windows.Forms.UnsafeNativeMethods.Shell32.SHGetMalloc(IMalloc[] ppMalloc)
at System.Windows.Forms.FolderBrowserDialog.GetSHMalloc()
at System.Windows.Forms.FolderBrowserDialog.RunDialog(IntPtr hWndOwner)
at System.Windows.Forms.CommonDialog.ShowDialog(IWin32Window owner)
at System.Windows.Forms.CommonDialog.ShowDialog()
Run Code Online (Sandbox Code Playgroud)

编辑:附加信息:我只能在VS2008调试器中运行时才能重现这一点.

当用完调试器时,它在我的64位Windows 7上很少发生(在6个月内发生过一次或两次),并在重启后消失.

客户端肯定没有在调试器中运行应用程序,所以它肯定可以从调试器中重现.

csh*_*net 1

这里有一些想法:

据我所知,使用 Reflector.Net 会在实际对话框返回后将其抛出到finally 块中。这基本上是您遇到问题的地方:

IntPtr pszPath = IntPtr.Zero;
try
{
    UnsafeNativeMethods.BROWSEINFO lpbi = new UnsafeNativeMethods.BROWSEINFO();
    hglobal = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
    pszPath = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
    ... /*init structure*/
    pidl = UnsafeNativeMethods.Shell32.SHBrowseForFolder(lpbi);
    if (pidl != IntPtr.Zero)
    {
        UnsafeNativeMethods.Shell32.SHGetPathFromIDList(pidl, pszPath);
        ...
    }
}
finally
{
    UnsafeNativeMethods.IMalloc sHMalloc = GetSHMalloc(); /* Boom! */
    sHMalloc.Free(zero);
    ...
Run Code Online (Sandbox Code Playgroud)

如果您根本没有看到该对话框,上面的异常可能掩盖了真正的错误。尝试使用“异常中断”运行并禁用“工具”->“调试”->“仅我的代码”。try 块中的代码看起来非常基本,他们所做的最危险的事情是 shell32.dll 的 SHBrowseForFolder 上的 PInvoke,如果它生成“随机”错误,我会感到惊讶。

如果您看到该对话框并且仅在关闭时才收到此错误,那么您可以忽略它,但发生这种情况时会导致内存泄漏:

    using (FolderBrowserDialog fbd = new FolderBrowserDialog())
    {
        fbd.ShowNewFolderButton = false;
        DialogResult r;
        try { r = fbd.ShowDialog(); }
        catch (InvalidCastException) 
        { r = DialogResult.OK; /* you might check the path first */ }
        if (fbd.ShowDialog() == DialogResult.OK)
            ...
Run Code Online (Sandbox Code Playgroud)

当然,您始终可以自己PInvoke SHBrowseForFolder,而不使用对话框类。