Windows 服務在背景執行、開機自動啟動、無需使用者登入,適合監控、備份、伺服器類程式。本文以 Win32 應用程式專案為基礎,逐步建立完整服務框架,包含安裝、解除安裝、主執行緒、控制處理與狀態回報。
ServiceTest,選 Empty Project。ServiceTest.cpp 作為唯一原始檔。
#include <windows.h>
#include <winsvc.h>
#include <tchar.h>
TCHAR g_szSvcName[] = _T("ServiceTest");
SERVICE_STATUS_HANDLE g_hStatus = NULL;
SERVICE_STATUS g_status = {0};
DWORD g_dwThreadId = 0;
BOOL InstallService();
BOOL UninstallService();
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl);
VOID LogEvent(LPCTSTR fmt, ...);
void InitStatus()
{
g_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_status.dwCurrentState = SERVICE_STOPPED;
g_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_status.dwWin32ExitCode = 0;
g_status.dwCheckPoint = 0;
g_status.dwWaitHint = 0;
}
BOOL InstallService()
{
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL, szPath, MAX_PATH);
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return FALSE;
SC_HANDLE hSvc = CreateService(hSCM, g_szSvcName, g_szSvcName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
szPath, NULL, NULL, _T(""), NULL, NULL);
BOOL ok = (hSvc != NULL);
if (hSvc) CloseServiceHandle(hSvc);
CloseServiceHandle(hSCM);
return ok;
}
BOOL UninstallService()
{
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return FALSE;
SC_HANDLE hSvc = OpenService(hSCM, g_szSvcName, SERVICE_STOP | DELETE);
if (!hSvc) { CloseServiceHandle(hSCM); return FALSE; }
ControlService(hSvc, SERVICE_CONTROL_STOP, &g_status);
BOOL ok = DeleteService(hSvc);
CloseServiceHandle(hSvc);
CloseServiceHandle(hSCM);
return ok;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
g_status.dwCurrentState = SERVICE_START_PENDING;
g_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_hStatus = RegisterServiceCtrlHandler(g_szSvcName, ServiceCtrlHandler);
if (!g_hStatus) { LogEvent(_T("Handler 註冊失敗")); return; }
SetServiceStatus(g_hStatus, &g_status);
g_status.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(g_hStatus, &g_status);
// --- 實際工作迴圈 ---
while (g_status.dwCurrentState == SERVICE_RUNNING) {
// 執行核心任務:監控、備份、網路服務等
Sleep(1000);
}
// ----------------------
g_status.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(g_hStatus, &g_status);
}
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl)
{
switch (dwCtrl) {
case SERVICE_CONTROL_STOP:
g_status.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(g_hStatus, &g_status);
// 通知工作迴圈結束(可用事件物件)
break;
case SERVICE_CONTROL_INTERROGATE:
break;
}
SetServiceStatus(g_hStatus, &g_status);
}
int APIENTRY _tWinMain(HINSTANCE hInst, HINSTANCE, LPTSTR lpCmdLine, int)
{
InitStatus();
if (_tcsicmp(lpCmdLine, _T("/install")) == 0) {
InstallService();
return 0;
}
if (_tcsicmp(lpCmdLine, _T("/uninstall")) == 0) {
UninstallService();
return 0;
}
SERVICE_TABLE_ENTRY dispatchTable[] = {
{ g_szSvcName, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher(dispatchTable)) {
LogEvent(_T("StartServiceCtrlDispatcher 失敗: %d"), GetLastError());
}
return 0;
}
ServiceTest.exe。ServiceTest.exe /install # 安裝服務
net start ServiceTest # 啟動服務
net stop ServiceTest # 停止服務
ServiceTest.exe /uninstall # 移除服務
dwControlsAccepted 必須包含 SERVICE_ACCEPT_STOP,否則服務管理員無法發送停止命令。SERVICE_RUNNING,SCM 會判定啟動失敗;長時間初始化需定期 SetServiceStatus 更新 dwCheckPoint 與 dwWaitHint。ServiceMain 開頭加 DebugBreak(),附加偵錯器至服務進程。