Delphi编写的Windows服务如何区分自动启动与管理器手动启动
Windows 服务启动来源判断方案(Delphi XE5 环境)
最优替代方案:启动参数传递法
该方案比写入注册表的逻辑更简洁,无残留状态,不会出现标记未清理导致的判断错误问题,实现逻辑如下:
- 系统自动启动服务时,不会传入任何自定义参数,你的管理程序手动启动服务时,主动传入约定好的唯一标记参数
- 服务启动时读取入参即可直接判断启动来源
代码实现示例
管理端启动服务代码
uses WinSvc; procedure LaunchMyService; const SERVICE_NAME = '你的服务注册表名称'; CUSTOM_LAUNCH_FLAG = 'ManualLaunchByManager'; var hSCM, hSvc: SC_HANDLE; pFlag: PChar; begin hSCM := OpenSCManager(nil, nil, SC_MANAGER_CONNECT); if hSCM = 0 then RaiseLastOSError; try hSvc := OpenService(hSCM, PChar(SERVICE_NAME), SERVICE_START); if hSvc = 0 then RaiseLastOSError; try pFlag := PChar(CUSTOM_LAUNCH_FLAG); // 传递自定义标记参数 if not StartService(hSvc, 1, @pFlag) then RaiseLastOSError; finally CloseServiceHandle(hSvc); end; finally CloseServiceHandle(hSCM); end; end;
服务端判断逻辑
在TService组件的OnStart事件中添加如下判断:
uses SysUtils; procedure TMainService.ServiceStart(Sender: TService; var Started: Boolean); const CUSTOM_LAUNCH_FLAG = 'ManualLaunchByManager'; var i: Integer; isManualLaunch: Boolean; begin isManualLaunch := False; // 遍历所有启动参数匹配标记 for i := 0 to ParamCount - 1 do begin if ParamStr(i) = CUSTOM_LAUNCH_FLAG then begin isManualLaunch := True; Break; end; end; if isManualLaunch then begin // 执行管理程序手动启动对应的业务逻辑 end else begin // 执行系统开机自动启动对应的业务逻辑 end; Started := True; end;
备选方案:父进程判断法
如果不想修改启动参数,也可以通过判断服务进程的父进程来区分:
- 系统自动启动的服务,父进程固定为系统的
services.exe进程 - 管理程序手动启动的服务,父进程为你的管理程序进程
该方案的缺点是如果管理程序启动服务后立即退出,服务的父进程会被系统回收为0,会出现判断失效的情况,稳定性低于参数传递法。
内容的提问来源于stack exchange,提问作者kbriggs
相关产品推荐
相关产品推荐

