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

发布于 2024-09-01 15:10:30 字数 1001 浏览 2 评论 0原文

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

客户端肯定不会在调试器中运行该应用程序,因此它肯定可以在调试器中重现。

I am randomly getting InvalidCastException when showing FolderBrowserDialog and also many clients have reported this.

I have not been able to find anything relevant on the internet. Does anyone know what causes this/how to fix this?

My code:

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

Stack trace:

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

EDIT: Additional information: I have been able to reproduce this only when running in VS2008 debugger.

When running out of debugger, it happens only very rarely (happened once or twice in 6 months) on my 64 bit Windows 7 and goes away after restart.

The clients are certainly not running the app in debugger so it is surely reproducible out of debugger.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

合久必婚 2024-09-08 15:10:30

这里有一些想法:

据我从使用 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)
            ...

当然,您始终可以 P自己调用 SHBrowseForFolder 并且不使用对话框类。

Here is a couple of thoughts:

As far as I can tell from using Reflector.Net this is getting thrown in the finally block just after the actual dialog returns. Here is basically where your getting the problem:

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);
    ...

If your not seeing the dialog at all the exception above is probably masking the real error. Try running with 'Break on Exception' and disable Tools->Debugging->Just my code. The code in the try block looks pretty basic, the most risky thing they are doing is PInvoke on shell32.dll's SHBrowseForFolder I'd be surprised if it's generating a 'random' error.

If you are seeing the dialog and only upon closing do you get this error then you could just ignore it at the expense of leaking memory when this happens:

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

Of course you can always PInvoke the SHBrowseForFolder yourself and not use the dialog class.

帅冕 2024-09-08 15:10:30

这种症状似乎发生在其他人身上,所以至少你并不孤单;-)

有几种可能性:

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

This symptom seems to have happened to others, so at least you are not alone ;-)

A couple of possibilities:

  1. Are you running this in a single threaded apartment (i.e. with the [STAThreadAttribute] on the entry point method)?
  2. The maximum path length in Windows is 260 characters. Could the initial path used by the FolderBrowserDialog be longer than this? If you can (occasionally) reproduce this in VS debug mode, try moving your solution higher in your folder tree, thus shortening the default folder path used by the dialog.
因为看清所以看轻 2024-09-08 15:10:30

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

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

你说过,你没有使用单独的线程。但也许您没有意识到,因为异步委托并不显式使用 Thread 类,而是将其视为一个类。

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

你可以这样做:

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

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

I had almost the same Problem (also an InvalidCastException) in my project, which only occured sometimes.

It came from a Thread that hasn't been running as a STAThread. Although my Main method was tagged with the [STAThread] Attribute.

You said, that you'r not using a separate thread. But perhaps you'r not aware of, because of an async delegate, which does not explicit uses a Thread class, but treated as one.

If you create new threads, (doesn't matter if you create it with the ThreadPool or an async delegate), they are always MTA Threads. So you have to create your Thread by your own and starting it explicit as an STAThread.

You can do this like:

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

I think you have to dig in that direction to find the bug.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文