与 Linux 的 systemd 不同,并不是所有的应用程序都可以作为 Windows 服务。如果强行以服务形式启动某个不支持的应用程序,会得到“错误 1053: 服务没有及时响应启动服务和控制请求”。

注:如果你是一个开发人员,应当通过编程来满足成为 Windows 服务的条件,而不要使用本文的方法,可参考这篇文章这个例子

可以通过增加额外的代码来支持 Windows 服务。然而,如果我们无法获取软件的源代码,或者没有足够的代码能力,这条道路是行不通的。

微软在 Microsoft Windows Resource Kits 中提供了 instsrv.exe 和 srvany.exe 两个程序,可用来将任意程序作为 Windows 服务。顾名思义,instsrv.exe 的功能与 sc create 命令类似,而 srvany.exe 程序,则是一个响应 Windows 消息的一个“媒介”,它会间接启动我们需要的程序,并且向 Windows 报告服务的情况。

由于有更方便的 sc 命令,无需获得 instsrv.exe 程序,只需要获得 srvany.exe 即可。微软在 Microsoft Windows Resource Kits 中提供的 srvany.exe 文件是 32 位应用程序,如果在 64 位系统中运行 32 位程序,部分特殊文件夹和注册表会被重定向(如 System32 实际上是 SysWow64。但这并不意味着 32 位应用程序永远无法访问正确的资源,这可以通过特殊的 WinAPI 实现)。因此,需要 64 位的 srvany.exe,可从 GitHub 上获取一个开源的 srvany 实现

获取到合适的 srvany.exe 后,可将其放入与应用程序同一文件夹。然后继续剩余的步骤。

1. sc create %servicename% binPath= "%srvany%"
其中,%servicename% 为服务的名称,%srvany% 为 srvany.exe 文件的全路径。

注意:应当为 srvany.exe 创建服务,而不是为目标程序创建服务!
注意:等号和值之间需要一个空格。

2. 注册表进入 HKLM\SYSTEM\CurrentControlSet\Services\%servicename% 项,新建一名为 Parameters 的项,进入,再依次新建三个字符串值,分别名为 Application、AppDirectory、AppParameters。以上三个字符串值的内容分别为程序的全路径、程序的工作目录(一般为程序所在目录)、运行参数。

等价的 .reg 文件如下:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\%servicename%\Parameters]
"Application"="%application%"
"AppDirectory"="%workingdirectory%"
"AppParameters"="%parameters%"

其中,%application%、%workingdirectory%、%parameters%分别为程序的全路径、程序的工作目录(一般为程序所在目录)、运行参数。
注意:在 .reg 文件中要对反斜杠字符做 escape。如果你不明白什么叫 escape,请使用注册表编辑器。

3. 在“服务”中启动服务,或者通过 sc start %servicename% 启动服务。