我正在使用NativeWindow
对象来子类化非托管窗口的消息泵,目的是拦截其消息。
代码结构看起来像这样(它的psuedo C#,请原谅小的语法问题):
class AppSubclass : Control {
class SpecialAppWndProc : NativeWindow {
protected override void WndProc(ref Message m) {
switch (m.msg) {
// do stuff
if (SpecialEvent != null) SpecialEvent(x);
}
base.WndProc(ref m);
}
public delegate void SpecialEventHandler(int Xstart);
public event SpecialEventHandler SpecialEvent;
~SpecialAppWndProc() {
DebugTrace("Help! Save me!");
}
}
private SpecialAppWndProc specialAppWndProc = new SpecialAppWndProc();
private void StartMonitoring() {
// do stuff
specialAppWndProc.AssignHandle(hWndUnmanagedWindow);
specialAppWndProc.SpecialEvent += new SpecialAppWndProc.SpecialEventHandler(specialAppWndProc_SpecialEvent);
}
/* ... event handler ... */
public AppSubClass() {
StartMonitoring();
}
}
现在,我认为设置一个事件监听器就足以让垃圾收集器停止运行,如果我的对象因GC而死亡。如果不是,是否有可能追踪为什么?我从来不知道.Net只是因为代码错误而杀死对象(异常和偶尔的静默失败似乎是事情的一般要点)而且我不知道主机应用程序是如何或为什么(我的应用程序是一个COM服务器非托管代码)也有足够的知识来杀死我的对象。
鉴于对象看似随机死亡(我无法确定某一组事件,只是在调用StartMonitoring()后不到一秒钟到几分钟就死掉了。
看起来HandleRef
可能会解决我的困境,但是我不清楚如何在这种情况下使用它,我无法想到如何在我的代码中使用它(除了可能在AppSubclass级别,然后为其分配SpecialAppWndProc对象。
那么,在我准备它死之前,如何防止我的对象死亡?
答案 0 :(得分:2)
您需要存储对象的引用。
该事件以另一个方向工作,保持事件将朝向活动而不是事件源发射。
如果你向GC.Collect和GC.WaitForPendingFinalizers添加一些调用,我很确定你可以很快地引发这个问题。
让我更多地充实我的答案。
事件基本上只是伪装的代表。伪装只是删除了与委托相关的一些功能,因此外部代码无法对底层委托执行任何操作,但从本质上讲,它是一个普通的委托。
那么什么是代表?引用单个方法的委托包含两件事:
当事件由定义它的对象调用时,就像被触发的“Button.Click”事件一样,特定对象(例如Form1的实例)会触发特定方法(例如,bt_Click)。 / p>
因此事件包含一个引用向外,朝向定义方法的对象。该事件对该其他对象没有任何作用,因此其他对象(如上例中的Form1)与此事件无任何关联,包含对该对象的引用。
所以在你的情况下,假设你有这个代码:
AppSubclass app = new AppSubclass(); // this starts monitoring
如果现在让该变量超出范围,则该对象符合收集条件,因为没有任何内容可以引用它。 AppSubclass和SpecialAppWndProc之间内部存在引用并不重要,可以引用两种方式,但如果没有外部代码保存对它的引用,那么这些对象就有资格进行收集。
因此,您需要在某处存储对象的引用,以避免被收集。
要回答你的原始问题,即“C#:什么是破坏我的NativeWindow对象以及为什么?”,答案是垃圾收集器会破坏你的NativeWindow对象,原因是没有root引用它(通过rooted引用,我的意思是存储在静态变量中的引用,其他有根引用的成员变量,或者作为活动方法中的局部变量。)