這次我們來創建一個windows本地服務,需要有以下功能:
- 安裝服務。
- 卸載服務。
- 手動啟動服務。
- 開機自動啟動服務。
- 控制服務(停止、暫停、恢復、啟動)。
服務概念及介紹
看下圖,一切盡在不言中了(-_-):
安裝服務並開機啟動
-
代碼邏輯: 打開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需要以管理員權限啟動,完整代碼見此處。