2011-01-31 16 views
13

estoy de subclases de una aplicación. Mi procedimiento de ventana subclasificado está dentro de una DLL. Mi código de subclases dentro de la DLL se parece a esto (desmantelado, eliminado otras partes no relacionadas).CallbackOnCollectedDelegate se detectó

class FooBar 
{ 
    private delegate int WndProcDelegateType(IntPtr hWnd, int uMsg, 
              int wParam, int lParam); 

    private const int GWL_WNDPROC = (-4); 
    private static IntPtr oldWndProc = IntPtr.Zero; 
    private static WndProcDelegateType newWndProc = new 
                WndProcDelegateType(MyWndProc); 

    internal static bool bHooked = false; 

    [DllImport("user32.dll")] 
    private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, 
              WndProcDelegateType dwNewLong); 

    [DllImport("user32.dll")] 
    private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, 
              IntPtr dwNewLong); 


    [DllImport("user32")] 
    private static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, 
              int Msg, int wParam, int lParam); 

    private static int MyWndProc(IntPtr lhWnd, int Msg, int wParam, int lParam) 
    { 
    switch (Msg) 
    { 
     // the usual stuff 


     // finally 
     return CallWindowProc(oldWndProc, lhWnd, Msg, wParam, lParam); 
    } 


    internal static void Hook() 
    { 
    oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc); 
    bHooked = oldWndProc != IntPtr.Zero; 
    } 

    internal static void Unhook() 
    { 
    if (bHooked) SetWindowLong(hWnd, GWL_WNDPROC, oldWndProc); 
    } 
} 

Ahora, a pesar de que estoy sosteniendo una fuerte referencia a la WndProc en una instancia estática variable de nivel de clase del delegado, me sale este error.

CallbackOnCollectedDelegate se detectó

Mensaje: Una devolución de llamada se hizo en un delegado recogida de basura de tipo 'PowerPointAddIn1 FooBar + WndProcDelegateType :: Invoke!'. Esto puede causar bloqueos en la aplicación, corrupción y pérdida de datos. Al pasar delegados a código no administrado, hay que mantenerlos vivos por la aplicación administrada hasta se garantiza que nunca van a ser llamados .

¿Qué estoy haciendo mal?

Respuesta

25
oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, MyWndProc); 

que las fuerzas de C# para crear un objeto delegado de la marcha. Se traduce el código para esto:

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, new WndProcDelegateType(MyWndProc)); 

que es un problema, ese objeto delegado no se hace referencia a cualquier lugar. La próxima recolección de basura va a destruirlo, sacando la alfombra del código no administrado. Ya hiciste lo correcto en tu código, simplemente olvidaste usarlo. Solución:

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc); 

Derivación de su propia clase de NativeWindow y utiliza su método AssignHandle() es la mejor trampa para ratones por cierto. Llame a ReleaseHandle() cuando vea el mensaje WM_DESTROY.

+1

Gracias por su ayuda. Su respuesta es correcta pero aún así obtener la excepción. Me siento mucho que he publicado el código incorrecto. yo ya había hecho que el cambio antes de publicar esta pregunta. yo tenía el código en dos lugares y publicado el código anterior, que yo no había cambiado. todavía consigo la excepción. –

+0

Eh, ¿qué se supone que debo mirar? –

+0

@Hans:. en este momento, no he tenido que he dejado algo inexplicable –

9

me llaman loco, pero almacenar una referencia debería resolver este:

private static readonly WndProcDelegateType _reference = MyWndProc; 
+2

Gracias. Pensé que ya tenía una referencia. De todos modos, la única diferencia entre su declaración y la mía fue que utilicé el nuevo operador y usted no. Lo intenté de la manera que sugeriste, pero sigue arrojando la misma excepción. :-( –

+1

Si fuera así de simple, no estaría buscando en Google esto durante horas y horas ... – BrainSlugs83

2

la función de devolución de llamada se puede invocar después se devuelve la llamada, la persona que llama administrado debe tomar medidas para asegurar que el delegado permanece sin recoger hasta que la función de devolución de llamada termina. Para obtener información detallada sobre la prevención de la recolección de basura, consulte Interop Marshaling con invocación de plataforma.

http://msdn.microsoft.com/en-us/library/eaw10et3.aspx

+1

Gracias. Estoy en el medio de algo. Estudiaré el enlace que mencionas cuando tenga oportunidad. Muchas gracias por su ayuda. –

Cuestiones relacionadas