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

Windows NT 服務程式設計完整指南:服務控制、列舉與管理

     編輯:關於C++

Windows NT 提供強大的服務架構(如 FTP、WWW、資料庫服務),服務通常在開機自動啟動、關機停止。但開發者常需在程式中動態控制服務(啟動、暫停、停止、查詢狀態),甚至開發自訂服務。本文系統介紹 Service Control Manager (SCM) 核心 API,並提供 C++ Builder 完整範例程式碼,實現服務列舉、啟動、停止功能。

一、核心 API 概覽

所有服務資訊儲存在 Service Control Manager Database 中,操作流程:開啟 SCM → 開啟特定服務 → 執行控制操作 → 關閉控制代碼。

1. OpenSCManager - 開啟服務控制管理器

SC_HANDLE OpenSCManager(
    LPCTSTR lpMachineName,    // NULL=本機
    LPCTSTR lpDatabaseName,   // NULL=預設資料庫
    DWORD   dwDesiredAccess   // 權限旗標
);

常用權限:SC_MANAGER_ALL_ACCESS、SC_MANAGER_ENUMERATE_SERVICE、SC_MANAGER_CREATE_SERVICE 等。

2. OpenService - 開啟特定服務

SC_HANDLE OpenService(
    SC_HANDLE hSCManager,
    LPCTSTR   lpServiceName,  // 服務名稱(區分大小寫)
    DWORD     dwDesiredAccess // SERVICE_ALL_ACCESS, SERVICE_START, SERVICE_STOP 等
);

3. QueryServiceStatus - 查詢服務狀態

BOOL QueryServiceStatus(
    SC_HANDLE hService,
    LPSERVICE_STATUS lpServiceStatus
);

SERVICE_STATUS 結構包含:dwCurrentState(SERVICE_STOPPED=1, SERVICE_RUNNING=4 等)、dwControlsAccepted、dwCheckPoint、dwWaitHint 等。

4. StartService - 啟動服務

BOOL StartService(
    SC_HANDLE hService,
    DWORD dwNumServiceArgs,
    LPCTSTR *lpServiceArgVectors
);

5. ControlService - 發送控制碼

BOOL ControlService(
    SC_HANDLE hService,
    DWORD dwControl,          // SERVICE_CONTROL_STOP, PAUSE, CONTINUE, INTERROGATE
    LPSERVICE_STATUS lpServiceStatus
);

6. EnumServicesStatus - 列舉服務

BOOL EnumServicesStatus(
    SC_HANDLE hSCManager,
    DWORD dwServiceType,      // SERVICE_DRIVER, SERVICE_WIN32 等
    DWORD dwServiceState,     // SERVICE_ACTIVE, SERVICE_INACTIVE 等
    LPENUM_SERVICE_STATUS lpServices,
    DWORD cbBufSize,
    LPDWORD pcbBytesNeeded,
    LPDWORD lpServicesReturned,
    LPDWORD lpResumeHandle
);

關鍵點:通常首次呼叫回傳 FALSE,GetLastError() == ERROR_MORE_DATA,需依 pcbBytesNeeded 配置足夠緩衝區再呼叫第二次取得完整列表。

二、C++ Builder 完整實作範例

介面:ListBox1 顯示服務清單,Button1 列舉,Button2 啟動選取服務,Button3 停止選取服務。

Unit1.h 關鍵宣告

#include 
class TForm1 : public TForm {
__published:
    TButton *Button1, *Button2, *Button3;
    TListBox *ListBox1;
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall Button2Click(TObject *Sender);
    void __fastcall Button3Click(TObject *Sender);
    void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
private:
    SC_HANDLE hSCManager, hService;
    SERVICE_STATUS ReturnStatus;
};

Unit1.cpp 核心邏輯

void __fastcall TForm1::Button1Click(TObject *Sender) {
    DWORD BytesNeeded, ServicesReturned, ResumeHandle = 0;
    BOOL ReturnFlag;
    ENUM_SERVICE_STATUS *lpServices = new ENUM_SERVICE_STATUS[100];
    ENUM_SERVICE_STATUS Service;

    ListBox1->Items->Clear();
    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
    if (!hSCManager) { ShowMessage("無法開啟 SCM"); return; }

    ReturnFlag = EnumServicesStatus(hSCManager, SERVICE_DRIVER, SERVICE_ACTIVE,
        &Service, sizeof(Service), &BytesNeeded, &ServicesReturned, &ResumeHandle);

    if (!ReturnFlag && GetLastError() == ERROR_MORE_DATA) {
        DWORD BufSize = BytesNeeded + sizeof(ENUM_SERVICE_STATUS);
        EnumServicesStatus(hSCManager, SERVICE_DRIVER, SERVICE_ACTIVE,
            lpServices, BufSize, &BytesNeeded, &ServicesReturned, &ResumeHandle);
        for (DWORD i = 0; i < ServicesReturned; i++)
            ListBox1->Items->Add(lpServices[i].lpServiceName);
    }
    delete[] lpServices;
}

void __fastcall TForm1::Button2Click(TObject *Sender) {
    for (int i = 0; i < ListBox1->Items->Count; i++) {
        if (ListBox1->Selected[i]) {
            hService = OpenService(hSCManager,
                ListBox1->Items->Strings[i].c_str(), SERVICE_ALL_ACCESS);
            if (!hService) { ShowMessage("無法開啟服務"); return; }
            QueryServiceStatus(hService, &ReturnStatus);
            if (ReturnStatus.dwCurrentState == SERVICE_STOPPED) {
                if (StartService(hService, 0, NULL))
                    ShowMessage("啟動成功!");
                else
                    ShowMessage("無法啟動服務!");
            }
            CloseServiceHandle(hService);
        }
    }
}

void __fastcall TForm1::Button3Click(TObject *Sender) {
    for (int i = 0; i < ListBox1->Items->Count; i++) {
        if (ListBox1->Selected[i]) {
            hService = OpenService(hSCManager,
                ListBox1->Items->Strings[i].c_str(), SERVICE_ALL_ACCESS);
            if (!hService) { ShowMessage("無法開啟服務"); return; }
            QueryServiceStatus(hService, &ReturnStatus);
            if (ReturnStatus.dwCurrentState == SERVICE_RUNNING) {
                if (ControlService(hService, SERVICE_CONTROL_STOP, &ReturnStatus))
                    ShowMessage("成功停止!");
                else
                    ShowMessage("無法停止服務!");
            }
            CloseServiceHandle(hService);
        }
    }
}

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) {
    CloseServiceHandle(hSCManager);
}

三、進階主題與注意事項

  • 權限需求:操作服務需管理員權限,建議在 Manifest 中宣告 requireAdministrator。
  • 服務相依性:啟動服務前應檢查相依服務是否已啟動(EnumDependentServices)。
  • 自訂服務開發:需實作 ServiceMain、HandlerEx、向 SCM 註冊(CreateService),另文詳述。
  • 遠端管理:OpenSCManager 指定機器名稱即可管理遠端電腦服務(需 RPC 通訊權限)。
  • 錯誤處理:所有 API 失敗時必須檢查 GetLastError(),常見錯誤碼:ERROR_ACCESS_DENIED、ERROR_SERVICE_DOES_NOT_EXIST、ERROR_SERVICE_ALREADY_RUNNING。

掌握 SCM API,即可在應用程式中無縫整合 Windows 服務管理功能,構建企業級系統管理工具。

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