通过 INF AddService 安装的理想 Win32 服务,与设备交互的行为与 驱动程序 与 设备交互的方式类似。 当设备存在时,驱动程序会加载,而当设备不存在时则卸载。与设备交互的 Win32 服务也应遵循相同的 启动 和 停止 模式。
服务应该仅在设备接口存在并已启用时启动,并在设备接口不再启用时停止。 此设计模式可确保一个可靠的服务,以最大程度地减少不需要和未定义的行为。 我们将逐步讲解应如何设计服务以遵循此模式。
服务安装
若要安装服务,请使用 INF AddService 指令。 这样,就可以创建和启动服务。
添加使服务按需启动的设置。 这可以通过设置 StartType=0x3 来实现,这会启动服务触发器。
本部分中的最后一步是使用 AddTrigger 指令在设备接口到达时启动服务(有关 AddTrigger 的更多详细信息,请参阅 AddService)。 下面是如何使用 AddTrigger 的示例:
[UserSvc_Install]
ServiceType = 0x10 ; SERVICE_WIN32_OWN_PROCESS
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 0 ; SERVICE_ERROR_IGNORE
ServiceBinary = %13%\oemsvc.exe
AddTrigger = UserSvc_AddTrigger
[UserSvc_AddTrigger]
TriggerType = 1 ; SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL
Action = 1 ; SERVICE_TRIGGER_ACTION_SERVICE_START
SubType = %GUID_DEVINTERFACE_OSRFX2% ; Interface class GUID
DataItem = 2, "USB\VID_0547&PID_1002" ; SERVICE_TRIGGER_DATA_TYPE_STRING
请注意,DataItem 中指定的 HardwareId 是可选的,通常仅在使用泛型类接口将触发器范围限定为更具体的设备时才需要。
服务运行时
从运行时的角度来看,服务的第一步应该是注册设备接口通知。 有关如何实现此操作的建议指南,可以在此页面找到:注册设备接口到达通知和设备删除。
具体而言,应将 CM_Register_Notification 与 CM_NOTIFY_FILTERY_TYPE_DEVICEINTERFACE 标志一起使用,以完成设备接口通知的相应注册。
注释
当服务启动时,你不能依赖将接收设备接口通知的事实,因为到达通知可能已经传递,尤其是在设备接口到达是服务启动的原因时。 相反,必须获取设备接口列表,以检查是否存在已有接口。
注册设备接口通知后,将收到有关启用的新设备接口或正在禁用的现有设备接口的通知。 可以从通知回调中发现设备接口路径。 若要查询现有设备接口列表,以检查服务启动之前存在的设备接口并注册通知,可以通过 API(如 CM_Get_Device_Interface_List)获取设备接口列表。
注释
在注册通知和检索系统上已有的设备接口列表之间,设备接口有可能到达。 在这种情况下,设备接口将同时列在通知回调和设备接口列表中。
如果要使用 I/O API 与设备接口进行交互,找到所需的设备接口后,请通过 CreateFile 打开句柄。
下一步是注册每个句柄的次级通知,以获取设备状态变化的通知,例如尝试查询或移除设备或者设备断开连接。 可以通过使用CM_Register_Notification和CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE标志来实现这一点。 按照注册设备接口到达和设备删除通知的指南,可以确保在设备离开时,能够相应地释放句柄。
应跟踪设备接口到达和删除,以便删除服务可能要与之交互的最后一个设备接口意味着可以停止服务。 删除最后一个接口后,停止服务( 可在此页面找到详细信息)。 可以通过执行以下步骤来实现此目的:
将SERVICE_STOP_PENDING状态发布到 SCM 以指示服务正在关闭
反初始化/清理掉服务使用的所有内容
将SERVICE_STOP状态发布到 SCM 以完成停止作
如果服务已停止,请确保检查并浏览设备接口的所有现有打开句柄(可能没有),并清理它们。
设备接口可以在设备安装、设备启用/禁用、设备重新枚举、系统重启或未列出的其他方案中返回。 当设备接口重新连接时,将根据其触发注册来启动该服务。
此流将确保服务在设备接口的到达时启动,并在最后一个设备接口不再存在时停止。
代码示例和相关链接
GitHub 上有一个示例,指导服务如何利用此事件流。 示例可在此处找到: Win32 服务示例。
此外,还可以在 AddService 页面上找到有关 AddTrigger 的有用文档。