0

別の C# アプリケーション (フォーム) が閉じようとしているときに、C# アプリケーションでイベントを受信したいと考えています。

どうすればこれを達成できますか? これはリフレクションで実行できますか?

編集:詳細な説明

私の元の質問はあまり具体的ではないことを認識しています。私の目標をより詳細に説明しようとします。

というわけで、応募は3件。ContainerPlacerToPlaceと名付けましょう。ContanerPlacerを C# で開発しています。Placerは dll ですが、Containerは WinForm です。ToPlaceのソース コードにはアクセスできません。Containerには、 Placerから呼び出された SetParent を使用してToPlaceのメイン ウィンドウに配置するカスタム コントロールがあります。目標は、 Contanerアプリを閉じる前にToPlaceの親ウィンドウを復元するか、ToPlace に送信された WM_DESTROY メッセージ (またはその他のメッセージ) を除外することです。ToPlaceメイン ウィンドウ。最終的には、 Containerの終了時にToPlaceのメイン ウィンドウを破棄しないことが目標です。

Containerでカスタム コントロールの WndProc をオーバーライドしようとしましたが、子ウィンドウへのメッセージが親ウィンドウ経由で送信されません。

また、コンテナアプリにメッセージ フィルタをインストールしようとしましたが、これも成功しませんでした。

この質問を書く前の最後の試みは SetWindowsHookEx でしたが、フックを正常にインストールした後、フック プロシージャが呼び出されることはありません。おそらく、どこかで読んだところによると、フック関数はマネージ dll ではなく win32 dll にある必要があるためです。次の試みは、SetWinEventHook を使用することです。これについて読んだところ、C# から作業する方が簡単であることがわかりました。

私が SetWindowsHookEx で試したコードは以下のとおりです。おそらく、C# 相互運用の経験が豊富な人なら、バグを見つけて機能させることができます。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace AppMonitor
{
    public class AppMonitor
    {
        private const int WH_GETMESSAGE = 3;
        private const int HC_ACTION = 0;
        private const int PM_NOREMOVE = 0x0000;
        private const int PM_REMOVE = 0x0001;
        private const int WM_QUIT = 0x0012;

        [DllImport("user32.dll")]
        private static extern int SetWindowsHookEx(int idHook, GetMsgProcDelegate lpfn, int hMod, int dwThreadId);

        [DllImport("user32.dll")]
        private static extern bool UnhookWindowsHookEx(int hhk);

        [DllImport("user32.dll")]
        private unsafe static extern int CallNextHookEx(int hhk, int nCode, int wParam, void* lParam);

        [DllImport("user32.dll")]
        private static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);

        [DllImport("kernel32.dll")]
        private static extern int GetLastError();

        private struct Msg {
            public int        hwnd;
            public int        message;
            public int      wParam;
            public int      lParam;
            public int       time;
            public int       pt;
        };

        [DllImport("kernel32.dll")]
        public static extern int LoadLibrary(string dllToLoad);

        public AppMonitor()
        { 
        }

        private int hHook;
        private int hMod;

        public event EventHandler AppClosing;

        private unsafe delegate int GetMsgProcDelegate(int code, int wParam, void* lParam);
        private unsafe GetMsgProcDelegate m_dlgt;

        private unsafe int GetMsgProc(int code, int wParam, void* lParam)
        {
            if (code != HC_ACTION || wParam != PM_REMOVE)
               return CallNextHookEx(this.hHook, code, wParam, lParam);

            Msg* msg = (Msg*)lParam;

            //if (msg.message == WM_QUIT)
            //    OnAppClosing(new EventArgs());

            return CallNextHookEx(this.hHook, code, wParam, lParam);
        }

        protected virtual void OnAppClosing(EventArgs e)
        {
            EventHandler h = AppClosing;
            if (h != null)
            {
                h(this, e);
            }
        }

        public unsafe bool setHook(int hWnd)
        {
            hMod = LoadLibrary("AppMonitor.dll"); //this dll
            int procId = 0;

            int threadId = GetWindowThreadProcessId(hWnd, out procId);
            if (threadId == 0)
                throw new System.Exception("Invalid thread Id");

            m_dlgt = GetMsgProc;
            this.hHook = SetWindowsHookEx(WH_GETMESSAGE, m_dlgt, hMod, threadId);

            if (this.hHook == 0)
                throw new System.Exception("Hook not successfull! Error code: " + GetLastError());

            return this.hHook != 0;
        }

        public bool unSetHook()
        {
            bool result = false;
            if (hHook != 0)
                result = UnhookWindowsHookEx(hHook);
            return result;
        }
    }
}
4

3 に答える 3

1

監視したいプロセスを何らかの方法で(ウィンドウタイトルまたは以下の例のように「わかりやすい」プロセス名で)見つけることができれば、プロセスが終了するかどうかを簡単に監視できます。

次の例は、「メモ帳」プロセスを監視して、いつ閉じるかを確認する方法を示しています。

using System;
using System.Diagnostics;

// To test this program:
// (1) Start Notepad.
// (2) Run this program.
// (3) Close Notepad.
// (4) This program should print "Notepad exited".

namespace Demo
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            foreach (var process in Process.GetProcessesByName("notepad"))
            {
                Console.WriteLine("Found a Notepad process to attach to.");
                process.EnableRaisingEvents = true;
                process.Exited += process_Exited;
            }

            Console.WriteLine("Press ENTER to quit.");
            Console.ReadLine();
        }

        private static void process_Exited(object sender, EventArgs e)
        {
            Console.WriteLine("Notepad exited.");
        }
   }
}

必要に応じて、Process.GetProcesses()を使用してコンピューター上のすべてのプロセスを列挙し、各プロセスについてProcess.MainWindowTitleをチェックして、必要なプロセスが見つかったかどうかを確認します。

于 2012-12-11T15:45:03.473 に答える