【问题标题】:SetWindowsLong on winproc causes old winproc to be garbage collectedwndproc 上的 SetWindowLong 导致旧的 wndproc 被垃圾收集
【发布时间】:2012-10-12 06:45:58
【问题描述】:

我有一个问题让我发疯。我花了一周的时间追查这个错误,这可能只是我对互操作的理解不如我想的那么好。这里是:

 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() 之后它会一直保持它并且没有错误。

我想我完全不明白为什么旧的非托管代码有资格进行垃圾收集?它快把我逼疯了。提前致谢!

【问题讨论】:

  • 垃圾收集器看不到非托管对象持有的引用。您需要通过自己存储委托对象来解决此问题,以便 GC 可以看到它。只要窗口还活着,就一直引用它。当您看到 WM_DESTROY 消息时,将其设置回 null 并恢复窗口过程。
  • 这对我来说没有意义。请在这里忍受我...
  • 旧的 WinProc 不受管理。为什么GC会碰它?
  • 抱歉继续按回车键。 GC 是如何突然知道保存旧 WinProc 的那部分非托管内存突然没有被使用的?它甚至在做什么?我知道我需要一个参考来防止某些东西被 GC,但是 GC 在非托管代码中做了什么?顺便说一句,谢谢。
  • 它对非托管内存做了nothing。这就是问题所在,它不知道本机窗口正在存储对回调的引用。所以没有什么可以阻止它收集委托对象。

标签: c# interop


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2013-07-28
    • 2012-08-07
    • 2012-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    相关资源
    最近更新 更多