Windows服务编程之服务程序
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表示为localSystemNULL); // 账户密码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;// 保存原始的CheckPointdwStartTickCount = 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服务编程之服务程序相关推荐
- windows服务编程
文章目录 前言 方案一:服务程序 方案二:后台程序 对比 windows服务编程 windows服务控制 附录 - 完整代码 前言 在linux中,如果需要一个程序在后台持续提供服务,我们一般会使用守 ...
- windows服务编程 注册InstallUtil.exe
dos命令下输入; C:\Windows\Microsoft.Net\Framework\v2.0.to727>InstallUtil.exe E:\Test\WindowsServiec1.e ...
- Windows服务描述及其原理
Windows服务描述及其原理 Windows下的服务程序都遵循服务控制管理器(SCM)的接口标准,它们会在登录系统时自动运行,甚至在没有用户登录系统的情况下也会正常执行,类似与UNIX系统中的守护进 ...
- windows服务守护进程bat脚本、windows窗体守护进程bat脚本
线上运行的windows服务和窗体服务程序经常挂掉,只能从windows日志中找到报了底层错误,问题无法定位,目前的办法是在服务器上运行守护进程 window服务守护进程 @echo off titl ...
- 编程打开Windows服务控制管理器
假设要自己编程来加载Windows下后缀为.sys的驱动程序:首先要使用 OpenSCManager 函数打开Windows服务控制管理器: 下面先来调用此函数看一下会不会打开成功:代码如下: #in ...
- 《Windows核心编程》---Windows服务
Windows服务(Services),是一些运行在WindowsNT.Windows2000和Windows XP等操作系统下用户环境以外的程序.它不同于一般的可执行程序,不需要系统登录便可以运行, ...
- 十年一遇的奇葩故障--Windows网络编程接口故障:telnet显示无法加载或初始化请求的服务提供程序...
现象:某同事的笔记本win7x64系统,当初故障是无法使用小乌龟连接到svn服务器,但又可以正常上网,并且svn服务器端是正常的. 后来我进一步测试,发觉该电脑也不能连接到远程windows. net ...
- C# Net6开发Linux守护进程(后台服务程序,类似Windows服务)案例
C# Net6开发Linux守护进程(后台服务程序,类似Windows服务)案例 背景 C# net6开发Linux守护进程要点 背景 在使用net6开发Linux程序时,除了AspNet Core项 ...
- python开发服务程序_Python 编写Windows服务程序:将Python作为Windows服务启动 | 学步园...
Python程序作为Windows服务启动,需要安装pywin32包.下载路径: #-*- coding:utf-8 -*- import win32serviceutil import win32s ...
最新文章
- 打算把我的视频工具整合一下
- java练气期(2)----java高级(File类与IO流)
- java遇见的问题分析
- Java jar 修改(springfox-swagger-ui-2.9.2.jar 修改去掉顶部的绿色topbar,汉化)
- Druid的Segment Balance及其代价计算函数分析
- 比特币蒸发 1 万亿;中兴入局无人驾驶;特斯拉 Model 3 在华降价 | 极客头条
- OSG三维渲染引擎编程指南(详读)
- 反射(一)动态加载类
- DsoFramer-辛酸泪史
- 蚂蚁区块链第1课 蚂蚁10大区块链解决方案及应用场景
- 算法学习之投票算法以及对应leetcode题目
- 卷积神经网络 CNN 学习
- vue引入图片的方式
- 拷机测试需要多久_【温馨提示】亚马逊卖家警惕!没有UL测试报告产品将会被下架...
- mysql索引linke和等于_MySQL索引介绍和实战
- 主流mes厂商_国内主流MES厂商排名报告
- c语言遍历json数组,如何使用c动态获取所有json元素?
- 珠宝erp是否能带回珠宝行业的“黄金时代”?
- vue微信分享给朋友,朋友圈自定义网页链接url改变了
- react方法返回html_#react# 在页面中显示html代码块
热门文章
- C. Gas Pipeline(1207C)
- Ie6 Ie7 常见 兼容问题解决方案
- C++中的HRESULT的声明定义
- 数字历史地理教室教育装备设备配套清单
- 使用VS2010编写C++
- oracle datafile offline,alter database datafile offline drop 与 alter ...
- 记录cacl()函数中使用scss变量不生效的问题
- 为什么定位不了HTML,css 锚点定位不了
- 四季度策略报告曝光基金高位“生存法则”!
- Mysql中外连接,内连接,左连接,右连接的区别