3.1.3 创建Windows服务应用程序

服务应用程序 (CppWindowsService)

一、简介

本代码示例演示了如何使用 Visual C++ 创建非常基础的 Windows 服务应用程序。示例 Windows 服务将服务的开始和停止信息记录到应用程序事件日志中,并展示了如何在线程池工作线程中运行服务的主函数。你可以方便地扩展 Windows 服务框架,以满足自身的业务需求。

二、运行示例

以下步骤将进行 Windows 服务示例的演示。

步骤 1

在 Visual Studio 2008 中成功构建示例项目后,你将获得以下服务应用程序:CppWindowsService.exe。

步骤 2

以管理员身份运行命令提示符,导航到示例项目的输出文件夹,然后输入以下命令并安装服务。

CppWindowsService.exe -install

如果进程输出以下内容,说明服务已成功安装:

img

如果你未看到此输出,请在输出中查找错误代码,并调查失败原因。例如,错误代码 0x431 说明服务已经存在,你需要先将其卸载。

步骤 3

打开服务管理控制台 (services.msc)。你将在服务列表中找到“CppWindowsService 示例服务”。

img

步骤 4

在服务管理控制台中右键单击 CppWindowsService 服务,然后选择“启动”来启动服务。打开事件查看器,并导航到 Windows 日志/应用程序。你会在 CppWindowsService 中看到此事件和以下信息:

img

步骤 5

在服务管理控制台中右键单击服务,然后选择“停止”以停止服务。你会在事件查看器/Windows 日志/应用程序的 CppWindowsService 中看到此新事件和以下信息:

img

步骤 6

若要卸载此服务,请以管理员身份运行命令提示符并输入以下命令。

CppWindowsService.exe -remove

如果此服务已成功删除,你将看到以下输出:

img

三、使用代码

步骤 1

在 Visual Studio 2008 中添加名为 CppWindowsService 的新 Visual C++ / Win32 / Win32 控制台应用程序项目。在 Win32 应用程序向导的“应用程序设置”中取消选择“预译编头”选项,并在创建项目后删除 stdafx.h、stdafx.cpp 和 targetver.h 文件。

步骤 2

在 CppWindowsService.cpp 中定义服务设置。

// Internal name of the service 
   #define SERVICE_NAME             L"CppWindowsService" 


   // Displayed name of the service 
   #define SERVICE_DISPLAY_NAME     L"CppWindowsService Sample Service" 


   // Service start options. 
   #define SERVICE_START_TYPE       SERVICE_DEMAND_START 


   // List of service dependencies - "dep1\0dep2\0\0" 
   #define SERVICE_DEPENDENCIES     L"" 


   // The name of the account under which the service should run 
   #define SERVICE_ACCOUNT          L"NT AUTHORITY\\LocalService" 


   // The password to the service account name 
   #define SERVICE_PASSWORD         NULL

安全说明:在本示例代码中,服务配置为以 LocalService(而非 LocalSystem)身份运行。LocalSystem 帐户有广泛的权限。请小心使用 LocalSystem 帐户,因为这可能会增加你受到恶意软件攻击的风险。对于不需要广泛权限的任务,请考虑使用 LocalService 帐户,它会在本地计算机上扮演非特权用户的角色,并对任何远程服务器显示匿名凭据。

步骤 3

将 CppWindowsService.cpp 中的应用程序入口点(主要)替换为以下代码。根据命令行中的参数,该函数会通过调用将在后续步骤中声明并实施的多个例程来安装、卸载或启动服务。

int wmain(int argc, wchar_t *argv[]) 
    { 
        if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/')))) 
        { 
            if (_wcsicmp(L"install", argv[1] + 1) == 0) 
            { 
                // Install the service when the command is  
                // "-install" or "/install". 
                InstallService( 
                    SERVICE_NAME,               // Name of service 
                    SERVICE_DISPLAY_NAME,       // Name to display 
                    SERVICE_START_TYPE,         // Service start type 
                    SERVICE_DEPENDENCIES,       // Dependencies 
                    SERVICE_ACCOUNT,            // Service running account 
                    SERVICE_PASSWORD            // Password of the account 
                    ); 
            } 
            else if (_wcsicmp(L"remove", argv[1] + 1) == 0) 
            { 
                // Uninstall the service when the command is  
                // "-remove" or "/remove". 
                UninstallService(SERVICE_NAME); 
            } 
        } 
        else 
        { 
            wprintf(L"Parameters:\n"); 
            wprintf(L" -install  to install the service.\n"); 
            wprintf(L" -remove   to remove the service.\n"); 

            CSampleService service(SERVICE_NAME); 
            if (!CServiceBase::Run(service)) 
            { 
                wprintf(L"Service failed to run w/err 0x%08lx\n", GetLastError()); 
            } 
        } 

        return 0; 
    }

步骤 4

添加 ServiceBase.h 和 ServiceBase.cpp 文件,为将作为服务应用程序一部分存在的服务提供基类。该类名为 "CServiceBase"。创建新服务类时必须从该类派生。

该服务基类有以下公用函数:

// It register the executable for a service with SCM. 
  static BOOL CServiceBase::Run(CServiceBase &service) 


  // This is the constructor of the service class. The optional parameters  
  // (fCanStop, fCanShutdown and fCanPauseContinue) allow you to specify  
  // whether the service can be stopped, paused and continued, or be  
  // notified when system shutdown occurs. 
  CServiceBase::CServiceBase(PWSTR pszServiceName,  
      BOOL fCanStop = TRUE,  
      BOOL fCanShutdown = TRUE,  
      BOOL fCanPauseContinue = FALSE) 


  // This is the virtual destructor of the service class. 
  virtual ~CServiceBase::CServiceBase(void); 

  // Funtion that stops the service. 
  void CServiceBase::Stop();

该类还提供了以下虚拟成员函数。你可以在派生类中实施这些函数。这些函数将在服务启动、停止、暂停、继续和系统关闭时执行。

virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv); 
 virtual void OnStop(); 
 virtual void OnPause(); 
 virtual void OnContinue(); 
 virtual void OnShutdown();

步骤 5

添加 SampleService.h 和 SampleService.cpp 文件,提供派生自服务基类 (CServiceBase) 的示例服务类。示例服务将服务的开始和停止信息记录到应用程序日志中,并展示了如何在线程池工作线程中运行服务的主函数。

在服务启动时执行的 CSampleService::OnStart 将调用 CServiceBase::WriteEventLogEntry 来记录服务启动信息。它还将调用 CThreadPool::QueueUserWorkItem,以便将在工作线程中执行的主服务函数 (CSampleService::ServiceWorkerThread) 排队。

注意:服务应用程序设计为长时间运行。因此,它通常可轮询或监视系统中的某些内容。已在 OnStart 方法中设置了监视。但是,OnStart 不会实际进行监视。服务操作开始之后,OnStart 方法必须返回操作系统。它不能始终循环或阻止。若要设置简单监测机制,常规解决方案是在 OnStart 中创建一个计时器。随后计时器将定期引发代码中的事件,在此时间服务可进行监测。另一种解决方案是生成一个新

线程来执行主服务函数,此过程将在本代码示例中进行演示。

void CSampleService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv) 
   { 
       // Log a service start message to the Application log. 
       WriteEventLogEntry(L"CppWindowsService in OnStart",  
           EVENTLOG_INFORMATION_TYPE); 

       // Queue the main service function for execution in a worker thread. 
       CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this); 
   }

在服务停止时执行的 CSampleService::OnStop 将调用 CServiceBase::WriteEventLogEntry 来记录服务停止信息。接下来,它会将成员变量 m_fStopping 设置为 TRUE,以指示服务正在停止,并等待由 m_hStoppedEvent 事件对象用信号通知的主服务函数完成。

C++

void CSampleService::OnStop() 
   { 
       WriteEventLogEntry(L"CppWindowsService in OnStop",  
           EVENTLOG_INFORMATION_TYPE); 

       // Indicate that the service is stopping and wait for the finish of the  
       // main service function (ServiceWorkerThread). 
       m_fStopping = TRUE; 
       if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0) 
       { 
           throw GetLastError(); 
       } 
   }

CSampleService::ServiceWorkerThread 在线程池工作线程中运行。它将执行服务的主函数,例如,通过命名管道与客户端应用程序进行通信。为了使主函数正常完成,当服务即将停止时,应定期检查 m_fStopping 变量。当此函数检测到服务正在停止时,将清除该工作并用信号通知 m_hStoppedEvent 事件对象。

void CSampleService::ServiceWorkerThread(void) 
   { 
       // Periodically check if the service is stopping. 
       while (!m_fStopping) 
       { 
           // Perform main service function here... 

           ::Sleep(2000);  // Simulate some lengthy operations. 
       } 

       // Signal the stopped event. 
       SetEvent(m_hStoppedEvent); 
   }

步骤 6

添加 ServiceInstaller.h 和 ServiceInstaller.cpp 文件,声明并实施安装和卸载此服务的函数:

InstallService          Installs the service 
UninstallService        Uninstalls the service

原文及源码链接

results matching ""

    No results matching ""