Nie*_*jes 4 .net c# winapi synchronization inter-process-communicat
我正在用 C# 开发一个 Windows 服务来集中管理一些应用程序连接。它通常是一个休眠服务,它在被外部可执行文件唤醒时执行一些操作。为此,我使用了命名事件,特别是 .NET EventWaitHandle. 我的代码在服务端归结为:
EventWaitHandleSecurity sec = new EventWaitHandleSecurity();
sec.AddAccessRule(new EventWaitHandleAccessRule(
new SecurityIdentifier(WellKnownSidType.WorldSid, null),
EventWaitHandleRights.FullControl,
AccessControlType.Allow));
evh = new EventWaitHandle(false, EventResetMode.AutoReset, EVENT_NAME,
out created, sec);
Log(created ? "Event created" : "Event already existed?");
Run Code Online (Sandbox Code Playgroud)
由于它是受信任服务器上的内部应用程序,因此我不介意将“完全控制”授予“世界”一般不明智。
在客户端,我有:
EventWaitHandle.TryOpenExisting(EVENT_NAME, EventWaitHandleRights.Modify, out evh)
Run Code Online (Sandbox Code Playgroud)
当我在基于控制台的交互模式下运行我的服务时,上面的代码可以完美运行。两端都找到事件,客户端可以设置,服务开始工作。大家都很开心。
但是在安装服务时它不起作用。日志记录仍然报告该事件是重新创建的,但客户端找不到该事件。因为我认为它与安全相关,所以我添加了 World Full Control Allow 访问规则,但它没有改变任何东西。我将服务更改为以本地管理员身份运行,即使以我自己的用户帐户身份运行,但什么也没有 - 即使日志显示该服务正在愉快地对其进行轮询,客户端也找不到该事件。如果我更改TryOpenExisting为OpenExisting我得到一个明确的异常:
System.Threading.WaitHandleCannotBeOpenedException: No handle of the given name exists.
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
从 Windows Vista 开始,服务被隔离并在会话 0 中运行(请参阅Windows Vista 的服务更改)。在调用CreateEvent(EventWaitHandle所做的)时,默认情况下在本地命名空间中创建事件对象,也称为会话命名空间。由会话 0 中的服务创建且名称在会话命名空间中的事件对象仅在会话 0 中可见。它对于在交互式用户会话中运行的应用程序是不可见的。
要通过可由应用程序代码(在交互式用户会话中运行)发现的服务(在会话 0 中运行)创建事件对象,您必须将其创建到全局命名空间中。这是通过在事件名称前加上"Global\" 来完成的,如CreateEvent下所述。
Sysinternal 的 WinObj是跟踪内核对象相关错误的有用工具。