2010-05-11 8 views
5

Estoy obteniendo InvalidCastException al azar cuando se muestra FolderBrowserDialog y también muchos clientes han informado esto.WinForms: ¿Por qué obtengo InvalidCastException al mostrar el cuadro de diálogo del navegador de carpetas?

No he podido encontrar nada relevante en internet. ¿Alguien sabe qué causa esto/cómo solucionar esto?

Mi código:

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

Seguimiento de la pila:

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: Información adicional: He sido capaz de reproducir esto sólo cuando se ejecuta en depurador VS2008.

Cuando se queda sin depurador, ocurre muy raramente (sucedió una o dos veces en 6 meses) en mi Windows 7 de 64 bits y desaparece después de reiniciar.

Los clientes ciertamente no están ejecutando la aplicación en el depurador por lo que seguramente es reproducible de depurador.

+0

Guau, eso es raro. Ese código parece perfectamente inofensivo. ¿Intentó actualizar o degradar .NET? – Thomas

+0

¿Llamas al 'FolderBrowserDialog' de un hilo que no sea el del UI? –

+0

@Thomas: No, y no intentaré eso ni puedo pedirle a ninguno de los usuarios que lo hagan – Marek

Respuesta

1

Aquí hay un par de reflexiones:

Por lo que yo puedo decir por el uso de Reflector.Net esto se les metan en el bloque finally justo después de los rendimientos reales de diálogo. Aquí está, básicamente, en su conseguir el problema:

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

Si su no ver el cuadro de diálogo en absoluto la excepción anterior es probablemente enmascarar el verdadero error. Intenta ejecutar con 'Break on Exception' e inhabilita Tools-> Debugging-> Just my code. El código en el bloque try parece bastante básico, lo más arriesgado que están haciendo es PInvoke en SHBrowseForFolder de shell32.dll. Me sorprendería que esté generando un error "aleatorio".

Si usted está viendo el cuadro de diálogo y sólo durante el cierre se consigue este error, entonces usted podría ignorarlo a expensas de una fuga de memoria cuando esto sucede:

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

Por supuesto, siempre se puede PInvoke the SHBrowseForFolder mismo y no use la clase de diálogo.

+0

Sí, estoy obteniendo esto después de que se cierre el diálogo. Gracias por el truco, creo que tendré que seguir este camino, pero no estoy seguro de si la ruta seleccionada será la correcta. Comprobará mañana. ¿Estás sugiriendo mostrar el diálogo dos veces? – Marek

+0

Lo siento, sí, el segundo espectáculo es un error. –

0

Este síntoma parece tener happened to others, así que al menos no están solos ;-)

Un par de posibilidades:

  1. ¿Está ejecutando esto en un apartamento individual roscado (es decir, con la [ STAThreadAttribute] en el método de punto de entrada)?
  2. La longitud máxima de la ruta en Windows es de 260 caracteres. ¿Podría la ruta inicial utilizada por el FolderBrowserDialog ser más larga que esto? Si puede (ocasionalmente) reproducir esto en el modo de depuración VS, intente mover su solución más arriba en su árbol de carpetas, acortando así la ruta de carpeta predeterminada utilizada por el cuadro de diálogo.
+0

1. por supuesto :) 2. no, la longitud de la ruta no es un problema aquí. – Marek

0

Considere utilizar el Windows® API Code Pack for Microsoft® si no necesita soportar XP o Windows 2003. Tal vez su cuadro de diálogo de buscador de carpetas no solo es más bonito sino también más estable ...

+0

Necesito admitir todas las versiones de Windows, incluido WinXP – Marek

0

Tuve casi el mismo problema (también una InvalidCastException) en mi proyecto, que solo ocurría a veces.

Venía de un subproceso que no se ejecutaba como STAThread. Aunque mi método principal fue etiquetado con el atributo [STAThread].

Has dicho que no estás utilizando un hilo por separado. Pero quizás usted no tenga conocimiento de, debido a un delegado asíncrono, que no usa explícitamente una clase Thread, sino que se trata como uno solo.

Si crea subprocesos nuevos, (no importa si lo crea con el ThreadPool o un delegado asincrónico), siempre son subprocesos MTA. Por lo tanto, debe crear su Thread por su cuenta e iniciarlo explícitamente como STAThread.

Usted puede hacer esto como:

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

yo creo que hay que excavar en esa dirección para encontrar el fallo.

+0

Este diálogo del buscador de carpetas se muestra directamente desde un botón. Haga clic en el controlador de eventos. No hay delegados/BeginInvokes/... que puedan ocultar un problema de subprocesamiento. – Marek

Cuestiones relacionadas