返回介绍

1 C

2 C++

3 Windows

4 Linux

5 数据库

6 数据结构

7 算法

8 Qt

9 AS400

10 Web

12 C

13 框架

14 协议

15 工具

17 QA

3.1.3 创建 Windows 服务应用程序

发布于 2023-10-02 20:38:18 字数 17980 浏览 0 评论 0 收藏 0

一、简介

本代码示例演示了如何使用 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

原文及源码链接

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文