乐于分享
好东西不私藏

Windows服务(一):安装和卸载

Windows服务(一):安装和卸载

需要实现这么一个功能:windows系统开机时启动某个进程,当发现这个进程被关闭时,要再次启动它。然后就想到了用windows服务刚好合适呀。

创建工程

用Visual Studio创建一个控制台程序就行,然后在main.cpp添加两个空函数,一个函数叫installService,另一个函数叫uninstallService。

安装服务

打开服务管理器 --> 创建服务 --> 修改服务配置 --> 清理资源

// 服务名称
#define SERVICE_NAME L"SimpleService"
#define SERVICE_DISPLAY_NAME L"简单服务示例"

// 安装服务
voidinstallService()
{
// 打开服务控制管理器
    SC_HANDLE hSCManager = OpenSCManager(NULLNULL, SC_MANAGER_CREATE_SERVICE);
if (hSCManager)
    {
// 获取当前路径
wchar_t szPath[MAX_PATH];
GetModuleFileName(NULL, szPath, MAX_PATH);
// 创建服务
        SC_HANDLE hService = CreateService(
            hSCManager,
            SERVICE_NAME,
            SERVICE_DISPLAY_NAME,
            SERVICE_ALL_ACCESS,
            SERVICE_WIN32_OWN_PROCESS,
            SERVICE_AUTO_START,
            SERVICE_ERROR_NORMAL,
            szPath,
NULLNULLNULLNULLNULL);

// 清理打开的资源
if (hService)
        {
//添加描述
            SERVICE_DESCRIPTION sd = { 0 };
            sd.lpDescription = (LPWSTR)L"这仅仅是个测试服务,没啥用。";
if (!ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sd))
            {
wprintf(L"设置服务描述失败,错误: %lu\n"GetLastError());
            }

//设置延迟启动
            SERVICE_DELAYED_AUTO_START_INFO delayedInfo = { TRUE };
if (!ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayedInfo))
            {
wprintf(L"设置服务延迟启动失败,错误: %lu\n"GetLastError());
            }

wprintf(L"服务安装成功!\n");
CloseServiceHandle(hService);
        }
else
        {
wprintf(L"服务安装失败,错误码: %d\n"GetLastError());
        }
CloseServiceHandle(hSCManager);
    }
}

OpenSCManager

打开服务控制管理器

SC_HANDLE OpenSCManagerA(
  [in, optional] LPCSTR lpMachineName,
  [in, optional] LPCSTR lpDatabaseName,
  [in]           DWORD  dwDesiredAccess
)
;

第一个参数lpMachineName: 目标计算机的名称,NULL表示本机
第二个参数lpDatabaseName: 服务管理控制器数据库的名称,NULL表示当前活动的数据库
第三个参数dwDesiredAccess: 指定访问权限。SC_MANAGER_ALL_ACCESS是所有权限,安装服务仅指定SC_MANAGER_CREATE_SERVICE就足够了

CreateService

创建服务并添加到服务管理控制器数据库中。

SC_HANDLE CreateServiceA(
  [in]            SC_HANDLE hSCManager,
  [in]            LPCSTR    lpServiceName,
  [in, optional]  LPCSTR    lpDisplayName,
  [in]            DWORD     dwDesiredAccess,
  [in]            DWORD     dwServiceType,
  [in]            DWORD     dwStartType,
  [in]            DWORD     dwErrorControl,
  [in, optional]  LPCSTR    lpBinaryPathName,
  [in, optional]  LPCSTR    lpLoadOrderGroup,
  [out, optional] LPDWORD   lpdwTagId,
  [in, optional]  LPCSTR    lpDependencies,
  [in, optional]  LPCSTR    lpServiceStartName,
  [in, optional]  LPCSTR    lpPassword
)
;

很多参数哈!一个个来看看
第一个hSCManager:服务管理器
第二个lpServiceName:安装的服务名称
第三个lpDisplayName:用来对外显示服务名称。
第四个dwDesiredAccess:对服务的访问权限,无特殊要求就设置SC_MANAGER_ALL_ACCESS
第五个dwServiceType:服务类型,可以设置文件系统驱动程序服务、驱动程序服务、进程服务、共享进程服务。
第六个dwStartType:服务启动选项,SERVICE_AUTO_START自动启动
第七个dwErrorControl:服务无法启动的处理,SERVICE_ERROR_NORMAL把错误记录到事件日志中。
第八个lpBinaryPathName:服务程序的路径
第九个lpLoadOrderGroup:此服务所属的加载排序组,NULL:不属于任何组
第十个lpdwTagId:返回此服务在加载排序组的唯一标志
第十一个lpDependencies:指定组依赖项,NULL:没有依赖项
第十二个lpServiceStartName:运行服务的账户名称,NULL:本地SYSTEM账户
第十三个lpPassword:运行服务的账户密码,NULL:没有密码。

ChangeServiceConfig2

修复服务配置参数

BOOL ChangeServiceConfig2(
  [in]           SC_HANDLE hService,
  [in]           DWORD     dwInfoLevel,
  [in, optional] LPVOID    lpInfo
)
;

第一个hService: 服务句柄
第二个dwInfoLevel:指定要修改的配置,SERVICE_CONFIG_DESCRIPTION:修改描述信息;SERVICE_CONFIG_DELAYED_AUTO_START_INFO:设置延迟启动。
第三个lpInfo:取决于第二个参数

卸载服务

打开服务管理器 --> 打开已安装的服务 --> 停止服务 --> 删除服务 --> 清理资源

voiduninstallService()
{
    SC_HANDLE hSCManager = OpenSCManager(NULLNULL, SC_MANAGER_ALL_ACCESS);
if (hSCManager)
    {
        SC_HANDLE hService = OpenService(hSCManager, SERVICE_NAME, SERVICE_STOP | DELETE);
if (hService)
        {
            SERVICE_STATUS status;
ControlService(hService, SERVICE_CONTROL_STOP, &status);
DeleteService(hService);
wprintf(L"服务卸载成功!\n");
CloseServiceHandle(hService);
        }
else
        {
wprintf(L"服务卸载失败,错误码: %d\n"GetLastError());
        }
CloseServiceHandle(hSCManager);
    }
}

OpenService

打开服务

SC_HANDLE OpenServiceA(
  [in] SC_HANDLE hSCManager,
  [in] LPCSTR    lpServiceName,
  [in] DWORD     dwDesiredAccess
)
;

第一个hSCManager:服务管理器
第二个lpServiceName:服务名称
第三个dwDesiredAccess:权限 SERVICE_STOP:停止服务;DELETE:删除服务。

ControlService

控制代码发送给服务

BOOL ControlService(
  [in]  SC_HANDLE        hService,
  [in]  DWORD            dwControl,
  [out] LPSERVICE_STATUS lpServiceStatus
)
;

第一个hService:服务句柄
第二个dwControl:控制代码,SERVICE_CONTROL_STOP:通知服务停止
第三个lpServiceStatus:接收服务状态信息
返回值:失败返回0,成功返回非0。

typedefstruct_SERVICE_STATUS {
  DWORD dwServiceType;
  DWORD dwCurrentState;
  DWORD dwControlsAccepted;
  DWORD dwWin32ExitCode;
  DWORD dwServiceSpecificExitCode;
  DWORD dwCheckPoint;
  DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;

第二个dwCurrentState:服务的当前状态。

DeleteService

删除服务

BOOL DeleteService(
  [in] SC_HANDLE hService
)
;

第一个hService: 服务句柄,必须要有DELETE权限。

调用安装和卸载

intwmain(int argc, wchar_t* argv[])
{
// 检查是否是安装/卸载命令
if (argc > 1)
    {
if (_wcsicmp(argv[1], L"install") == 0)
        {
installService();
        }
elseif (_wcsicmp(argv[1], L"uninstall") == 0)
        {
uninstallService();
        }
return0;
    }

//入口函数...

return0;
}

测试安装

打开命令行,切换到进程所在目录,执行SimpleServer.exe install
打开服务面板可以看到服务已经安装上了。


但是还无法启动,因为服务的入口函数没有指定。

测试卸载

在命令行中再执行SimpleServer.exe uninstall
刷新服务面板,可以看到服务又没了。

(关于windows API接口,本篇仅大致说明参数的用途,详细内容还请参阅官方文档。)