2

メッセージをインターセプトする目的で、オブジェクトを使用してNativeWindow、管理されていないウィンドウのメッセージポンプをサブクラス化します。

コード構造は次のようになります(その疑似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()が呼び出されてから1秒未満から数分で死ぬだけです。

私の悩みを解決するかもしれないように見えHandleRefますが、このコンテキストでそれを使用する方法が不明であり、コードにどのように適合させるかを考えることができません(AppSubclassレベルで宣言してから割り当てる以外は) SpecialAppWndProcオブジェクト。

では、オブジェクトが死ぬ準備ができる前に、オブジェクトが死ぬのを防ぐにはどうすればよいですか?

4

1 に答える 1

2

オブジェクトへの参照を保存する必要があります。

イベントは反対方向に機能し、イベントが発生するオブジェクトを、イベントソースではなく、生きている方向に維持します。

GC.CollectとGC.WaitForPendingFinalizersにいくつかの呼び出しを追加すると、問題をすぐに引き起こすことができると確信しています。

私の答えをもう少し具体化させてください。

イベントは基本的には変装した単なる代理人です。変装は、デリゲートに関連する機能の一部を削除するだけなので、外部コードは、基になるデリゲートで必要なことを実行できませんが、本質的には通常のデリゲートです。

では、デリゲートとは何ですか?単一のメソッドを参照するデリゲートは、次の2つで構成されます。

  1. メソッドリファレンス
  2. オブジェクト参照(ターゲット)

「Button.Click」イベントが発生するなど、イベントを定義するオブジェクトによってイベントが呼び出されると、特定のメソッド(たとえば、bt_Click)が特定のオブジェクト(Form1のインスタンスなど)で発生します。

したがって、イベントには、メソッドが定義されているオブジェクトに向かって、外側への参照が含まれます。イベントは他のオブジェクトに対して何も実行しないため、上記の例のForm1のように、このイベントに関連する他のオブジェクトには、オブジェクトへの参照が含まれていません。

したがって、あなたの場合、あなたがこのコードを持っているとしましょう:

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

ここでその変数をスコープから外すと、そのオブジェクトへの参照を保持するものがないため、そのオブジェクトは収集の対象になります。AppSubclassとSpecialAppWndProcの間に内部的に参照があることは問題ではなく、両方の方法で参照される可能性がありますが、外部コードがそれへの参照を保持していない場合、それらのオブジェクトは収集の対象となります。

したがって、オブジェクトへの参照をどこかに保存して、収集されないようにする必要があります。

「C#:NativeWindowオブジェクトを破棄する理由とその理由」という元の質問に答えるには、NativeWindowオブジェクトを破棄するのはガベージコレクターであり、その理由は、ルート化された参照がないためです。 (ルート参照とは、静的変数、他のルート参照のメンバー変数、またはアクティブメソッドのローカル変数に格納されている参照を意味します。)

于 2009-12-22T23:38:08.010 に答える