代码之家  ›  专栏  ›  技术社区  ›  Tom Corelis

C:什么在破坏我的NativeWindow对象?为什么?

  •  2
  • Tom Corelis  · 技术社区  · 15 年前

    我正在使用 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 回复  |  直到 15 年前
        1
  •  2
  •   Lasse V. Karlsen    15 年前

    您需要存储对对象的引用。

    事件朝另一个方向工作,使事件将向活动的对象(而不是事件源)开火。

    如果您向gc.collect和gc.waitForPendingFinalizers添加一些调用,我确信您可以很快地引发问题。

    让我再充实一下我的答案。

    一个事件基本上只是一个伪装的代表。伪装只是删除了一些与委托相关联的功能,这样外部代码就不能对底层委托执行它想要的任何操作,但本质上,它是一个普通的委托。

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

    1. 方法参考
    2. 对象引用(目标)

    当定义该事件的对象调用该事件时,例如“button.click”正在激发的事件,特定方法(例如bt_click)将在特定对象(例如form1的实例)上激发。

    因此,事件包含一个引用 向外地 ,指向定义方法的对象。事件不会对另一个对象做任何操作,因此其他对象(如上面的示例中的Form1)不会以任何方式与此事件相关,包含对该对象的引用。

    因此,在您的案例中,假设您有以下代码:

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

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

    所以您需要将对象的引用存储在某个地方,以避免被收集。

    为了回答你最初的问题,“C”:什么在破坏我的NativeWindow对象,为什么?,答案是垃圾收集器破坏了NativeWindow对象,原因是没有对它的根引用(根引用是指存储在静态变量中的引用、其他根引用的成员变量或活动方法中的局部变量)。

    推荐文章