服务的概念:
Microsoft Windows 服务(过去称为 NT 服务)允许用户创建可在其自身的 Windows 会话中长时间运行的可执行应用程序。 这些服务可在计算机启动时自动启动,可以暂停和重启,并且不显示任何用户界面。
注:所以一个正常运行的服务程序是不应该执行完就退出的。应该在所有进程中的所有服务均终止时才返回退出。
目标:
编写一个服务,能够正常添加到Windows服务列表并能随系统启动,可正常手动启停。暂时不需要通过服务实现任何实际的功能。
组成部分:
使用C语言通过WindowsAPI编写一个可用的服务至少要包括以下几部分内容:
1. 服务程序的入口点
2. 服务程序的主体ServiceMain函数
3. 服务程序的控制处理功能函数
以上三者缺一不可,否则将无法正常启动。
具体步骤:
1.创建服务
该部分可选,如果忽略创建服务部分可使用手动方式添加服务。
2.编写入口点
第一个重要组成部分,必不可少。
SERVICE_TABLE_ENTRY service_table[2]; //为可以在调用过程中运行的服务指定ServiceMain函数 service_table[0].lpServiceName = L"TestService"; //此服务在进程中运行的名称 service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; //指向ServiceMain函数的指针 service_table[1].lpServiceName = NULL; //表中最后一个条目的成员必须具有NULL值才能指定表的末尾 service_table[1].lpServiceProc = NULL; result = StartServiceCtrlDispatcherW(service_table); //将服务进程的主线程连接到服务控制管理器,该服务控制管理器使该线程成为调用过程的服务控制调度程序线程 if (result == 0) { printf("StartServiceCtrlDispatcherW error: %d\n", GetLastError()); break; }
3.编写ServiceMain函数
第二个重要组成部分,必不可少。
VOID WINAPI ServiceMain(DWORD argc, LPWSTR* argv) { service_status_handle = RegisterServiceCtrlHandlerW(L"TestService", (LPHANDLER_FUNCTION)ServiceControlHandler); //参数2为函数指针,该指针指向的函数定义了如何处理服务控制管理器发来的控制请求 //填充SERVICE_STATUS结构体,该结构体为全局变量 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwCurrentState = SERVICE_RUNNING; //如果有需要初始化的内容,此处可以先填SERVICE_START_PENDING,待初始化完成后将值改为SERVICE_RUNNING service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; service_status.dwWin32ExitCode = 0; service_status.dwServiceSpecificExitCode = 0; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 0; SetServiceStatus(service_status_handle, &service_status); //该函数用以更新服务控制管理器的的状态信息 return;
4.编写控制处理程序功能(即前面代码参数2对应的函数)
第三个重要组成部分,必不可少。该函数用于接收服务控制管理器(SCM)发来的指令,然后根据指令让服务做出相应的状态更新。如下面代码,若不增加对停止服务指令的状态更新,则服务无法正常停止。
VOID WINAPI ServiceControlHandler(DWORD parameter) //该函数的参数即服务控制管理器传入的控制参数 { service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwCurrentState = SERVICE_RUNNING; service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; service_status.dwWin32ExitCode = 0; service_status.dwServiceSpecificExitCode = 0; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 0; if (parameter == SERVICE_CONTROL_STOP) //根据参数内容更新对应的服务状态 { service_status.dwCurrentState = SERVICE_STOPPED; } SetServiceStatus(service_status_handle, &service_status); return; }
包含以上内容就完成了作为一个最基本的Windows服务。
以下为该示例完整代码:
#include <stdio.h> #include <Windows.h> SERVICE_STATUS service_status; SERVICE_STATUS_HANDLE service_status_handle; BOOL InstallService() { BOOL result = FALSE; SC_HANDLE SCM_handle = NULL; SC_HANDLE service_handle = NULL; DWORD return_value = 0; TCHAR Path[MAX_PATH]; HANDLE file_handle = NULL; char error[64]; DWORD bytes_written = 0; DWORD last_error = 0; SecureZeroMemory(error, sizeof(error)); do { return_value = GetModuleFileNameW(NULL, Path, MAX_PATH); if (return_value == 0) { printf("GetModuleFileName error: %d\n", GetLastError()); break; } SCM_handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (SCM_handle == NULL) { printf("OpenSCManagerW error: %d\n", GetLastError()); break; } service_handle = OpenServiceW(SCM_handle, L"TestService", SC_MANAGER_ALL_ACCESS); if (service_handle != NULL) { printf("Test Service Created\n"); } else { service_handle = CreateServiceW( SCM_handle, L"TestService", L"TestService", SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, Path, NULL, NULL, NULL, NULL, NULL ); if (service_handle == NULL) { printf("CreateServiceW error: %d\n", GetLastError()); break; } } result = TRUE; } while (0); if (SCM_handle != NULL) { CloseServiceHandle(SCM_handle); } if (service_handle != NULL) { CloseServiceHandle(service_handle); } return result; } VOID WINAPI ServiceControlHandler(DWORD parameter) { service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwCurrentState = SERVICE_RUNNING; service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; service_status.dwWin32ExitCode = 0; service_status.dwServiceSpecificExitCode = 0; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 0; if (parameter == SERVICE_CONTROL_STOP) { service_status.dwCurrentState = SERVICE_STOPPED; } SetServiceStatus(service_status_handle, &service_status); return; } VOID WINAPI ServiceMain(DWORD argc, LPWSTR* argv) { service_status_handle = RegisterServiceCtrlHandlerW(L"TestService", (LPHANDLER_FUNCTION)ServiceControlHandler); service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwCurrentState = SERVICE_RUNNING; service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; service_status.dwWin32ExitCode = 0; service_status.dwServiceSpecificExitCode = 0; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 0; SetServiceStatus(service_status_handle, &service_status); return; } int main(int argc, char* argv[]) { BOOL result = 0; HANDLE file_handle = NULL; DWORD last_error = 0; do { result = InstallService(); if (result == 0) { printf("InstallService faild.\n"); break; } SERVICE_TABLE_ENTRY service_table[2]; service_table[0].lpServiceName = L"TestService"; service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; service_table[1].lpServiceName = NULL; service_table[1].lpServiceProc = NULL; result = StartServiceCtrlDispatcherW(service_table); if (result == 0) { printf("StartServiceCtrlDispatcherW error: %d\n", GetLastError()); break; } } while (0); return 0; }