Windows 服務(Service)是在後台運行、無需用戶登錄即可啟動的長期進程。本文提供一個基於 Win32 API 的最小化 C 語言服務框架,並詳述編譯、安裝、啟動、調試全流程。
服務程序需實現三大核心入口:
main():調用 StartServiceCtrlDispatcher 連接服務控制管理器 (SCM)。ServiceMain():服務主線程,初始化狀態、註冊控制處理函數、進入工作循環。ControlHandler():處理 SCM 發來的控制碼(停止、關機、暫停等)。#include <windows.h>
#include <stdio.h>
#define SLEEP_TIME 5000
#define LOGFILE "D:\\TEST\\memstatus.txt"
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv);
void WINAPI ControlHandler(DWORD request);
int WriteToLog(const char *str);
int wmain(int argc, wchar_t *argv[]) {
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = L"MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// 進入服務調度循環,不返回直到服務停止
StartServiceCtrlDispatcher(ServiceTable);
return 0;
}
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv) {
// 1. 初始化狀態結構
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
// 2. 註冊控制處理函數
hStatus = RegisterServiceCtrlHandler(L"MemoryStatus", ControlHandler);
if (!hStatus) return;
// 3. 設置運行狀態
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);
// 4. 服務主工作循環
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
char buffer[256];
GetCurrentDirectoryA(256, buffer); // 示例任務:記錄當前目錄
if (WriteToLog(buffer)) {
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
Sleep(SLEEP_TIME);
}
}
void WINAPI ControlHandler(DWORD request) {
switch (request) {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
WriteToLog("Monitoring stopped");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);
return;
default:
break;
}
SetServiceStatus(hStatus, &ServiceStatus);
}
int WriteToLog(const char *str) {
FILE *log = fopen(LOGFILE, "a+");
if (!log) return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
wmain/LPWSTR (ServiceMain) 與 GetCurrentDirectoryA/fopen (ANSI)。實際項目建議統一字符集(推薦 Unicode,宏 UNICODE/_UNICODE)。SERVICE_START_PENDING → SERVICE_RUNNING → SERVICE_STOPPED。必須及時調用 SetServiceStatus 回報 SCM,否則服務會被判定為「無響應」並被強制終止。C:\Windows\Temp 或顯式授權目錄)。Advapi32.lib。生成 service_test.exe。sc create MemoryStatus binPath= "D:\TEST\service_test.exe" DisplayName= "Memory Status Service" start= auto
成功提示:[SC] CreateService SUCCESS。
sc start MemoryStatus / sc stop MemoryStatusservices.msc 中查找「Memory Status Service」操作。sc delete MemoryStatus (需先停止服務)。OutputDebugString 配合 DebugView 工具查看。main 中添加參數判斷(如 -console),直接調用 ServiceMain 邏輯,方便斷點調試。掌握此框架,即可將任何長期後台任務(監控、定時同步、網絡監聽)封裝為標準 Windows 服務。