C# subscribe to FormClosing



当另一个C#应用程序(Form)即将关闭时,我想在我的C#应用程序中接收一个事件。

我怎样才能做到这一点?这可以用Reflections完成吗?

编辑:详细描述

我意识到我最初的问题不是很具体。我会更详细地描述我的目标。

所以我有3个申请。让我们将它们命名为ContainerPlacerToPlace。我正在C#中开发容器占位符Placer是dll,而集装箱则是WinForm。我无法访问ToPlace的源代码。在Container中,我有一个自定义控件,我将它放在ToPlace的主窗口中,并从Placer调用SetParent。目标是在Contaner应用程序关闭之前恢复ToPlace的父窗口,或者过滤掉发送到ToPlaceontainer退出时破坏ToPlace的主窗口。

我试图覆盖Container中自定义控件的WndProc,但发送给子窗口的消息不是通过父窗口发送的。

我还尝试在Container应用程序上安装消息过滤器,但也没有成功。

在写这个问题之前,我最后一次尝试是SetWindowsHookEx,但在成功安装钩子后,钩子过程永远不会被调用。也许是因为,我在某个地方读到,钩子函数必须在win32 dll中,而不是在托管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;
}
}
}

如果你能以某种方式找到你想要监控的进程(通过窗口标题,或者,在下面的例子中,通过"友好"进程名称),那么很容易监控它的关闭。

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

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,看看是否找到了所需的进程。

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

你提供的信息很少,无法给出具体的答案。。。例如:

  • 如果两个过程都"正在开发中"(即可以更改两者的源代码),那么解决方案可能很容易
    否则会变得复杂,并且可能不可靠

  • 如果两个进程都在同一台机器上,则可以通过挂钩
    实现,否则您将需要更复杂的实现。

  • 如果你只想被告知表单关闭,那么这是可能的
    如果你想在其他流程的上下文中执行某个事情,甚至自己处理该事件,这非常复杂,取决于你想要什么,这可能是不可能的。。。

请提供更多详细信息,以便找到具体答案。

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

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

最新更新