在 Windows 服务中创建时找不到命名事件
Cannot find named event when created in Windows Service
我正在用 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?");
因为它是受信任服务器上的内部应用程序,所以我不介意将 'Full Control' 授予 'World' 通常并不明智。
在客户端我有:
EventWaitHandle.TryOpenExisting(EVENT_NAME, EventWaitHandleRights.Modify, out evh)
当我 运行 我的服务处于基于控制台的交互模式时,上面的代码可以完美运行。两端都找到事件,客户端可以设置,服务开始工作。大家都很开心。
但是安装服务时它不起作用。日志记录仍然报告事件是重新创建的,但客户端找不到该事件。因为我认为它与安全相关,所以我添加了 World Full Control Allow 访问规则,但它没有改变任何东西。我以本地管理员身份将服务更改为 运行,即使是我自己的用户帐户,但什么也没有 - 即使日志显示服务正在愉快地轮询,客户端也找不到该事件。如果我将 TryOpenExisting
更改为 OpenExisting
我会得到一个明确的异常:
System.Threading.WaitHandleCannotBeOpenedException: No handle of the given name exists.
我错过了什么?
从WindowsVista开始,服务被隔离,运行在Session 0中(参见Service Changes for Windows Vista). When calling CreateEvent (which EventWaitHandle),事件对象默认在本地命名空间中创建,也称为会话命名空间。由会话 0 中的服务创建且名称在会话命名空间中的事件对象仅在会话 0 中可见。它对交互式用户会话中的应用程序 运行ning 是不可见的。
要通过应用程序代码(运行ning 在交互式用户会话中)可以发现的服务(运行ning 在会话 0 中)创建事件对象,您必须创建它进入全局命名空间。这是通过在事件名称前加上 "Global\" 前缀来完成的,如 CreateEvent.
中所述
跟踪内核对象相关错误的有用工具是 Sysinternal's WinObj。
我正在用 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?");
因为它是受信任服务器上的内部应用程序,所以我不介意将 'Full Control' 授予 'World' 通常并不明智。
在客户端我有:
EventWaitHandle.TryOpenExisting(EVENT_NAME, EventWaitHandleRights.Modify, out evh)
当我 运行 我的服务处于基于控制台的交互模式时,上面的代码可以完美运行。两端都找到事件,客户端可以设置,服务开始工作。大家都很开心。
但是安装服务时它不起作用。日志记录仍然报告事件是重新创建的,但客户端找不到该事件。因为我认为它与安全相关,所以我添加了 World Full Control Allow 访问规则,但它没有改变任何东西。我以本地管理员身份将服务更改为 运行,即使是我自己的用户帐户,但什么也没有 - 即使日志显示服务正在愉快地轮询,客户端也找不到该事件。如果我将 TryOpenExisting
更改为 OpenExisting
我会得到一个明确的异常:
System.Threading.WaitHandleCannotBeOpenedException: No handle of the given name exists.
我错过了什么?
从WindowsVista开始,服务被隔离,运行在Session 0中(参见Service Changes for Windows Vista). When calling CreateEvent (which EventWaitHandle),事件对象默认在本地命名空间中创建,也称为会话命名空间。由会话 0 中的服务创建且名称在会话命名空间中的事件对象仅在会话 0 中可见。它对交互式用户会话中的应用程序 运行ning 是不可见的。
要通过应用程序代码(运行ning 在交互式用户会话中)可以发现的服务(运行ning 在会话 0 中)创建事件对象,您必须创建它进入全局命名空间。这是通过在事件名称前加上 "Global\" 前缀来完成的,如 CreateEvent.
中所述跟踪内核对象相关错误的有用工具是 Sysinternal's WinObj。