Windows服务程序基本结构
当SCM(服务管理器)启动服务进程时, 该进程必须立即调用StartServiceCtrlDispatcher函数,该函数接收一个服务入口点列表,每个入口点对应该进程中的一个服务,每个入口点由其所对应的服务名称来标识;StartServiceCtrlDispatcher创建了一个命名管道与SCM进行通信,当管道建立后,等待接收到SCM发送的服务启动命令后,创建一个服务线程来调用服务入口点函数,并且实现该服务的命令循环。StartServiceCtrlDispatcher会一直等待SCM传过来的命令,只有该进程对应的所有服务都停止时,才会返回到main函数所在线程,方便进程退出前做一些清理工作。 如果一些初始化工作不超过30秒,也可以在main函数所在线程执行,例如根据不同的命令行参数执行不同的任务,但每个服务自己的初始化工作最好放在自己的服务入口点函数。
每个服务的入口点函数的第一个动作就是调用RegisterServiceCtrlHandler或者RegisterServiceCtrlHandlerEx函数,该函数接收一个称为服务控制处理的函数指针,并将该函数指针保存起来,服务必须实现该函数以便处理来自SCM的各种命令,服务控制处理函数由StartServiceCtrlDispatcher函数来调用,也就是在主线程中调用的,StartServiceCtrlDispatcher函数继续初始化该服务,包括分配内存,从注册表中读入私有的配置数据。
在服务入口点函数初始化服务的过程中,他必须调用SetServiceStatus来定期的给SCM发送状态信息,以表明该服务的启动过程正在如何运行。先看一些该函数原型
BOOL WINAPI SetServiceStatus(
_In_ SERVICE_STATUS_HANDLE hServiceStatus,
_In_ LPSERVICE_STATUS lpServiceStatus
);
第一个参数为RegisterServiceCtrlHandler或者RegisterServiceCtrlHandlerEx返回的服务状态句柄,第二个参数为服务状态结构指针,该结构如下:
typedef struct _SERVICE_STATUS {
DWORD dwServiceType;
DWORD dwCurrentState;
DWORD dwControlsAccepted;
DWORD dwWin32ExitCode;
DWORD dwServiceSpecificExitCode;
DWORD dwCheckPoint;
DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;
- dwServiceType参数表示服务类型,它有如下取值:
| 值 | 含义 |
|---|---|
| SERVICE_FILE_SYSTEM_DRIVER | Windows文件系统驱动程序,系统保留 |
| SERVICE_KERNEL_DRIVER | Windows设备驱动程序,系统保留 |
| SERVICE_WIN32_OWN_PROCESS | Windows服务运行于自己的进程,独占进程资源 |
| SERVICE_WIN32_SHARE_PROCESS | Windows服务与其他服务共享一个进程,共享进程资源,优点可以节省在单独进程中运行每个一个服务的系统资源,但缺点是一旦一个服务发生错误导致服务程序退出时,其他服务也会停止工作,因此现在也不提倡使用 |
| SERVICE_INTERACTIVE_PROCESS | 必须与SERVICE_WIN32_OWN_PROCESS或者SERVICE_WIN32_SHARE_PROCESS共同使用表示可以与桌面进行交互,已经不推荐,可以通过第三方程序实现桌面交互再与服务通信的方式来实现 |
- dwCurrentState表示当前的服务状态,它有如下取值:
| 值 | 含义 |
|---|---|
| SERVICE_CONTINUE_PENDING | 服务处于从暂停状态恢复的过程中 |
| SERVICE_PAUSE_PENDING | 服务正在暂停过程中,但还有没完全进入暂停状态 |
| SERVICE_PAUSED | 服务已经暂停 |
| SERVICE_RUNNING | 服务正在运行 |
| SERVICE_START_PENDING | 服务在启动过程中,但还没有准备好对请求进行响应 |
| SERVICE_STOPPED | 服务已经停止 |
- dwControlsAccepted指定服务会接收处理那些控制码,它有如下取值
| 值 | 含义 |
|---|---|
| SERVICE_ACCEPT_NETBINDCHANGE | 该服务是一个网络组件,并且能够在服务在服务不重启的情况下,改变其所网络接收的绑定,接收SERVICE_CONTROL_NETBINDADD、SERVICE_CONTROL_NETBINDREMOVE、SERVICE_CONTROL_NETBINDENABLE、SERVICE_CONTROL_NETBINDDISABLE 的通知 |
| SERVICE_ACCEPT_PARAMCHANGE | 服务在不重启的情况下能够重新读取其配置参数,接收SERVICE_CONTROL_PARAMCHANGE 通知 |
| SERVICE_ACCEPT_PAUSE_CONTINUE | 服务支持暂停和重启,服务能够接收到SERVICE_CONTROL_PAUSE 和SERVICE_CONTROL_CONTINUE的通知 |
| SERVICE_ACCEPT_PRESHUTDOWN | 系统在关闭前,能够收到系统的SERVICE_CONTROL_PRESHUTDOWN 通知,用来处理一些关闭前的清理,xp之前不支持此控制码 |
| SERVICE_ACCEPT_SHUTDOWN | 能够接收系统退出时的SERVICE_CONTROL_SHUTDOWN 的通知,以便处理一些回收 |
| SERVICE_ACCEPT_STOP | 能够接收SERVICE_CONTROL_STOP 的通知来处理一些回收任务 |
- dwWin32ExitCode逻辑服务正常退出时的退出吗,一般为0(NoError)
- dwServiceSpecificExitCode只有在dwWin32ExitCode设置为ERROR_SERVICE_SPECIFIC_ERROR才有效,可用于服务启动或停止时错误码
- dwCheckPoint,在服务启动,停止,暂停,继续,过程中不断自增来标识一个计数
- dwWaitHint,标识两次调用SetServiceStatus所消耗的时间,这两次调用要么是dwCheckPoint的递增值,要么是dwCurrentState的更改,这个时间超时了,服务管理器可以认为是一种服务发生了错误。
服务控制处理函数(在RegisterServiceCtrlHandler或者RegisterServiceCtrlHandlerEx注册的函数,),用来处理接收来自于SCM的通知,这里以RegisterServiceCtrlHandlerEx注册的函数为例,原型如下:
DWORD WINAPI HandlerEx(
_In_ DWORD dwControl,
_In_ DWORD dwEventType,
_In_ LPVOID lpEventData,
_In_ LPVOID lpContext
);
RegisterServiceCtrlHandler注册函数没有lpContext函数,其中dwControl表示接收到的来自于SCM的通知,除了一些常用通知,还能接收哪些通知与上面SERVICE_STATUS中的dwControlsAccepted有关。其中0-127由系统占用,用户还可以通过RegisterDeviceNotification 注册自己的控制码通知。
下面是一个windows服务程序的基本结构代码,基本满足大多数服务。
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#define MyServiceName TEXT("MyService")
bool g_bPausedFlag = false;
HANDLE g_hSvcStopEvent = NULL;
SERVICE_STATUS g_MyServiceStatus;
SERVICE_STATUS_HANDLE g_hMyServiceStatusHandle;
void __stdcall MyServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
DWORD __stdcall MyServiceHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext);
void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
DWORD MyServiceInitialization(DWORD dwArgc, LPTSTR *lpszArgv);
DWORD MyServiceWorker(DWORD dwArgc, LPTSTR *lpszArgv);
int _tmain(int argc, TCHAR* argv[])
{
SERVICE_TABLE_ENTRY dispatchTable[] = {
{MyServiceName, (LPSERVICE_MAIN_FUNCTION)MyServiceMain},
{NULL, NULL} };
if (!StartServiceCtrlDispatcher(dispatchTable))
{
// cleaning worker
}
return 0;
}
void __stdcall MyServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
g_hSvcStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
g_hMyServiceStatusHandle = RegisterServiceCtrlHandlerEx(MyServiceName, (LPHANDLER_FUNCTION_EX)MyServiceHandlerEx, NULL);
if (g_hMyServiceStatusHandle == NULL)
return;
g_MyServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_MyServiceStatus.dwServiceSpecificExitCode = 0;
ReportServiceStatus(SERVICE_START_PENDING, 0, 0);
DWORD dwRet = MyServiceInitialization(dwArgc, lpszArgv);
if (dwRet != NO_ERROR)
ReportServiceStatus(SERVICE_STOPPED, dwRet, 0);
ReportServiceStatus(SERVICE_RUNNING, 0, 0);
MyServiceWorker(dwArgc, lpszArgv);
while (true)
{
WaitForSingleObject(g_hSvcStopEvent, INFINITE);
ReportServiceStatus(SERVICE_STOPPED, 0, 0);
return;
}
}
DWORD __stdcall MyServiceHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
switch (dwControl)
{
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
ReportServiceStatus(SERVICE_STOP_PENDING, 0, 0);
SetEvent(g_hSvcStopEvent);
break;
case SERVICE_CONTROL_PAUSE:
ReportServiceStatus(SERVICE_PAUSE_PENDING, 0, 0);
g_bPausedFlag = true;
break;
case SERVICE_CONTROL_CONTINUE:
ReportServiceStatus(SERVICE_CONTINUE_PENDING, 0, 0);
g_bPausedFlag = false;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
return 0;
}
// 执行一些初始化过程
DWORD MyServiceInitialization(DWORD dwArgc, LPTSTR *lpszArgv)
{
return NO_ERROR;
}
// 服务工作执行函数
DWORD MyServiceWorker(DWORD dwArgc, LPTSTR *lpszArgv)
{
return 0;
}
// 向服务控制管理器报告状态信息
void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
g_MyServiceStatus.dwCurrentState = dwCurrentState;
g_MyServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
g_MyServiceStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
g_MyServiceStatus.dwControlsAccepted = 0;
else
g_MyServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
if ((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED))
g_MyServiceStatus.dwCheckPoint = 0;
else
g_MyServiceStatus.dwCheckPoint = dwCheckPoint++;
SetServiceStatus(g_hMyServiceStatusHandle, &g_MyServiceStatus);
}
只需要将上述程序中的MyService替换成自己的服务名称,在MyServiceInitialization函数中完成服务启动时需要的一些初始化工作,如果没有也可以不写此函数,在MyServiceWorker函数中实现自己的服务的主要工作程序。
windows服务配置程序
要修改服务的配置有两种方法,一种就是直接修改注册表,此种方法不提倡,通过SCM管理器提供的接口来配置Windows服务(本质是由SCM来修改注册表),Services.msc与命令行工具sc,都是系统提供的服务配置管理程序。因为SCM是基于RPC的程序,因此也可以配置远程电脑的服务。
Windows服务管理器提供了如下常用的接口函数供我们调用,来配置服务程序:
| 函数 | 主要功能 |
|---|---|
| ChangeServiceConfig | 修改服务的配置参数 |
| ChangeServiceConfig2 | 修改一些可选的服务配置参数,例如失败后操作 |
| ControlService | 发送控制码到服务 |
| ControlServiceEx | 发送控制码到服务 |
| CreateService | 创建一个windows服务对象,并将其添加的服务管理器中 |
| DeleteService | 从服务管理器中删除一个服务 |
| EnumDependentServices | 枚举依赖于某个服务的所有服务 |
| EnumServicesStatusEx | 枚举某个服务管理器中的所有服务的状态信息 |
| GetServiceDisplayName | 通过服务名称,获取显示名称 |
| GetServiceKeyName | 通过服务的显示名称,获取服务名称 |
| OpenSCManager | 打开服务管理器,获取服务管理器句柄 |
| OpenService | 打开一个服务,获取该服务句柄 |
| QueryServiceConfig | 获取服务的配置参数 |
| QueryServiceConfig2 | 获取可选的服务配置参数 |
| QueryServiceStatusEx | 获取当前服务状态信息 |
| StartService | 启动一个服务 |
这些函数具体使用方式和参数请查询MSDN,这里不再详述。
接下来我们实现一个自己的服务配置管理工具,直接上代码:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <Shlwapi.h>
#include <winsvc.h>
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "Advapi32.lib")
// 显示提供的所有命令
void DisplayUsage(int argc, TCHAR* argv[]);
void IntallService(int argc, TCHAR* argv[]);
void StartService(int argc, TCHAR* argv[]);
void StopService(int argc, TCHAR* argv[]);
BOOL StopDependentServices(SC_HANDLE schSCManager, SC_HANDLE schService);
void RemoveService(int argc, TCHAR* argv[]);
int _tmain(int argc, TCHAR* argv[])
{
if (argc < 2)
{
DisplayUsage(argc, argv);
return 0;
}
TCHAR szCommand[32] = { 0 };
StringCchCopy(szCommand, 32, argv[1]);
if (lstrcmpi(szCommand, _T("create")))
{
IntallService(argc, argv);
}
else if (lstrcmpi(szCommand, _T("start")))
{
StartService(argc, argv);
}
else if (lstrcmpi(szCommand, _T("stop")))
{
StopService(argc, argv);
}
else if (lstrcmpi(szCommand, _T("delete")))
{
RemoveService(argc, argv);
}
return 0;
}
void DisplayUsage(int argc, TCHAR* argv[])
{
}
void IntallService(int argc, TCHAR* argv[])
{
if (argc != 4)
{
_tprintf(_T("sc create [service name] [binPath= ]"));
return;
}
TCHAR szServiceName[256] = { 0 };
TCHAR szBinPath[MAX_PATH] = { 0 };
StringCchCopy(szServiceName, 256, argv[3]);
StringCchCopy(szBinPath, MAX_PATH, argv[4]);
if (!PathFileExists(szBinPath))
{
_tprintf(_T("文件路径不存在"));
return;
}
SC_HANDLE schSCManager;
SC_HANDLE schService;
schSCManager = OpenSCManager(
NULL, // 如果是本机传入NULL,如果是远程写远端机器名
NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == schSCManager)
{
printf("OpenSCManager failed (%d)\n", GetLastError());
return;
}
schService = CreateService(
schSCManager, // SCM句柄
szServiceName, // 服务名称
szServiceName, // 显示名称
SERVICE_ALL_ACCESS, // 服务权限
SERVICE_WIN32_OWN_PROCESS, // 服务类型
SERVICE_AUTO_START, // 服务启动类型
SERVICE_ERROR_NORMAL, // 服务错误控制类型
szBinPath, // 服务exe所在路径
NULL, // 服务所需要加载的组
NULL, // tag标识符
NULL, // 依赖的服务
NULL, // 服务账户,NULL表示为localSystem
NULL); // 账户密码
if (schService == NULL)
{
_tprintf(_T("CreateService failed (%d)\n"), GetLastError());
CloseServiceHandle(schSCManager);
return;
}
else
{
printf("Service installed successfully\n");
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
void StartService(int argc, TCHAR* argv[])
{
if (argc != 3)
{
_tprintf(_T(" sc start [service name]"));
return;
}
TCHAR szServiceName[256] = { 0 };
StringCchCopy(szServiceName, 256, argv[3]);
SC_HANDLE schSCManager;
SC_HANDLE schService;
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == schSCManager)
{
_tprintf(_T("OpenSCManager failed (%d)\n"), GetLastError());
return;
}
schService = OpenService(
schSCManager,
szServiceName,
SERVICE_ALL_ACCESS);
if (schService == NULL)
{
_tprintf(_T("OpenService failed (%d)\n"), GetLastError());
CloseServiceHandle(schSCManager);
return;
}
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded;
// 查看服务是否已经启动
if (!QueryServiceStatusEx(
schService, // 服务句柄
SC_STATUS_PROCESS_INFO, // 要获取的信息级别,不同的级别返回的信息详细程度不同
(LPBYTE)&ssStatus, // 服务进程状态结构体
sizeof(SERVICE_STATUS_PROCESS), // 服务进程状态结构体大小
&dwBytesNeeded)) // 还需要的额外地址空间
{
_tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
// 如果服务已经启动,直接返回
if (ssStatus.dwCurrentState != SERVICE_STOPPED &&
ssStatus.dwCurrentState != SERVICE_STOP_PENDING)
{
_tprintf(_T("Cannot start the service because it is already running\n"));
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
// 保存原始的CheckPoint
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
// 如果服务正在关闭,则等待关闭后再启动
while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
dwWaitTime = ssStatus.dwWaitHint / 10;
if (dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
// 检查服务是否关闭
if (!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssStatus,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded))
{
_tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
if (ssStatus.dwCheckPoint > dwOldCheckPoint)
{
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
{
_tprintf(_T("Timeout waiting for service to stop\n"));
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
}
}
// 尝试启动服务
if (!StartService(
schService, // 服务句柄
0, // 参数个数
NULL)) // 参数
{
_tprintf(_T("StartService failed (%d)\n"), GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else
{
_tprintf(_T("Service start pending...\n"));
}
// 检查服务状态直到到服务启动为止
if (!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssStatus,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded))
{
_tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
{
dwWaitTime = ssStatus.dwWaitHint / 10;
if (dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
if (!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssStatus,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded))
{
_tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
break;
}
if (ssStatus.dwCheckPoint > dwOldCheckPoint)
{
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
{
break;
}
}
}
// 检查服务是否启动
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
{
_tprintf(_T("Service started successfully.\n"));
}
else
{
_tprintf(_T("Service not started. \n"));
_tprintf(_T(" Current State: %d\n"), ssStatus.dwCurrentState);
_tprintf(_T(" Exit Code: %d\n"), ssStatus.dwWin32ExitCode);
_tprintf(_T(" Check Point: %d\n"), ssStatus.dwCheckPoint);
_tprintf(_T(" Wait Hint: %d\n"), ssStatus.dwWaitHint);
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
void StopService(int argc, TCHAR* argv[])
{
if (argc != 3)
{
_tprintf(_T(" sc stop [service name]"));
return;
}
TCHAR szServiceName[256] = { 0 };
StringCchCopy(szServiceName, 256, argv[3]);
SC_HANDLE schSCManager;
SC_HANDLE schService;
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS);
if (NULL == schSCManager)
{
printf("OpenSCManager failed (%d)\n", GetLastError());
return;
}
schService = OpenService(
schSCManager,
szServiceName,
SERVICE_STOP |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS);
if (schService == NULL)
{
_tprintf(_T("OpenService failed (%d)\n"), GetLastError());
CloseServiceHandle(schSCManager);
return;
}
SERVICE_STATUS_PROCESS ssp;
DWORD dwBytesNeeded;
// 检查服务是否已经在关闭状态
if (!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded))
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
goto stop_cleanup;
}
if (ssp.dwCurrentState == SERVICE_STOPPED)
{
_tprintf(_T("Service is already stopped.\n"));
goto stop_cleanup;
}
DWORD dwStartTime = GetTickCount();
DWORD dwTimeout = 30000;
DWORD dwWaitTime;
// 如果服务正在关闭,等待其完全关闭
while (ssp.dwCurrentState == SERVICE_STOP_PENDING)
{
_tprintf(_T("Service stop pending...\n"));
dwWaitTime = ssp.dwWaitHint / 10;
if (dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
if (!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded))
{
_tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
goto stop_cleanup;
}
if (ssp.dwCurrentState == SERVICE_STOPPED)
{
_tprintf(_T("Service stopped successfully.\n"));
goto stop_cleanup;
}
if (GetTickCount() - dwStartTime > dwTimeout)
{
_tprintf(_T("Service stop timed out.\n"));
goto stop_cleanup;
}
}
// 如果服务正在运行过程中,需要先关闭依赖该服务的服务
StopDependentServices(schSCManager, schService);
// 发送一个服务退出通知给服务程序
if (!ControlService(
schService,
SERVICE_CONTROL_STOP,
(LPSERVICE_STATUS)&ssp))
{
_tprintf(_T("ControlService failed (%d)\n"), GetLastError());
goto stop_cleanup;
}
// 等待服务关闭
while (ssp.dwCurrentState != SERVICE_STOPPED)
{
Sleep(ssp.dwWaitHint);
if (!QueryServiceStatusEx(
schService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded))
{
_tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
goto stop_cleanup;
}
if (ssp.dwCurrentState == SERVICE_STOPPED)
break;
if (GetTickCount() - dwStartTime > dwTimeout)
{
_tprintf(_T("Wait timed out\n"));
goto stop_cleanup;
}
}
_tprintf(_T("Service stopped successfully\n"));
stop_cleanup:
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
BOOL StopDependentServices(SC_HANDLE schSCManager, SC_HANDLE schService)
{
DWORD i;
DWORD dwBytesNeeded;
DWORD dwCount;
LPENUM_SERVICE_STATUS lpDependencies = NULL;
ENUM_SERVICE_STATUS ess;
SC_HANDLE hDepService;
SERVICE_STATUS_PROCESS ssp;
DWORD dwStartTime = GetTickCount();
DWORD dwTimeout = 30000;
if (EnumDependentServices(schService, SERVICE_ACTIVE,
lpDependencies, 0, &dwBytesNeeded, &dwCount))
{
return TRUE;
}
else
{
if (GetLastError() != ERROR_MORE_DATA)
return FALSE;
// Allocate a buffer for the dependencies.
lpDependencies = (LPENUM_SERVICE_STATUS)HeapAlloc(
GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded);
if (!lpDependencies)
return FALSE;
__try {
// Enumerate the dependencies.
if (!EnumDependentServices(schService, SERVICE_ACTIVE,
lpDependencies, dwBytesNeeded, &dwBytesNeeded,
&dwCount))
return FALSE;
for (i = 0; i < dwCount; i++)
{
ess = *(lpDependencies + i);
// Open the service.
hDepService = OpenService(schSCManager,
ess.lpServiceName,
SERVICE_STOP | SERVICE_QUERY_STATUS);
if (!hDepService)
return FALSE;
__try {
// Send a stop code.
if (!ControlService(hDepService,
SERVICE_CONTROL_STOP,
(LPSERVICE_STATUS)&ssp))
return FALSE;
// Wait for the service to stop.
while (ssp.dwCurrentState != SERVICE_STOPPED)
{
Sleep(ssp.dwWaitHint);
if (!QueryServiceStatusEx(
hDepService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded))
return FALSE;
if (ssp.dwCurrentState == SERVICE_STOPPED)
break;
if (GetTickCount() - dwStartTime > dwTimeout)
return FALSE;
}
}
__finally
{
CloseServiceHandle(hDepService);
}
}
}
__finally
{
HeapFree(GetProcessHeap(), 0, lpDependencies);
}
}
return TRUE;
}
void RemoveService(int argc, TCHAR* argv[])
{
if (argc != 3)
{
_tprintf(_T("sc delete [service name]"));
return;
}
TCHAR szServiceName[256] = { 0 };
StringCchCopy(szServiceName, 256, argv[3]);
SC_HANDLE schSCManager;
SC_HANDLE schService;
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == schSCManager)
{
_tprintf(_T("OpenSCManager failed (%d)\n"), GetLastError());
return;
}
// 打开服务获取服务句柄
schService = OpenService(schSCManager, szServiceName, DELETE);
if (schService == NULL)
{
_tprintf(_T("OpenService failed (%d)\n"), GetLastError());
CloseServiceHandle(schSCManager);
return;
}
// 删除服务
if (!DeleteService(schService))
{
_tprintf(_T("DeleteService failed (%d)\n"), GetLastError());
}
else
_tprintf(_T("Service deleted successfully\n"));
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
本文详细介绍了Windows服务程序的基本结构,包括StartServiceCtrlDispatcher的作用、服务入口点函数的实现、SetServiceStatus的状态更新,以及服务控制处理函数。此外,还探讨了Windows服务的配置方法,如通过SCM接口进行服务配置,并提供了一段基本的服务程序代码框架。
8650

被折叠的 条评论
为什么被折叠?



