wndproc上的SetWindowLong导致旧的wndproc被垃圾收集

时间:2012-10-22 12:46:02

标签: c# interop

我有一个让我疯狂的问题。我花了一个星期追逐这个bug,可能只是我不理解互操作以及我认为。这是:

 public class User
{
  public const int GWL_WNDPROC = -4;

   [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, User.WindowProc newProc);

   [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    public delegate IntPtr WindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

 }

这是我的基本User32包装器。现在打电话给:

class MyClass
{
  private User.WindowProc proc;

  public void MyMethod()
  {      
    proc = new User.WindowProc(WndProc);

    old_window_proc = User.SetWindowLong(handle,User.GWL_WNDPROC,proc);
  }

}

强制垃圾收集:

   GC.Collect();
   GC.WaitForPendingFinalizers();

然后打电话给:

User.CallWindowProc(old_window_proc,hWnd,   (uint)message.Msg,message.WParam,message.LParam);

我收到* CallbackOnCollectedDelegate * 错误。为什么旧的Winproc指针中存在的非托管代码会得到GC?如果我加上这个:

oldProcHolder = (User.WindowProc)Marshal.GetDelegateForFunctionPointer(old_window_proc, typeof(User.WindowProc));

在SetWindowLong()之后,它保持它并且没有错误。

我想我完全不理解为什么旧的非托管代码有资格进行垃圾回收?这让我疯了。提前谢谢!

1 个答案:

答案 0 :(得分:0)

GetDelegateForFunctionPointer函数在使用时,非托管函数被转换为托管代码,即委托。由于任何委托都是托管代码,因此垃圾收集过程会自动运行。因此,GetDelegateForFunctionPointer函数适用于自动垃圾收集。