創建Windows服務(C++)


這次我們來創建一個windows本地服務,需要有以下功能:

  • 安裝服務。
  • 卸載服務。
  • 手動啟動服務。
  • 開機自動啟動服務。
  • 控制服務(停止、暫停、恢復、啟動)。

服務概念及介紹

看下圖,一切盡在不言中了(-_-):
pic

安裝服務並開機啟動

  • 代碼邏輯: 打開SCM(Service Control Manager)-> 創建服務。

  • 在CreateService調用中,我們傳入SERVICE_AUTO_START里表明這個服務是開啟自啟動的,SCM會在開機時調用StartService來啟動我們的服務;同時我們傳入NULL作為服務開始名稱,這樣該服務就可以開機啟動為系統服務。在調用installService后,我們會調用startService來手動啟動服務。

  • 這里我用SAFE_CALL簡化了錯誤處理邏輯。

    wstring getExeFullFilename()
    {
        static wchar_t buffer[1024];
    
        SAFE_CALL(GetModuleFileNameW(NULL, buffer, 1024), 0);
        return wstring(buffer);
    }
    
    void installService()
    {
        auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
        SAFE_CALL(scmHandle, NULL);
    
        auto serviceHandle = CreateServiceW(scmHandle,
                                            L"lgxZJ::Service",
                                            L"lgxZJ::Service", 
                                            SERVICE_ALL_ACCESS,
                                            SERVICE_WIN32_OWN_PROCESS,
                                            SERVICE_AUTO_START,
                                            SERVICE_ERROR_NORMAL,
                                            getExeFullFilename().c_str(),
                                            NULL, NULL, L"", NULL, L"");
        SAFE_CALL(serviceHandle, NULL);
    
        CloseServiceHandle(scmHandle);
        CloseServiceHandle(serviceHandle);
    }
    
    void startService()
    {
        auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        SAFE_CALL(scmHandle, NULL);
    
        auto serviceHandle = OpenServiceW(	scmHandle,
                                            L"lgxZJ::Service",
                                            SERVICE_ALL_ACCESS);
        SAFE_CALL(serviceHandle, NULL);
    
        SERVICE_STATUS serviceStatus;
        SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0);
        if (serviceStatus.dwCurrentState == SERVICE_START && 
            serviceStatus.dwCurrentState != SERVICE_START_PENDING)
            return;
    
        SAFE_CALL(StartServiceW(serviceHandle, 0, NULL), FALSE);
    
        CloseServiceHandle(scmHandle);
        CloseServiceHandle(serviceHandle);
    }
    
    #define SAFE_CALL(FuncCall, ErrorCode)                              \
        if (FuncCall == ErrorCode) {			                        \
            cout << #FuncCall " error, code:" << GetLastError()         \
                << " ,line:" << \__LINE__ << "\n"; 		                \
            exit(-1);							                        \
        }
    

卸載服務

  • 代碼邏輯: 打開SCM(Service Control Manager)-> 打開服務 -> 停止服務(如果正在運行) -> 刪除服務。

    void uninstallService()
    {
        auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        SAFE_CALL(scmHandle, NULL);
    
        auto serviceHandle = OpenServiceW(	scmHandle,
                                            L"lgxZJ::Service",
                                            SERVICE_ALL_ACCESS);
        SAFE_CALL(serviceHandle, NULL);
    
        SERVICE_STATUS serviceStatus;
        SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0);
        if (serviceStatus.dwCurrentState == SERVICE_RUNNING) {
            SAFE_CALL(ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus), 0);
            SAFE_CALL(serviceStatus.dwCurrentState, NO_ERROR);
    
            do {
                SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0);
                Sleep(1000);
            } while (serviceStatus.dwCurrentState != SERVICE_STOPPED);
        }
    
        SAFE_CALL(DeleteService(serviceHandle), FALSE);
    
        CloseServiceHandle(scmHandle);
        CloseServiceHandle(serviceHandle);
    }
    

手動啟動服務

  • 代碼邏輯: 打開SCM -> 打開服務 -> 啟動服務。

    void startService()
    {
        auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        SAFE_CALL(scmHandle, NULL);
    
        auto serviceHandle = OpenServiceW(	scmHandle,
                                            L"lgxZJ::Service",
                                            SERVICE_ALL_ACCESS);
        SAFE_CALL(serviceHandle, NULL);
    
        SERVICE_STATUS serviceStatus;
        SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0);
        if (serviceStatus.dwCurrentState == SERVICE_START && 
            serviceStatus.dwCurrentState != SERVICE_START_PENDING)
            return;
    
        SAFE_CALL(StartServiceW(serviceHandle, 0, NULL), FALSE);
    
        CloseServiceHandle(scmHandle);
        CloseServiceHandle(serviceHandle);
    }
    

運行服務(服務啟動時會運行服務)、服務控制處理

  • 代碼邏輯: 啟動分發器(連接到SCM) -> 注冊服務控制處理器 -> 在控制處理器中對服務控制進行處理(通過SetServiceStatus反饋服務狀態和設置接受的控制)。

    void runService()
    {
        const SERVICE_TABLE_ENTRYW serviceTable[] = {
            { L"", ServiceMain },
            { NULL, NULL }
        };
    
        SAFE_CALL(StartServiceCtrlDispatcherW(&serviceTable[0]), 0);
    }
    
    SERVICE_STATUS_HANDLE g_serviceStatusHandle = NULL;
    
    void setServiceStatus(DWORD status)
    {
        SERVICE_STATUS serviceStatus;
        serviceStatus.dwServiceType              = SERVICE_WIN32_OWN_PROCESS;
        serviceStatus.dwWin32ExitCode            = NO_ERROR;
        serviceStatus.dwServiceSpecificExitCode  = 0;
        serviceStatus.dwWaitHint                 = 2000;
        serviceStatus.dwCheckPoint               = 0;
        serviceStatus.dwControlsAccepted         =  SERVICE_ACCEPT_PAUSE_CONTINUE |
                                                    SERVICE_ACCEPT_SHUTDOWN |
                                                    SERVICE_ACCEPT_STOP;
    
        serviceStatus.dwCurrentState = status;
        SAFE_CALL(SetServiceStatus(g_serviceStatusHandle, &serviceStatus), 0);
    }
    
    VOID WINAPI ServiceHandler(DWORD controlCode)
    {
        switch (controlCode)
        {
            case SERVICE_CONTROL_CONTINUE:
                setServiceStatus(SERVICE_START_PENDING);    break;
            case SERVICE_CONTROL_INTERROGATE:
                                                            break;
            case SERVICE_CONTROL_PAUSE:
                setServiceStatus(SERVICE_PAUSED);           break;
            case SERVICE_CONTROL_SHUTDOWN:
                setServiceStatus(SERVICE_STOPPED);          break;
            case SERVICE_CONTROL_STOP:
                setServiceStatus(SERVICE_STOPPED);          break;
            default:
                break;
        }
    }
    
    VOID WINAPI ServiceMain(DWORD argc, LPWSTR *argv)
    {
        g_serviceStatusHandle = RegisterServiceCtrlHandlerW(L"lgxZJ::Service", &ServiceHandler);
        if (g_serviceStatusHandle == 0)
        {
            cout << "RegisterServiceCtrlHandlerW error, code:" << GetLastError()
                << " ,line:" << __LINE__ << "\n";
            exit(-1);
        }
    
        setServiceStatus(SERVICE_START_PENDING);
        setServiceStatus(SERVICE_RUNNING);
    }
    

完整代碼

生成的exe需要以管理員權限啟動,完整代碼見此處


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM