互操作:在 C# 中等待外部 Win32 事件






4.37/5 (11投票s)
2005 年 8 月 31 日
2分钟阅读

99955

2753
一篇关于从 .NET (C#) 代码中捕获外部进程事件的文章。
引言
我发现了一些关于如何从 .NET 代码中打开和设置命名的 Win32 事件的示例,但我也需要在我的 .NET 应用程序中捕获 Win32 事件。也就是说,我希望执行与 Win32 (C++) WaitForMultipleObjects()
等效的操作,只是使用 C#。我在 Microsoft 或整个 Internet 上没有找到任何这样的示例。所有关于 WaitHandle
及其衍生物 AutoResetEvent
和 ManualResetEvent
的讨论都只涉及多线程,而不涉及进程间通信。我不太确定这是否可行(或者至少是否*简单*,大多数事情在经过足够的曲折和进入托管 C++ 之后都是*可能*的......);所以我尝试了一下。结果呢?它*非常简单* ...
背景
我们的环境使用一个管理进程来控制哪些其他进程正在运行,以及它们以何种状态运行,例如作为“主要”或“次要”进程,后者是一个热备份,如果第一个副本失败,可以快速切换到主要进程。
有一些命名的事件用于在管理进程和工作进程之间进行通信,例如,一个事件告诉它们从“次要”转换为“主要”,另一个事件告诉它们关闭。这个管理进程使用众所周知的环境变量来将其事件的名称传递给其工作进程。
从历史上看,所有这些进程都是 Win32/MFC 应用程序。现在有些正在变成 .NET 应用程序,但暂时保持相同的通信机制是最方便的。
使用代码
由于这样做的方式非常简单,我将直接展示代码。粗体部分是直接将 Win32 OpenEvent()
调用的结果分配给 AutoResetEvent.Handle
属性
uint unEventPermissions = 2031619;
// Same as EVENT_ALL_ACCESS value
// in the Win32 realm IntPtr hEvent = IntPtr.Zero;
// Get a handle to the Win32 Event.
// The name, "MfcEventSource", is known in advance
hEvent = OpenEvent(unEventPermissions,
false, "MfcEventSource");
if (IntPtr.Zero == hEvent)
{
Console.WriteLine("OpenEvent failed");
return; // Exit
}
// Create an AutoResetEvent object to wrap
// the handle we got from OpenEvent
AutoResetEvent arEvent = new AutoResetEvent(false);
// Set the Handle property to the external event HANDLE
arEvent.Handle = hEvent;
就是这样!现在您可以将此 AutoResetEvent
对象放入 WaitHandle
数组中并使用 WaitAny()
(或直接在 AutoResetEvent
对象上使用 WaitOne()
,或使用 WaitAll()
等)。这是一个例子
WaitHandle[] waitHandles;
waitHandles = new WaitHandle[1];
//Put it in our array for WaitAny()
waitHandles[0] = arEvent;
bool bDone = false;
while ( !bDone )
{
Console.WriteLine("Top of while");
int waitResult = WaitHandle.WaitAny(waitHandles, 2000, false);
//For timeout, just loop and wait again
if (waitResult == WaitHandle.WaitTimeout)
{
Console.WriteLine(" WaitAny timed out.");
}
else if (0 == waitResult)
{
Console.WriteLine("0 == waitResult. Yippee !!!");
// Do Something
}
else if (1 == waitResult)
{
Console.WriteLine("1 == waitResult !!!");
// Do Something Else
}
else
{
Console.WriteLine("Error else");
}
}
如果下载演示项目,您实际上会得到三个解决方案,一个是 MFC/Win32 (C++) 应用程序,它是命名事件的来源,另一个是 .NET (C#) 事件接收器应用程序,它打开并等待外部事件,第三个是 MFC/Win32(非托管 C++)事件接收器应用程序,它是 C# 应用程序的逻辑等效项。请务必首先运行 MfcEventSource
程序,然后启动其他两个程序中的任何一个。
关注点
我想不能指望 Microsoft 提供所有可用类的示例和实践描述,但在这种情况下,仅描述 WaitHandle
对象用于多线程,但没有提及多进程使用似乎具有误导性。另一方面,一旦你看到这些类上可用的东西,并大胆地使用这些特性,它似乎工作得很好。有人知道有什么理由担心吗?谢谢。