我们进行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;
- }