首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#订阅FormClosing

C#订阅FormClosing
EN

Stack Overflow用户
提问于 2012-12-11 15:19:25
回答 3查看 624关注 0票数 0

当一个不同的C#应用程序(表单)即将关闭时,我希望在C#应用程序中接收一个事件。

我怎样才能做到这一点?这能用反射来完成吗?

编辑:详细描述

我知道我原来的问题不是很具体。我将尝试更详细地描述我的目标。

所以我有三份申请。让我们将它们命名为ContainerPlacerToPlace。我正在开发ContanerPlacer in C#,Placer是dll,Container是WinForm。我无法访问ToPlace的源代码。在Container中,我有一个自定义控件,将它放在ToPlace的主窗口中,并从Placer调用SetParent。其目标是在关闭ToPlace应用程序之前恢复的父窗口,或者过滤发送到ToPlace主窗口的WM_DESTROY消息(或其他消息)。最后,我们的目标不是在ToPlace退出时破坏的主窗口。

我试图在WndProc容器中重写自定义控件的,但是没有通过父窗口发送到子窗口的消息。

我还试图在容器应用程序上安装一个消息过滤器,但这也没有成功。

在编写这个问题之前,我最后一次尝试的是SetWindowsHookEx,但是在成功安装钩子之后,钩子过程永远不会被调用。也许是因为,我在某个地方读到,钩子函数必须在win32 dll中,而不是在托管dll中。下一次尝试将是使用SetWinEventHook,我了解到这一点,使它更容易从C#工作。

我在SetWindowsHookEx中尝试过的代码如下所示,也许在C#互操作方面更有经验的人会看到一个bug,并能让它正常工作:

代码语言:javascript
复制
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;
        }
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-12-11 15:29:27

不,这不能用反射来完成。

你提供的信息很少能给出具体的答案..。例如:

  • 如果这两个进程都处于“开发中”(即可以为两者更改源代码),那么解决方案可能很容易。 否则,它会变得复杂和潜在的不可靠。
  • 如果两个进程都在同一台机器上,则可以通过挂钩实现。 否则,您将需要一个更加复杂的实现。
  • 如果您只想被告知表单已关闭,那么这是可能的。 如果您想在另一个进程的上下文中执行某件事情,或者甚至自己处理该事件,这是非常复杂的,并且取决于您到底想要什么,这可能是不可能的。

请提供更多的细节,以便有可能得到一个具体的答案。

票数 0
EN

Stack Overflow用户

发布于 2012-12-11 15:45:03

如果您可以以某种方式找到要监视的进程(通过窗口标题,或者,如下面的示例所示,通过“友好”进程名称),则很容易监视其关闭。

下面的示例显示了如何监视“记事本”进程以查看它何时关闭:

代码语言:javascript
复制
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以查看是否找到了所需的进程。

票数 1
EN

Stack Overflow用户

发布于 2012-12-11 15:28:30

我们在这里谈了多少IPC?如果这只是一个简单的通知,也许使用WM_COPYDATA就可以了。下面是这种方法的一个示例:http://www.codeproject.com/Articles/17606/NET-Interprocess-Communication

如果有更多的管道和/或内存映射文件,或者不仅仅是一条简单的“我要关闭”消息,那么使用命名管道和/或内存映射文件也是合适的。命名管道方法的示例如下:http://msdn.microsoft.com/en-us/library/bb546085.aspx

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13822838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档