代码之家  ›  专栏  ›  技术社区  ›  Marek

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

  •  6
  • Marek  · 技术社区  · 15 年前

    当显示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()
    

    当调试器用完时,它在64位Windows7上很少发生(6个月内发生一次或两次),并且在重新启动后消失。

    客户机肯定没有在调试器中运行应用程序,因此它肯定可以在调试器外复制。

    4 回复  |  直到 10 年前
        1
  •  1
  •   csharptest.net    15 年前

    以下是一些想法:

    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 而不是使用对话类。

        2
  •  0
  •   Simon Chadwick    15 年前

    这种症状似乎有 happened to others

    有几种可能性:

    1. 您是在一个单线程单元(即在入口点方法上使用[stathreaddattribute]运行这个程序吗?
        3
  •  0
  •   BitKFu    15 年前

    在我的项目中,我遇到了几乎相同的问题(也是一个InvalidCastException),这只是偶尔发生的。

    它来自一个没有作为STAThread运行的线程。尽管我的主方法被标记为[STAThread]属性。

    你说,你不用单独的线。但也许你不知道 ,因为异步委托不显式地使用线程类,而是作为一个线程类处理。

    它们总是MTA线程 . 因此,您必须自己创建线程,并以STAThread的形式显式启动它。

    你可以这样做:

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

    推荐文章