Windows 服務由服務主程序(在後台運行的業務邏輯)和服務控制程序(安裝、啟動、停止、刪除服務)組成。本文提供一個完整、可編譯運行的單文件實例,展示如何將兩者融合在一個 .exe 中,通過命令行參數控制服務生命週期。
-create/-start/-stop/-delete),或啟動服務調度器。#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#define SLEEP_TIME 5000
#define SERVICE_NAME "ServiTest"
#define SERVICE_DISPLAY_NAME "Test Service"
#define SERVICE_DESC "Demo Win32 Service"
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
void Log(const char* filename, const char* str);
int MyWork();
void OnCreate(); void OnStart(); void OnStop(); void OnDelete();
int main(int argc, char* argv[]) {
SERVICE_TABLE_ENTRY ServiceTable[2] = {
{ SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
if (argc == 2) {
if (!stricmp(argv[1], "-create")) { OnCreate(); return 0; }
if (!stricmp(argv[1], "-start")) { OnStart(); return 0; }
if (!stricmp(argv[1], "-stop")) { OnStop(); return 0; }
if (!stricmp(argv[1], "-delete")) { OnDelete(); return 0; }
printf("Invalid parameter\n"); return 0;
}
// 作為服務運行
StartServiceCtrlDispatcher(ServiceTable);
return 0;
}
// === 服務主程序 ===
void ServiceMain(int argc, char** argv) {
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)ControlHandler);
if (!hStatus) return;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
if (MyWork()) { // 返回非0 表示需停止
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
}
}
int MyWork() {
MessageBox(NULL, "Service Working...", SERVICE_NAME, MB_OK);
Sleep(SLEEP_TIME);
return 0;
}
void ControlHandler(DWORD request) {
switch (request) {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
Log("C:\\MemoryWatch.txt", "Monitoring stopped.");
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
SetServiceStatus(hStatus, &ServiceStatus);
}
// === 服務控制程序 ===
void OnCreate() {
char path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH);
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!scm) { printf("OpenSCManager failed: %d\n", GetLastError()); return; }
SC_HANDLE svc = CreateService(
scm, SERVICE_NAME, SERVICE_DISPLAY_NAME, SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
path, NULL, NULL, NULL, NULL, NULL
);
if (!svc) {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_EXISTS) printf("CreateService failed: %d\n", err);
else printf("Service already exists.\n");
} else {
printf("Service created successfully.\n");
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
void OnStart() {
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!scm) return;
SC_HANDLE svc = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (svc) {
if (!StartService(svc, 0, NULL)) {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_ALREADY_RUNNING) printf("StartService failed: %d\n", err);
else printf("Already running.\n");
} else {
printf("Starting...");
// 等待服務進入 RUNNING 狀態
while (QueryServiceStatus(svc, &ServiceStatus)) {
if (ServiceStatus.dwCurrentState == SERVICE_START_PENDING) Sleep(100);
else break;
}
}
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
void OnStop() {
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!scm) return;
SC_HANDLE svc = OpenService(scm, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS);
if (svc) {
QueryServiceStatus(svc, &ServiceStatus);
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
ControlService(svc, SERVICE_CONTROL_STOP, &ServiceStatus);
}
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
void OnDelete() {
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!scm) return;
SC_HANDLE svc = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (svc) {
QueryServiceStatus(svc, &ServiceStatus);
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
ControlService(svc, SERVICE_CONTROL_STOP, &ServiceStatus);
}
DeleteService(svc);
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
void Log(const char* file, const char* str) {
FILE* fp = fopen(file, "a+");
if (fp) { fprintf(fp, "%s\n", str); fclose(fp); }
}
ServiceDemo.exe。ServiceDemo.exe -create # 安裝服務
ServiceDemo.exe -start # 啟動服務
# 觀察彈出的 MessageBox(需勾選服務屬性「允許服務與桌面交互」)
ServiceDemo.exe -stop # 停止服務
ServiceDemo.exe -delete # 卸載服務
SERVICE_START_PENDING → SERVICE_RUNNING → SERVICE_STOPPED,必須及時 SetServiceStatus,否則 SCM 會判定服務掛起並強制終止。GetLastError() 定位問題(常見:權限不足、服務已存在、路徑錯誤)。argc==2 走控制邏輯,否則走服務調度,部署極簡。ServiceMain 僅負責狀態管理。EventLog 替代文件日誌。SERVICE_CONTROL_PAUSE/CONTINUE 支持。ChangeServiceConfig2 + SERVICE_CONFIG_FAILURE_ACTIONS)。此例為學習 Win32 服務機制的最小完整樣本,掌握後可擴展為健壯的生產級服務程序。