Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 348
Marek Avatar asked May 11 '10 15:05

Marek


1 Answers

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.

like image 52
csharptest.net Avatar answered Oct 04 '22 02:10

csharptest.net