用C++创建Windows服务代码

Create a new C++ project. I used simply Empty Win32 Console Application in Visual Studio.


Coding

Every service has to contain following items :

  • A Main Entry point (like any application)
  • A Service Entry point
  • A Service Control Handler

Before writing Main Entry point we must declare some variables, which will be used in our application, but to correclty do this let's import following header files :

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#pragma comment(lib, "advapi32.lib")

First we need SERVICE_STATUS structure which will provide information about status of our service for Service Control Manager (SCM) .

 SERVICE_STATUS        g_ServiceStatus = {0}; 

We need also SERVICE_STATUS_HANDLE that is used to reference our service instance once it is registered with the SCM.

 SERVICE_STATUS_HANDLE g_StatusHandle = NULL; 

And there some additional variables, about it I will tell later.

HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;

VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv); //service entry point
VOID WINAPI ServiceCtrlHandler (DWORD);
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam); //service thread

#define SERVICE_NAME _T("My Sample Service");  //here we can write the visible name of our service  

Application Main Entry point

int _tmain (int argc, TCHAR *argv[])
{
    SERVICE_TABLE_ENTRY ServiceTable[] = 
    {
        {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
        {NULL, NULL}
    };

    if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
    {
        return GetLastError ();
    }

    return 0;
}

In the main entry point you quickly call StartServiceCtrlDispatcher so the SCM can call your Service Entry point (ServiceMain in the example above). You want to defer any initialization until your Service Entry point, which is defined next.

Service entry point

VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv)
{
    DWORD Status = E_FAIL;

    // Register our service control handler with the SCM
    g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler);

    if (g_StatusHandle == NULL) 
    {
        goto EXIT;
    }

    // Tell the service controller we are starting
    ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus));
    g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    g_ServiceStatus.dwControlsAccepted = 0;
    g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwServiceSpecificExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;

    if (SetServiceStatus (g_StatusHandle , &g_ServiceStatus) == FALSE)
    {
        OutputDebugString(_T(
          "My Sample Service: ServiceMain: SetServiceStatus returned error"));
    }

    /*
     * Perform tasks necessary to start the service here
     */

    // Create a service stop event to wait on later
    g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
    if (g_ServiceStopEvent == NULL) 
    {   
        // Error creating event
        // Tell service controller we are stopped and exit
        g_ServiceStatus.dwControlsAccepted = 0;
        g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        g_ServiceStatus.dwWin32ExitCode = GetLastError();
        g_ServiceStatus.dwCheckPoint = 1;

        if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
    {
        OutputDebugString(_T(
          "My Sample Service: ServiceMain: SetServiceStatus returned error"));
    }
        goto EXIT; 
    }    

    // Tell the service controller we are started
    g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;

    if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
    {
        OutputDebugString(_T(
          "My Sample Service: ServiceMain: SetServiceStatus returned error"));
    }

    // Start a thread that will perform the main task of the service
    HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);

    // Wait until our worker thread exits signaling that the service needs to stop
    WaitForSingleObject (hThread, INFINITE);


    /*
     * Perform any cleanup tasks 
     */

    CloseHandle (g_ServiceStopEvent);

    // Tell the service controller we are stopped
    g_ServiceStatus.dwControlsAccepted = 0;
    g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 3;

    if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
    {
        OutputDebugString(_T(
          "My Sample Service: ServiceMain: SetServiceStatus returned error"));
    }

EXIT:
    return;
} 

Here we have following tasks :

  • Initialize all necessary tasks from App Main Point
  • Register the service control handler which will handle Service Stop, Pause, Continue, Shutdown, etc control commands. These are registered via the dwControlsAccepted field of the SERVICE_STATUS structure as a bit mask.
  • Set Service Status to SERVICE_PENDING then to SERVICE_RUNNING. Set status to SERVICE_STOPPED on any errors and on exit. Always set SERVICE_STATUS.dwControlsAccepted to 0 when setting status to SERVICE_STOPPED or SERVICE_PENDING.
  • Perform start up tasks. Like creating threads/events/mutex/IPCs/etc.

Service Controller Handler

VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode)
{
    switch (CtrlCode) 
    {
     case SERVICE_CONTROL_STOP :

        if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
           break;

        /* 
         * Perform tasks necessary to stop the service here 
         */

        g_ServiceStatus.dwControlsAccepted = 0;
        g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
        g_ServiceStatus.dwWin32ExitCode = 0;
        g_ServiceStatus.dwCheckPoint = 4;

        if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
        {
            OutputDebugString(_T(
              "My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));
        }

        // This will signal the worker thread to start shutting down
        SetEvent (g_ServiceStopEvent);

        break;

     default:
         break;
    }
}  

The Service Control Handler was registered in your Service Main Entry point. Each service must have a handler to handle control requests from the SCM. The control handler must return within 30 seconds or the SCM will return an error stating that the service is not responding. This is because the handler will be called in the context of the SCM and will hold the SCM until it returns from the handler.

And now we're going to the penultimate step :

Service working thread

WORD WINAPI ServiceWorkerThread (LPVOID lpParam)
{
    //  Periodically check if the service has been requested to stop
    while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
    {        
        /* 
         * Perform main service function here
         */

        //  Simulate some work by sleeping
        Sleep(3000);
    }

    return ERROR_SUCCESS;
} 

This sample Service Worker Thread does nothing but sleep and check to see if the service has received a control to stop. Once a stop control has been received the Service Control Handler sets the g_ServiceStopEvent event. The Service Worker Thread breaks and exits. This signals the Service Main routine to return and effectively stop the service.


Installing and uninstalling the service

Installing the service

Every services have to be installed into the OS. To do that type that command in cmd line :

sc create "The name of service" binPath= C:\OurExecutableFileWithService.exe

Uninstalling the service

If we want use service never more, we should uninstall service from Windows.

sc delete "The name of service"

Other possibilities

There is also a possibility to install and uninstall(and also manage) a service directly from application - to do that read about CServiceHelper class.


This tutorial has been written based on :

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值