Open SilverRoe opened 4 years ago
我的总结: 服务里的线程关系: SvcMain 并不是主线程;StartServiceCtrlDispatcher会阻塞主线程直到所有运行的服务都进入 SERVICE_STOPPED 状态; SvcCtrlHandler 控制回调会在主线程里执行;
多服务共享进程实例: 多个服务共享一个进程,必须在CreateService 设置 SERVICE_WIN32_SHARE_PROCESS标志 备注:不同服务可以设置为相同的执行程序,服务启动时会启动多个进程实例;
服务提权: 从服务中启动进程可以解决UAC弹窗的问题。主要需要使用CreateProcessAsUser API
服务相关命令: sc create SvcTest binpath= e:\CodeForFun\ServiceTest.exe sc delete SvcTest sc stop SvcTest sc start SvcTest
调试信息输出: 可以用OutputDebugString 输出调试信息,并用DbgView查看
MSDN上关于windows services的文档很齐全,这里翻译部分方便查阅: 服务程序 一个服务程序包含了一个或多个服务的代码。 SERVICE_WIN32_OWN_PROCESS 类型的服务只包含一个服务的代码; SERVICE_WIN32_SHARE_PROCESS 类型包含多个服务的代码;
服务程序可以在build-in(local), primary 或者 trusted domain 账户下运行。也可以被配置在指定账户下运行
一个服务程序必须包含以下部分:
服务入口点 服务一般被写为console应用。一个console应用的入口点是main函数。服务的main函数接受记录在注册表键里的ImagePath作为参数。 当SCM启动一个服务程序,它将等待服务程序调用 StartServiceCtrlDispatcher 函数;请注意以下这些点:
StartServiceCtrlDispatcher 函数为每一个进程中的服务保存一个 SERVICE_TABLE_ENTRY 结构。每个结构都指定了服务名和对应的入口点(entry point) 如果 StartServiceCtrlDispatcher 成功了,调用的线程会直到所有运行的服务都进入 SERVICE_STOPPED 状态。SCM通过一个命名管道向这个线程发送请求。这个线程作为控制分发者(control dispatcher),将执行以下任务:
服务ServiceMain函数 当一个服务控制程序请求一个新服务运行时,SCM 启动服务并且向control dispatcher 发送一个开始请求.control dispatcher 创建一个新的线程并且执行该服务的 ServiceMain函数。 ServiceMain 函数将执行以下任务:
服务控制回调Control Handler 函数 每个服务都有一个控制回调;当服务进程接收到一个控制请求时,这个回调将被control dispatcher执行。因此,这个函数在control dispatcher的上下文环境中被执行。 服务调用RegisterServiceCtrlHandler 或者 RegisterServiceCtrlHandlerEx 函数注册服务控制回调函数。 当一个服务控制回调被执行,服务只有在控制code造成服务状态改变时才 必须调用 SetServiceStatus 函数来给SCM报告状态。如果控制码没有导致服务状态改变,那么就不需要调用SetServiceStatus。 服务控制程序可以通过 ControlService API 发送控制请求。所有服务都必须接收和处理SERVICE_CONTROL_INTERROGATE 控制码。 如果一个服务接收了SERVICE_CONTROL_STOP 控制码,它必须接收时马上停下来,变成 SERVICE_STOP_PENDDING 或 SERVICE_STOPPED 状态。当SCM发送了这个控制码,将不会再发送其他控制码。 控制回调必须在30s内返回,否则SCM将返回一个错误。如果一个服务需要在控制回调中做一个耗时动作,它应该创建一个线程,并且直接从控制回调中返回。举个例子,当处理停止请求时,如果服务需要花费较长时间,那么创建另外一个线程来停止,控制回调应该只是简单调用SetServiceStatus 返回SERVICE_STOP_PENDING 消息并且返回。 当用户关机时,所有调用SetServiceStatus并且设置SERVICE_ACCEPT_PRESHUTDOWN 控制码的回调将收到SERVICE_CONTROL_PRESHUTDOWN 控制码。这个控制码只应该在特殊场景使用,因为这个服务回调将阻塞系统关机 直到服务停止 或者超时。(这里只需要大概了解下,服务在关机前能收到通知)
其他相关的topics:
一个完整的服务例子