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服务编程之服务程序相关推荐

  1. windows服务编程

    文章目录 前言 方案一:服务程序 方案二:后台程序 对比 windows服务编程 windows服务控制 附录 - 完整代码 前言 在linux中,如果需要一个程序在后台持续提供服务,我们一般会使用守 ...

  2. windows服务编程 注册InstallUtil.exe

    dos命令下输入; C:\Windows\Microsoft.Net\Framework\v2.0.to727>InstallUtil.exe E:\Test\WindowsServiec1.e ...

  3. Windows服务描述及其原理

    Windows服务描述及其原理 Windows下的服务程序都遵循服务控制管理器(SCM)的接口标准,它们会在登录系统时自动运行,甚至在没有用户登录系统的情况下也会正常执行,类似与UNIX系统中的守护进 ...

  4. windows服务守护进程bat脚本、windows窗体守护进程bat脚本

    线上运行的windows服务和窗体服务程序经常挂掉,只能从windows日志中找到报了底层错误,问题无法定位,目前的办法是在服务器上运行守护进程 window服务守护进程 @echo off titl ...

  5. 编程打开Windows服务控制管理器

    假设要自己编程来加载Windows下后缀为.sys的驱动程序:首先要使用 OpenSCManager 函数打开Windows服务控制管理器: 下面先来调用此函数看一下会不会打开成功:代码如下: #in ...

  6. 《Windows核心编程》---Windows服务

    Windows服务(Services),是一些运行在WindowsNT.Windows2000和Windows XP等操作系统下用户环境以外的程序.它不同于一般的可执行程序,不需要系统登录便可以运行, ...

  7. 十年一遇的奇葩故障--Windows网络编程接口故障:telnet显示无法加载或初始化请求的服务提供程序...

    现象:某同事的笔记本win7x64系统,当初故障是无法使用小乌龟连接到svn服务器,但又可以正常上网,并且svn服务器端是正常的. 后来我进一步测试,发觉该电脑也不能连接到远程windows. net ...

  8. C# Net6开发Linux守护进程(后台服务程序,类似Windows服务)案例

    C# Net6开发Linux守护进程(后台服务程序,类似Windows服务)案例 背景 C# net6开发Linux守护进程要点 背景 在使用net6开发Linux程序时,除了AspNet Core项 ...

  9. python开发服务程序_Python 编写Windows服务程序:将Python作为Windows服务启动 | 学步园...

    Python程序作为Windows服务启动,需要安装pywin32包.下载路径: #-*- coding:utf-8 -*- import win32serviceutil import win32s ...

最新文章

  1. 打算把我的视频工具整合一下
  2. java练气期(2)----java高级(File类与IO流)
  3. java遇见的问题分析
  4. Java jar 修改(springfox-swagger-ui-2.9.2.jar 修改去掉顶部的绿色topbar,汉化)
  5. Druid的Segment Balance及其代价计算函数分析
  6. 比特币蒸发 1 万亿;中兴入局无人驾驶;特斯拉 Model 3 在华降价 | 极客头条
  7. OSG三维渲染引擎编程指南(详读)
  8. 反射(一)动态加载类
  9. DsoFramer-辛酸泪史
  10. 蚂蚁区块链第1课 蚂蚁10大区块链解决方案及应用场景
  11. 算法学习之投票算法以及对应leetcode题目
  12. 卷积神经网络 CNN 学习
  13. vue引入图片的方式
  14. 拷机测试需要多久_【温馨提示】亚马逊卖家警惕!没有UL测试报告产品将会被下架...
  15. mysql索引linke和等于_MySQL索引介绍和实战
  16. 主流mes厂商_国内主流MES厂商排名报告
  17. c语言遍历json数组,如何使用c动态获取所有json元素?
  18. 珠宝erp是否能带回珠宝行业的“黄金时代”?
  19. vue微信分享给朋友,朋友圈自定义网页链接url改变了
  20. react方法返回html_#react# 在页面中显示html代码块

热门文章

  1. C. Gas Pipeline(1207C)
  2. Ie6 Ie7 常见 兼容问题解决方案
  3. C++中的HRESULT的声明定义
  4. 数字历史地理教室教育装备设备配套清单
  5. 使用VS2010编写C++
  6. oracle datafile offline,alter database datafile offline drop 与 alter ...
  7. 记录cacl()函数中使用scss变量不生效的问题
  8. 为什么定位不了HTML,css 锚点定位不了
  9. 四季度策略报告曝光基金高位“生存法则”!
  10. Mysql中外连接,内连接,左连接,右连接的区别