检测到CallbackOnCollectedDelegate

Wat*_* v2 15 c# winapi unmanaged

我是一个应用程序的子类.我的子类Window过程在DLL中.我在DLL中的子类代码看起来有点像这样(剥离,删除其他不相关的部分).

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,即使我在委托的类级静态实例变量中持有对WndProc的强引用,我也会收到此错误.

检测到CallbackOnCollectedDelegate

消息:对类型为"PowerPointAddIn1!FooBar + WndProcDelegateType :: Invoke"的垃圾回收委托进行了回调.这可能会导致应用程序崩溃,损坏和数据丢失.将委托传递给非托管代码时,托管应用程序必须将它们保持活动状态,直到确保它们永远不会被调用.

我究竟做错了什么?

Han*_*ant 29

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, MyWndProc);
Run Code Online (Sandbox Code Playgroud)

这迫使C#即时创建委托对象.它将代码转换为:

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, new WndProcDelegateType(MyWndProc));
Run Code Online (Sandbox Code Playgroud)

这是一个问题,委托对象没有被引用到任何地方.下一个垃圾收集将破坏它,从非托管代码下拉出地毯.你已经在你的代码中做了正确的事情,你只是忘了使用它.固定:

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc);
Run Code Online (Sandbox Code Playgroud)

从NativeWindow派生自己的类并使用其AssignHandle()方法是更好的捕鼠器顺便说一句.当您看到WM_DESTROY消息时调用ReleaseHandle().


Cha*_*ion 10

叫我疯了但存储引用应该解决这个问题:

 private static readonly WndProcDelegateType _reference = MyWndProc;  
Run Code Online (Sandbox Code Playgroud)

  • 谢谢.我以为我已经有了参考资料.无论如何,你的声明和我的声明之间的唯一区别是我使用了新的运算符而你却没有.我按照你的建议尝试了它,但它仍然会抛出同样的异常.:-( (2认同)