我们进行Windows编程的时候,经常涉及到Windows服务编程,针对Windows服务我们该怎么编程呢,
我们先来实现一个Windows服务并实现之,请见注释代码分析。
/* 头文件 */ #include <windows.h> /* 全局变量 */ SERVICE_STATUS SplSrvServiceStatus; SERVICE_STATUS_HANDLE SplSrvServiceStatusHandle; /* 函数声明 */ VOID SvcDebugOut(LPSTR String, DWORD Status); VOID WINAPI SplSrvServiceCtrlHandler (DWORD opcode); VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv); DWORD SplSrvServiceInitialization (DWORD argc, LPTSTR *argv, DWORD *specificError); /************************************* * VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv) * 功能 服务启动函数 * * 参数 未使用 **************************************/ VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv) { DWORD status; DWORD specificError; // 填充SERVICE_STATUS 结构 SplSrvServiceStatus.dwServiceType = SERVICE_WIN32; SplSrvServiceStatus.dwCurrentState = SERVICE_START_PENDING; // 服务在运行 SplSrvServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; SplSrvServiceStatus.dwWin32ExitCode = 0; SplSrvServiceStatus.dwServiceSpecificExitCode = 0; SplSrvServiceStatus.dwCheckPoint = 0; SplSrvServiceStatus.dwWaitHint = 0; // 注册服务控制请求处理例程 SplSrvServiceStatusHandle = RegisterServiceCtrlHandler( "Sample_Srv", // 服务名,在创建服务时使用了 // SERVICE_WIN32_OWN_PROCESS,因此本参数被忽略。 SplSrvServiceCtrlHandler); // 控制请求处理例程,函数名 if (SplSrvServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) { SvcDebugOut(" [SPLSRV_SERVICE] RegisterServiceCtrlHandler " "failed %d\n", GetLastError()); return; } // 初始化工作,本示例未使用,函数为空 status = SplSrvServiceInitialization(argc,argv, &specificError); // 初始化出错,用户自行修改 if (status != NO_ERROR) { SplSrvServiceStatus.dwCurrentState = SERVICE_STOPPED; SplSrvServiceStatus.dwCheckPoint = 0; SplSrvServiceStatus.dwWaitHint = 0; SplSrvServiceStatus.dwWin32ExitCode = status; SplSrvServiceStatus.dwServiceSpecificExitCode = specificError; SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus); return; } // 初始化完成,设置运行状态 SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING; SplSrvServiceStatus.dwCheckPoint = 0; SplSrvServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus)) { status = GetLastError(); SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld\n",status); } // 用户自行修改,用于完成服务的工作 SvcDebugOut(" [SPLSRV_SERVICE] Returning the Main Thread \n",0); return; } /************************************* * DWORD SplSrvServiceInitialization(DWORD argc, * LPTSTR *argv, * DWORD *specificError) * 功能 初始化,这里未进行任何工作,留待读者修改 * * 参数 **************************************/ DWORD SplSrvServiceInitialization(DWORD argc, LPTSTR *argv, DWORD *specificError) { return(0); } /************************************* * VOID WINAPI SplSrvServiceCtrlHandler (DWORD Opcode) * 功能 服务控制请求的处理函数,与ControlService函数配合。 * * 参数 服务控制码 **************************************/ VOID WINAPI SplSrvServiceCtrlHandler (DWORD Opcode) { DWORD status; switch(Opcode) { case SERVICE_CONTROL_PAUSE: // 完成相关功能 SplSrvServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: // 完成相关功能 SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: // 完成相关功能 SplSrvServiceStatus.dwWin32ExitCode = 0; SplSrvServiceStatus.dwCurrentState = SERVICE_STOPPED; SplSrvServiceStatus.dwCheckPoint = 0; SplSrvServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus)) { status = GetLastError(); SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld\n", status); } SvcDebugOut(" [SPLSRV_SERVICE] Leaving SplSrvService \n",0); return; case SERVICE_CONTROL_INTERROGATE: // 收到此请求后发出声响,演示服务控制请求的处理过程,读者可自行修改 MessageBeep(MB_OK); break; default: SvcDebugOut(" [SPLSRV_SERVICE] Unrecognized opcode %ld\n", Opcode); } // 当前状态 if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus)) { status = GetLastError(); SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld\n", status); } return; } /************************************* * void main( ) * 功能 程序入口函数,注册服务启动函数等。 * * 参数 服务控制码 **************************************/ void main( ) { // 设置SERVICE_TABLE_ENTRY 数据结构,以NULL 结构结束, // 作为StartServiceCtrlDispatcher 函数的参数。 SERVICE_TABLE_ENTRY DispatchTable[] = { { "Sample_Srv", (LPSERVICE_MAIN_FUNCTION) SplSrvServiceStart }, { NULL, NULL } }; if (!StartServiceCtrlDispatcher( DispatchTable)) { SvcDebugOut(" [SPLSRV_SERVICE] StartServiceCtrlDispatcher (%d)\n", GetLastError()); } } /************************************* * VOID SvcDebugOut(LPSTR String, DWORD Status) * 功能 显示信息给调试器。 * * 参数 LPSTR String 消息字符串 * DWORD Status 状态 **************************************/ VOID SvcDebugOut(LPSTR String, DWORD Status) { CHAR Buffer[1024]; if (strlen(String) < 1000) { wsprintf(Buffer, String, Status); OutputDebugString(Buffer); } }
然后我们实现了服务以后,需要进行安装,删除服务
具体实现代码如下,请见代码分析
**************************************/ /* 头文件 */ #include <windows.h> #include <tchar.h> #include <stdio.h> /* 全局变量 */ SC_HANDLE schService; SC_HANDLE schSCManager; LPTSTR szServiceName = TEXT("Sample_Srv"); /************************************* * BOOL CreateSampleService(LPTSTR szPath, LPSTR szServiceName) * 功能 创建服务 * * 参数 * SC_HANDLE schSCManager,SCM句柄 * LPTSTR szPath, 服务程序的路径 * LPSTR szServiceName, 服务名 **************************************/ BOOL CreateSampleService( SC_HANDLE schSCManager, LPTSTR szPath, LPSTR szServiceName) { // 创建服务 schService = CreateService( schSCManager, // SCM 句柄 szServiceName, // 服务名 "Service sample", // 显示的服务名 SERVICE_ALL_ACCESS, // 存取权限 SERVICE_WIN32_OWN_PROCESS, // 服务类别 SERVICE_DEMAND_START, // 启动类别 SERVICE_ERROR_NORMAL, // 错误控制类别 szPath, // 服务的可执行文件路径 NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL); // no password if (schService == NULL) { printf("CreateService failed (%d)\n", GetLastError()); return FALSE; } else { printf("CreateService succeeded\n"); CloseServiceHandle(schService); return TRUE; } } /************************************* * BOOL DeleteSampleService(LPTSTR szNameOfService) * 功能 删除服务 * * 参数 LPTSTR szNameOfService 服务的名字 **************************************/ BOOL DeleteSampleService(LPTSTR szNameOfService) { schService = OpenService( schSCManager, // SCM 句柄 szNameOfService, // 服务名 DELETE); // 可删除 if (schService == NULL) { printf("OpenService failed (%d)\n", GetLastError()); return FALSE; } // 删除服务 if (! DeleteService(schService) ) { printf("DeleteService failed (%d)\n", GetLastError()); return FALSE; } else printf("DeleteService succeeded\n"); // 关闭句柄 CloseServiceHandle(schService); return TRUE; } /************************************* * void main( int argc, TCHAR *argv[] ) * 功能 演示 * * 参数 未使用 **************************************/ void main( int argc, TCHAR *argv[] ) { TCHAR szBinFilePath[MAX_PATH]; PTCHAR pTemp; DWORD dwStopError; // 构造服务可执行程序的路径 GetModuleFileName(NULL,szBinFilePath,MAX_PATH); pTemp = szBinFilePath+lstrlen(szBinFilePath); while(*--pTemp!='\\'); lstrcpy(pTemp,TEXT("\\SplSrv.exe")); // 打开 SCM schSCManager = OpenSCManager( NULL, // local machine NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access rights if (NULL == schSCManager) printf("OpenSCManager failed (%d)\n", GetLastError()); // 创建服务 CreateSampleService(schSCManager, szBinFilePath, szServiceName); // 启动服务 StartSampleService(schSCManager,szServiceName); // 发送请求控制 ControlSampleService(SERVICE_CONTROL_INTERROGATE); ControlSampleService(SERVICE_CONTROL_CONTINUE); // 停止服务 dwStopError = StopService( schSCManager, szServiceName, TRUE, 1000); if(ERROR_SUCCESS == dwStopError) { printf("Service Stoped\n"); } else { printf("Service stoped error (%u)\n",dwStopError); } // 删除服务 DeleteSampleService(szServiceName); CloseServiceHandle(schSCManager); }
然后我们如何控制服务呢,我们来实现启动、停止服务,向服务发送请求。
/* 头文件 */ #include <windows.h> #include <tchar.h> #include <stdio.h> /* 全局变量 */ extern SC_HANDLE schService; // 在init.c中定义,下同 extern SC_HANDLE schSCManager; extern LPTSTR szServiceName; /************************************* * BOOL StartSampleService(SC_HANDLE schSCManager,LPTSTR szServiceName) * 功能 启动服务 * * 参数 SC_HANDLE schSCManager SCM 句柄 * LPTSTR szServiceName 服务名 **************************************/ BOOL StartSampleService(SC_HANDLE schSCManager,LPTSTR szServiceName) { SC_HANDLE schService; SERVICE_STATUS_PROCESS ssStatus; DWORD dwOldCheckPoint; DWORD dwStartTickCount; DWORD dwWaitTime; DWORD dwBytesNeeded; // 打开服务 schService = OpenService( schSCManager, // SCM database szServiceName, // service name SERVICE_ALL_ACCESS); if (schService == NULL) { return 0; } // 启动服务 if (!StartService( schService, // handle to service 0, // number of arguments NULL) ) // no arguments { printf("Service start error (%u).\n",GetLastError()); return 0; } else { printf("Service start pending.\n"); } // 验证状态 if (!QueryServiceStatusEx( schService, // handle to service SC_STATUS_PROCESS_INFO, // info level (LPBYTE)&ssStatus, // address of structure sizeof(SERVICE_STATUS_PROCESS), // size of structure &dwBytesNeeded ) ) // if buffer too small { return 0; } // tick count & checkpoint. dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; // 查询状态,确定 PENDING 状态结束 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, // handle to service SC_STATUS_PROCESS_INFO, // info level (LPBYTE)&ssStatus, // address of structure sizeof(SERVICE_STATUS_PROCESS), // size of structure &dwBytesNeeded ) ) // if buffer too small break; if ( ssStatus.dwCheckPoint > dwOldCheckPoint ) { // 进程创建中 dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint) { // WaitHint 时间到 break; } } } // 关闭句柄 CloseServiceHandle(schService); // 判断是否创建成功(状态由PENDING变为RUNNING) if (ssStatus.dwCurrentState == SERVICE_RUNNING) { printf("StartService SUCCESS.\n"); return 1; } else { printf("\nService not started. \n"); printf(" Current State: %d\n", ssStatus.dwCurrentState); printf(" Exit Code: %d\n", ssStatus.dwWin32ExitCode); printf(" Service Specific Exit Code: %d\n", ssStatus.dwServiceSpecificExitCode); printf(" Check Point: %d\n", ssStatus.dwCheckPoint); printf(" Wait Hint: %d\n", ssStatus.dwWaitHint); return 0; } } /************************************* * DWORD StopService( SC_HANDLE hSCM, LPTSTR szServiceName, BOOL fStopDependencies, DWORD dwTimeout ) * 功能 停止服务 * * 参数 SC_HANDLE hSCM SCM 句柄 * LPTSTR szServiceName 服务名 * BOOL fStopDependencies 是否结束依赖的服务 * DWORD dwTimeout 超时 **************************************/ DWORD StopService(SC_HANDLE hSCM, LPTSTR szServiceName, BOOL fStopDependencies, DWORD dwTimeout ) { SERVICE_STATUS_PROCESS ssp; SERVICE_STATUS ss; DWORD dwStartTime = GetTickCount(); DWORD dwBytesNeeded; // 打开服务 SC_HANDLE hService = OpenService( hSCM, // SCM 句柄 szServiceName, // 服务名 SERVICE_ALL_ACCESS); // 查询状态,确定是否已经停止 if ( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) { return GetLastError(); } if ( ssp.dwCurrentState == SERVICE_STOPPED ) { return ERROR_SUCCESS; } // 如果是 STOP_PENDING 状态,则只需等待 while ( ssp.dwCurrentState == SERVICE_STOP_PENDING ) { Sleep( ssp.dwWaitHint ); // 循环查询,直到状态改变 if ( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) { return GetLastError(); } if ( ssp.dwCurrentState == SERVICE_STOPPED ) { return ERROR_SUCCESS; } if ( GetTickCount() - dwStartTime > dwTimeout ) { return ERROR_TIMEOUT; } } // 先结束依赖服务 if ( fStopDependencies ) { DWORD i; DWORD dwBytesNeeded; DWORD dwCount; LPENUM_SERVICE_STATUS lpDependencies = NULL; ENUM_SERVICE_STATUS ess; SC_HANDLE hDepService; // 使用 0 大小的 buf,获取buf的大小 // 如果 EnumDependentServices 直接返回成功,说明没有依赖服务 if ( !EnumDependentServices( hService, SERVICE_ACTIVE, lpDependencies, 0, &dwBytesNeeded, &dwCount ) ) { if ( GetLastError() != ERROR_MORE_DATA ) return GetLastError(); // Unexpected error // 分配缓冲区存储依赖服务的数据 lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded ); if ( !lpDependencies ) return GetLastError(); __try { // 获得依赖服务 if ( !EnumDependentServices( hService, SERVICE_ACTIVE, lpDependencies, dwBytesNeeded, &dwBytesNeeded, &dwCount ) ) return GetLastError(); for ( i = 0; i < dwCount; i++ ) { ess = *(lpDependencies + i); // 打开服务 hDepService = OpenService( hSCM, ess.lpServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS ); if ( !hDepService ) return GetLastError(); __try { // 结束服务 if ( !ControlService( hDepService, SERVICE_CONTROL_STOP, &ss ) ) return GetLastError(); // 等待服务结束 while ( ss.dwCurrentState != SERVICE_STOPPED ) { Sleep( ss.dwWaitHint ); if ( !QueryServiceStatusEx( hDepService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) return GetLastError(); if ( ss.dwCurrentState == SERVICE_STOPPED ) break; if ( GetTickCount() - dwStartTime > dwTimeout ) return ERROR_TIMEOUT; } } __finally { // 关闭服务 CloseServiceHandle( hDepService ); } } } __finally { // 释放内存 HeapFree( GetProcessHeap(), 0, lpDependencies ); } } } // 所有的依赖服务已经结束,结束指定服务 if ( !ControlService( hService, SERVICE_CONTROL_STOP, &ss ) ) return GetLastError(); while ( ss.dwCurrentState != SERVICE_STOPPED ) { Sleep( ss.dwWaitHint ); if ( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) return GetLastError(); if ( ss.dwCurrentState == SERVICE_STOPPED ) break; if ( GetTickCount() - dwStartTime > dwTimeout ) return ERROR_TIMEOUT; } return ERROR_SUCCESS; } /************************************* * BOOL ControlSampleService(DWORD fdwControl) * 功能 向服务发送控制码 * * 参数 DWORD fdwControl 控制码值 * SCM 句柄,服务名直接使用全局变量 **************************************/ BOOL ControlSampleService(DWORD fdwControl) { SERVICE_STATUS ssStatus; DWORD fdwAccess; DWORD dwStartTickCount, dwWaitTime; // Access switch (fdwControl) { case SERVICE_CONTROL_STOP: fdwAccess = SERVICE_STOP; break; case SERVICE_CONTROL_PAUSE: case SERVICE_CONTROL_CONTINUE: fdwAccess = SERVICE_PAUSE_CONTINUE; break; case SERVICE_CONTROL_INTERROGATE: fdwAccess = SERVICE_INTERROGATE; break; default: fdwAccess = SERVICE_INTERROGATE; } // 打开服务 schService = OpenService( schSCManager, // SCManager 句柄 szServiceName, // 服务名 fdwAccess); // 存取权限 if (schService == NULL) { printf("OpenService failed (%d)\n", GetLastError()); return FALSE; } // 发送控制码 if (! ControlService( schService, // 服务的句柄 fdwControl, // 控制码 &ssStatus) ) // 状态 { printf("ControlService failed (%d)\n", GetLastError()); return FALSE; } // 显示状态 printf("\nStatus of Sample_Srv: \n"); printf(" Service Type: 0x%x\n", ssStatus.dwServiceType); printf(" Current State: 0x%x\n", ssStatus.dwCurrentState); printf(" Controls Accepted: 0x%x\n", ssStatus.dwControlsAccepted); printf(" Exit Code: %d\n", ssStatus.dwWin32ExitCode); printf(" Service Specific Exit Code: %d\n", ssStatus.dwServiceSpecificExitCode); printf(" Check Point: %d\n", ssStatus.dwCheckPoint); printf(" Wait Hint: %d\n", ssStatus.dwWaitHint); return TRUE; }