首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言開發 Windows 服務:從代碼到安裝部署全流程

     編輯:關於C語言

C 語言開發 Windows 服務:從代碼到安裝部署全流程

Windows 服務(Service)是在後台運行、無需用戶登錄即可啟動的長期進程。本文提供一個基於 Win32 API 的最小化 C 語言服務框架,並詳述編譯、安裝、啟動、調試全流程。

核心代碼架構

服務程序需實現三大核心入口:

  1. main():調用 StartServiceCtrlDispatcher 連接服務控制管理器 (SCM)。
  2. ServiceMain():服務主線程,初始化狀態、註冊控制處理函數、進入工作循環。
  3. ControlHandler():處理 SCM 發來的控制碼(停止、關機、暫停等)。

完整示例代碼 (service_test.c)

#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;
}

關鍵點詳解

  • Unicode/ANSI:示例混用 wmain/LPWSTR (ServiceMain) 與 GetCurrentDirectoryA/fopen (ANSI)。實際項目建議統一字符集(推薦 Unicode,宏 UNICODE/_UNICODE)。
  • 狀態機:SERVICE_START_PENDING → SERVICE_RUNNING → SERVICE_STOPPED。必須及時調用 SetServiceStatus 回報 SCM,否則服務會被判定為「無響應」並被強制終止。
  • 日誌路徑:服務運行於 SYSTEM 權限,寫入路徑需確保 SYSTEM 有寫入權限(如 C:\Windows\Temp 或顯式授權目錄)。

編譯、安裝與部署步驟

  1. 編譯:Visual Studio 創建「Windows 桌面應用程序」或控制台項目,鏈接 Advapi32.lib。生成 service_test.exe。
  2. 安裝 (需管理員權限):
    sc create MemoryStatus binPath= "D:\TEST\service_test.exe" DisplayName= "Memory Status Service" start= auto

    成功提示:[SC] CreateService SUCCESS。

  3. 啟動/停止:
    • 命令行:sc start MemoryStatus / sc stop MemoryStatus
    • GUI:services.msc 中查找「Memory Status Service」操作。
  4. 卸載:sc delete MemoryStatus (需先停止服務)。

調試技巧

  • 輸出調試信息:服務無控制台,可用 OutputDebugString 配合 DebugView 工具查看。
  • 以控制台模式運行:在 main 中添加參數判斷(如 -console),直接調用 ServiceMain 邏輯,方便斷點調試。
  • 事件查看器:Windows Logs → System/Application,查看服務啟動失敗的錯誤碼。

掌握此框架,即可將任何長期後台任務(監控、定時同步、網絡監聽)封裝為標準 Windows 服務。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved