【问题标题】:WinForms: Why do I get InvalidCastException when showing folder browser dialog?WinForms:为什么在显示文件夹浏览器对话框时会出现 InvalidCastException?
【发布时间】:2011-02-18 04:51:45
【问题描述】:

我在显示 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 个月内发生一次或两次),并且在重新启动后消失。

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

【问题讨论】:

  • 哇,这很奇怪。该代码看起来完全无害。您是否尝试升级或降级 .NET?
  • 您是从 UI 线程以外的线程调用 FolderBrowserDialog 吗?
  • @Thomas:不,我不会尝试,也不能要求任何用户这样做
  • @João:不。直接来自 UI 线程。
  • 我问是因为这看起来(对我来说)可能是一个框架错误。特别是如果您在 UI 线程上。如果您不愿意排除该选项,请适合自己:)

标签: c# winforms .net-2.0 folderbrowserdialog


【解决方案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);
    ...

如果您根本没有看到上述异常对话框,则可能掩盖了真正的错误。尝试使用“异常中断”运行并禁用工具->调试->只是我的代码。 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 自己而不使用对话框类。

【讨论】:

  • 是的,我在对话框关闭后得到这个。感谢您的提示,我想我将不得不走这条路,但我不确定 selectedPath 是否正确。明天检查。您是否建议显示两次对话框?
【解决方案2】:

这个症状好像有happened to others,所以至少你不是一个人;-)

几种可能性:

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

【讨论】:

    【解决方案3】:

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

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

    您说过,您没有使用单独的线程。但也许你不知道,因为异步委托没有明确使用 Thread 类,而是将其视为一个。

    如果您创建新线程(无论是使用 ThreadPool 还是异步委托创建都无所谓),它们始终是 MTA 线程。因此,您必须自己创建线程并将其作为 STAThread 显式启动。

    你可以这样做:

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

    我认为你必须朝那个方向挖掘才能找到错误。

    【讨论】:

    • 此文件夹浏览器对话框直接从按钮显示。单击事件处理程序。没有可以隐藏线程问题的委托/BeginInvokes/...。
    猜你喜欢
    • 2019-12-21
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多