C#:什么在摧毁我的NativeWindow对象?为什么?

时间:2009-12-22 23:33:03

标签: c# garbage-collection subclassing nativewindow

我正在使用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对象。

那么,在我准备它死之前,如何防止我的对象死亡?

1 个答案:

答案 0 :(得分:2)

您需要存储对象的引用。

该事件以另一个方向工作,保持事件将朝向活动而不是事件源发射。

如果你向GC.Collect和GC.WaitForPendingFinalizers添加一些调用,我很确定你可以很快地引发这个问题。

让我更多地充实我的答案。

事件基本上只是伪装的代表。伪装只是删除了与委托相关的一些功能,因此外部代码无法对底层委托执行任何操作,但从本质上讲,它是一个普通的委托。

那么什么是代表?引用单个方法的委托包含两件事:

  1. 方法参考
  2. 对象引用(目标)
  3. 当事件由定义它的对象调用时,就像被触发的“Button.Click”事件一样,特定对象(例如Form1的实例)会触发特定方法(例如,bt_Click)。 / p>

    因此事件包含一个引用向外,朝向定义方法的对象。该事件对该其他对象没有任何作用,因此其他对象(如上例中的Form1)与此事件无任何关联,包含对该对象的引用。

    所以在你的情况下,假设你有这个代码:

    AppSubclass app = new AppSubclass(); // this starts monitoring
    

    如果现在让该变量超出范围,则该对象符合收集条件,因为没有任何内容可以引用它。 AppSubclass和SpecialAppWndProc之间内部存在引用并不重要,可以引用两种方式,但如果没有外部代码保存对它的引用,那么这些对象就有资格进行收集。

    因此,您需要在某处存储对象的引用,以避免被收集。

    要回答你的原始问题,即“C#:什么是破坏我的NativeWindow对象以及为什么?”,答案是垃圾收集器会破坏你的NativeWindow对象,原因是没有root引用它(通过rooted引用,我的意思是存储在静态变量中的引用,其他有根引用的成员变量,或者作为活动方法中的局部变量。)