WinForms: Why do I get InvalidCastException when showing folder browser dialog?
Asked Answered
B

3

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.

Biscay answered 11/5, 2010 at 15:4 Comment(5)
Wow, that's weird. That code looks perfectly harmless. Did you try upgrading or downgrading .NET?Babble
Are you calling the FolderBrowserDialog from a thread other than the UI thread?Teeterboard
@Thomas: No and I will not try that nor can I ask any of the users to do thatBiscay
@João: No. From the UI thread directly.Biscay
I was asking because this looks (to me) like it might be a framework bug. Especially if you're on the UI thread. If you're unwilling to rule out that option, suit yourself :)Babble
L
1

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.

Languishment answered 11/5, 2010 at 16:58 Comment(1)
Yes, I am getting this after the dialog is closed. Thanks for the catch tip, I think I will have to go this path but I am not sure if the selectedPath will be correct. Will check tommorrow. Are you suggesting to show the dialog twice?Biscay
G
0

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.
Grandfather answered 11/5, 2010 at 17:19 Comment(0)
S
0

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.

Septi answered 12/5, 2010 at 14:31 Comment(1)
This folder browser dialog is shown directly from a button.Click event handler. No delegates/BeginInvokes/... that could hide a threading issue.Biscay

© 2022 - 2024 — McMap. All rights reserved.