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

时间:2010-05-11 15:04:10

标签: c# winforms .net-2.0 folderbrowserdialog

我在显示FolderBrowserDialog时随机获取InvalidCastException,并且许多客户端都报告了这一点。

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

我的代码:

        using (FolderBrowserDialog fbd = new FolderBrowserDialog())
        {
            fbd.ShowNewFolderButton = false;
            if (fbd.ShowDialog() == DialogResult.OK)

堆栈追踪:

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()

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

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

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

4 个答案:

答案 0 :(得分: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);
    ...

如果您没有看到上述所有异常的对话框,则可能掩盖了真正的错误。尝试运行'Break on Exception'并禁用Tools-> Debugging->只需我的代码。 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)
            ...

当然你总是PInvoke the SHBrowseForFolder自己而不是使用对话框类。

答案 1 :(得分:0)

这个症状似乎有happened to others,所以至少你并不孤单; - )

有几种可能性:

  1. 您是在单线程单元中运行它(即在入口点方法上使用[STAThreadAttribute])?
  2. Windows中的最大路径长度为260个字符。 FolderBrowserDialog使用的初始路径可能比这长吗?如果您(偶尔)可以在VS调试模式下重现此操作,请尝试在文件夹树中更高的位置移动解决方案,从而缩短对话框使用的默认文件夹路径。

答案 2 :(得分:0)

如果您不需要支持XP或Windows 2003,可以考虑使用Windows® API Code Pack for Microsoft®。也许它的文件夹浏览器对话框不仅更漂亮,而且更稳定......

答案 3 :(得分:0)

我的项目中有几乎相同的问题(也是InvalidCastException),有时只会发生。

它来自一个尚未作为STAThread运行的线程。虽然我的Main方法用[STAThread]属性标记。

你说,你没有使用单独的线程。但也许你不知道,因为异步委托,它没有显式使用Thread类,而是被视为一个。

如果您创建新线程(如果使用ThreadPool或异步委托创建它,则无关紧要),它们始终是MTA线程。因此,您必须自己创建线程并将其显式为STAThread。

您可以这样做:

var thread=new Thread( () => method() );
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

我认为你必须深入研究这个方向。