用 C++ 创建简单的 Win32 服务程序(2)
2006-04-09 11:41:10 来源:WEB开发网核心提示: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services我就是选择这里来存储我的服务配置信息,我创建了一个 Parameters 键,用 C++ 创建简单的 Win32 服务程序(2)(3),并在此存储我要保存的值,所以当服务启动时,然后在调
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
我就是选择这里来存储我的服务配置信息。我创建了一个 Parameters 键,并在此存储我要保存的值。所以当服务启动时,OnInit 函数被调用;这个函数从注册表中读取初始设置。
BOOL CMyService::OnInit() { // Read the registry parameters. // Try opening the registry key: // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\\Parameters HKEY hkey; char szKey[1024]; strcpy(szKey, "SYSTEM\\CurrentControlSet\\Services\\"); strcat(szKey, m_szServiceName); strcat(szKey, "\\Parameters"); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) { // Yes we are installed. DWORD dwType = 0; DWORD dwSize = sizeof(m_iStartParam); RegQueryValueEx(hkey, "Start", NULL, &dwType, (BYTE*)&m_iStartParam, &dwSize); dwSize = sizeof(m_iIncParam); RegQueryValueEx(hkey, "Inc", NULL, &dwType, (BYTE*)&m_iIncParam, &dwSize); RegCloseKey(hkey); } // Set the initial state. m_iState = m_iStartParam; return TRUE; }
现在我们有了服务参数,我们便可以运行服务了。运行服务
当 Run 函数被调用时将执行服务的主体代码。本文例子的这部分很简单:
void CMyService::Run() { while (m_bIsRunning) { // Sleep for a while. DebugMsg("My service is sleeping (%lu)...", m_iState); Sleep(1000); // Update the current state. m_iState += m_iIncParam; } }
注意,只要服务不终止,这个函数就不会退出。当有终止服务的请求时,CNTService::m_bIsRunning 标志被置成 FALSE。如果在服务终止时,你要实现清除操作,那么你还可以改写 OnStop 和/或 OnShutdown。响应控制请求
你可以用任何适合的方式与服务通讯——命名管道,思想交流,便条等等——对于一些简单的请求,用系统函数 ControlService 很容易实现。CNTService 提供了一个处理器专门用于通过 ControlService 函数发送的非标准消息(也就是用户发送的消息)。本文例子用单一消息在注册表中保存当前服务的状态,以便其它应用程序能看到它。我不建议用这种方法来监控服务,因为它不是最佳方法,这只是比较容易编码实现而已。ControlService 所能处理的用户消息必须在 128 到 255 这个范围。我定义了一个常量 SERVICE_CONTROL_USER,128 作为基值。范围内的用户消息被发送到 CNTService:: OnUserControl,在例子服务中,处理此消息的细节如下:
BOOL CMyService::OnUserControl(DWORD dwOpcode) { switch (dwOpcode) { case SERVICE_CONTROL_USER + 0: // Save the current status in the registry. SaveStatus(); return TRUE; default: break; } return FALSE; // say not handled }
SaveStatus 是一个局部函数,用来在注册表中存储服务状态。调试 Win32 服务
main 函数中包含一个对 DebugBreak 的调用,当服务第一次被启动时,它会激活系统调试器。你可以监控来自调试器命令窗口中的服务调试信息。你可以在服务中用 CNTService::DebugMsg 来报告调试期间感兴趣的事件。
为了调试服务代码,你需要按照 Platform SDK 文档中的要求安装 系统调试器(WinDbg)。你也可以用 Visual Studio 自带的调试器调试 Win32 服务。
有一点很重要,那就是 当它被服务管理器控制时,你不能终止服务和单步执行,因为服务管理器会让服务请求 超时并终止服务线程。所以你只能让服务吐出消息,跟踪其过程并在调试器窗口查看它们。
当服务启动后(例如,从控制面板的“服务”中),调试器将在服务线程的挂起后启动。你需要通过单击“Go”按钮或按 F5 让继续运行。然后在调试器中观察服务的运行过程。
下面是启动和终止服务的调试输出例子:
Module Load: WinDebug/NTService.exe (symbol loading deferred) Thread Create: Process=0, Thread=0 Module Load: C:\NT351\system32\NTDLL.DLL (symbol loading deferred) Module Load: C:\NT351\system32\KERNEL32.DLL (symbol loading deferred) Module Load: C:\NT351\system32\ADVAPI32.DLL (symbol loading deferred) Module Load: C:\NT351\system32\RPCRT4.DLL (symbol loading deferred) Thread Create: Process=0, Thread=1 *** WARNING: symbols checksum is wrong 0x0005830f 0x0005224f for C:\NT351\symbols\dll\NTDLL.DBG Module Load: C:\NT351\symbols\dll\NTDLL.DBG (symbols loaded) Thread Terminate: Process=0, Thread=1, Exit Code=0 Hard coded breakpoint hit Hard coded breakpoint hit [](130): CNTService::CNTService() Module Load: C:\NT351\SYSTEM32\RPCLTC1.DLL (symbol loading deferred) [NT Service Demonstration](130): Calling StartServiceCtrlDispatcher() Thread Create: Process=0, Thread=2 [NT Service Demonstration](174): Entering CNTService::ServiceMain() [NT Service Demonstration](174): Entering CNTService::Initialize() [NT Service Demonstration](174): CNTService::SetStatus(3026680, 2) [NT Service Demonstration](174): Sleeping... [NT Service Demonstration](174): CNTService::SetStatus(3026680, 4) [NT Service Demonstration](174): Entering CNTService::Run() [NT Service Demonstration](174): Sleeping... [NT Service Demonstration](174): Sleeping... [NT Service Demonstration](174): Sleeping... [NT Service Demonstration](130): CNTService::Handler(1) [NT Service Demonstration](130): Entering CNTService::Stop() [NT Service Demonstration](130): CNTService::SetStatus(3026680, 3) [NT Service Demonstration](130): Leaving CNTService::Stop() [NT Service Demonstration](130): Updating status (3026680, 3) [NT Service Demonstration](174): Leaving CNTService::Run() [NT Service Demonstration](174): Leaving CNTService::Initialize() [NT Service Demonstration](174): Leaving CNTService::ServiceMain() [NT Service Demonstration](174): CNTService::SetStatus(3026680, 1) Thread Terminate: Process=0, Thread=2, Exit Code=0 [NT Service Demonstration](130): Returned from StartServiceCtrlDispatcher() Module Unload: WinDebug/NTService.exe Module Unload: C:\NT351\system32\NTDLL.DLL Module Unload: C:\NT351\system32\KERNEL32.DLL Module Unload: C:\NT351\system32\ADVAPI32.DLL Module Unload: C:\NT351\system32\RPCRT4.DLL Module Unload: C:\NT351\SYSTEM32\RPCLTC1.DLL Thread Terminate: Process=0, Thread=0, Exit Code=0 Process Terminate: Process=0, Exit Code=0 >
总结也许用 C++ 创建 Win32 服务并不是最理想的,但使用单一的类来派生你自己的服务的确方便了你的服务开发工作。
更多精彩
赞助商链接