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

C++Builder 編寫 Windows 2000 服務程序:SCM API 完整封裝實戰

     編輯:VC 教學

Windows 2000 引入強大的**服務**機制:隨系統啟動、無用戶登錄即運行、可遠程管理。本文從零構建一個標準 Win32 服務框架,封裝 OpenSCManager、CreateService、StartServiceCtrlDispatcher 等核心 API,提供可直接填充業務邏輯的服務模板代碼。

服務程序架構三大塊

  1. ServiceMain:服務入口,註冊控制處理函數,啟動工作線程;
  2. ServiceCtrlHandler:響應 SCM 命令 (啟動/停止/暫停/繼續/關機);
  3. Worker Thread:實際業務邏輯循環,定期檢查停止事件。

關鍵 API 速查

API用途關鍵參數
OpenSCManager打開服務控制管理器數據庫lpMachineName=NULL (本機), dwDesiredAccess=SC_MANAGER_ALL_ACCESS
CreateService在 SCM 中創建服務記錄lpServiceName, lpDisplayName, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START
StartServiceCtrlDispatcher連接 SCM,進入服務主循環傳入 SERVICE_TABLE_ENTRY 陣列 (服務名+ServiceMain)
RegisterServiceCtrlHandler註冊控制處理函數返回 SERVICE_STATUS_HANDLE
SetServiceStatus向 SCM 報告狀態變化SERVICE_STATUS 結構 (dwCurrentState, dwControlsAccepted, dwCheckPoint, dwWaitHint)
ControlService發送控制碼 (停止/暫停/…)SERVICE_CONTROL_STOP 等

極簡服務骨架代碼 (可直接複製修改)


// Service.cpp
#include 
#include 

SERVICE_STATUS_HANDLE g_hStatus = NULL;
SERVICE_STATUS g_Status = {0};
HANDLE g_hStopEvent = NULL;
HANDLE g_hWorkerThread = NULL;

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI CtrlHandler(DWORD ctrlCode);
DWORD WINAPI WorkerThread(LPVOID lpParam);
VOID ReportStatus(DWORD state, DWORD exitCode, DWORD waitHint);

int _tmain() {
    SERVICE_TABLE_ENTRY dispatchTable[] = {
        { _T("MyCppBuilderService"), (LPSERVICE_MAIN_FUNCTION)ServiceMain },
        { NULL, NULL }
    };
    StartServiceCtrlDispatcher(dispatchTable);  // 進入 SCM 循環,不返回
    return 0;
}

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
    g_hStatus = RegisterServiceCtrlHandler(_T("MyCppBuilderService"), CtrlHandler);
    g_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    g_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ReportStatus(SERVICE_START_PENDING, NO_ERROR, 3000);

    g_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    g_hWorkerThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, NULL);

    ReportStatus(SERVICE_RUNNING, NO_ERROR, 0);
    // ServiceMain 返回即視為服務停止,這裡阻塞等待工作線程結束
    WaitForSingleObject(g_hWorkerThread, INFINITE);

    CloseHandle(g_hStopEvent);
    CloseHandle(g_hWorkerThread);
    ReportStatus(SERVICE_STOPPED, NO_ERROR, 0);
}

VOID WINAPI CtrlHandler(DWORD ctrlCode) {
    switch (ctrlCode) {
        case SERVICE_CONTROL_STOP:
        case SERVICE_CONTROL_SHUTDOWN:
            ReportStatus(SERVICE_STOP_PENDING, NO_ERROR, 3000);
            SetEvent(g_hStopEvent);  // 通知工作線程退出
            break;
        case SERVICE_CONTROL_PAUSE:  /* 暫停邏輯 */ break;
        case SERVICE_CONTROL_CONTINUE: /* 繼續邏輯 */ break;
        case SERVICE_CONTROL_INTERROGATE: break;
    }
}

DWORD WINAPI WorkerThread(LPVOID lpParam) {
    while (WaitForSingleObject(g_hStopEvent, 1000) == WAIT_TIMEOUT) {
        // ===== 在此填寫您的業務邏輯 =====
        // 例:定時檢測、數據同步、網絡監聽、文件處理…
    }
    return 0;
}

VOID ReportStatus(DWORD state, DWORD exitCode, DWORD waitHint) {
    g_Status.dwCurrentState = state;
    g_Status.dwWin32ExitCode = exitCode;
    g_Status.dwWaitHint = waitHint;
    if (state == SERVICE_START_PENDING)
        g_Status.dwControlsAccepted = 0;
    else
        g_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    SetServiceStatus(g_hStatus, &g_Status);
}

安裝/卸載服務輔助函數


bool InstallService(LPCTSTR exePath, LPCTSTR svcName, LPCTSTR displayName) {
    SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!hSCM) return false;
    SC_HANDLE hSvc = CreateService(hSCM, svcName, displayName,
        SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
        SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
        exePath, NULL, NULL, NULL, NULL, NULL);
    bool ok = (hSvc != NULL);
    if (hSvc) CloseServiceHandle(hSvc);
    CloseServiceHandle(hSCM);
    return ok;
}

bool UninstallService(LPCTSTR svcName) {
    SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!hSCM) return false;
    SC_HANDLE hSvc = OpenService(hSCM, svcName, DELETE);
    bool ok = false;
    if (hSvc) {
        ok = DeleteService(hSvc);
        CloseServiceHandle(hSvc);
    }
    CloseServiceHandle(hSCM);
    return ok;
}

C++Builder 專屬編譯設置

  1. **目標文件類型**:Console Application (主函數入口);
  2. **鏈接器**:勾選 Advapi32.lib (SCM API 所在);
  3. **運行庫**:建議動態 RTL + 動態 VCL (減小體積);
  4. **調試**:服務無法直接 F5,需 Run → Parameters → Host Application = services.exe 或裝上後用 Attach to Process;
  5. **日誌**:服務無控制台,必須寫文件/事件日誌/OutputDebugString 配合 DbgView 查看。

常見坑點

  • ❌ `ServiceMain` 返回太快 → 服務狀態變為 STOPPED,**必須阻塞** (等待線程/事件);
  • ❌ 未正確響應 `SERVICE_CONTROL_INTERROGATE` → SCM 認為服務掛起;
  • ❌ 僅處理 STOP,忽略 SHUTDOWN → 系統關機時服務未優雅退出;
  • ❌ 服務帳戶權限不足 (默認 LocalSystem) 訪問網絡資源失敗 → 安裝時指定域用戶或啟用「與桌面交互」 (僅本地調試);
  • ✅ 使用 **C++Builder 服務專家** (File → New → Other → Service Application) 可自動生成上述框架,僅需填充 `WorkerThread`。

掌握 SCM API 流程與狀態機,即可在 C++Builder 中編寫穩健、可管理的 Windows 服務程序,實現真正的無人值守後台服務。

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