Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# winproc上的SetWindowsLong导致旧winproc被垃圾收集_C#_Interop - Fatal编程技术网

C# winproc上的SetWindowsLong导致旧winproc被垃圾收集

C# winproc上的SetWindowsLong导致旧winproc被垃圾收集,c#,interop,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

我有个问题快把我逼疯了。我花了一周的时间追踪这个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);
  }

}
User.CallWindowProc(old_window_proc,hWnd,   (uint)message.Msg,message.WParam,message.LParam);
强制垃圾收集:

   GC.Collect();
   GC.WaitForPendingFinalizers();
然后称之为:

class MyClass
{
  private User.WindowProc proc;

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

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

}
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()之后,它会保持不变,不会出错


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

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

垃圾回收器无法看到非托管对象持有的引用。您需要通过自己存储委托对象来解决这个问题,以便GC能够看到它。并在窗口处于活动状态时保持引用状态。当你看到WM_DESTROY消息时,将其设置回null并恢复窗口过程。这对我来说没有意义。请容忍我在这里…旧的WinProc是不受管理的。GC为什么要碰它?对不起,继续按回车键。GC如何突然知道保存旧WinProc的非托管内存部分突然没有被使用?它在摸它干什么?我知道我需要一个引用来防止某些东西被GC'd,但是GC在非托管代码中做什么呢?顺便说一下,谢谢。它对非托管内存没有任何作用。这就是问题所在,它不知道本机窗口正在存储对回调的引用。因此,没有什么可以阻止它收集委托对象。