應用程式常需以程式控制服務啟動/停止(如 IIS 的 W3SVC、資料庫服務)。本文示範使用服務控制管理器 API 完整流程:開啟 SCM、開啟服務、查詢狀態、啟動/停止、等待狀態轉換完成。
#include
void StartStopWebService()
{
// 1. 開啟服務控制管理器
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, GENERIC_EXECUTE);
if (!hSCM) { TRACE(_T("OpenSCManager 失敗: %d\n"), GetLastError()); return; }
// 2. 開啟目標服務 (需 START/STOP/QUERY 權限)
SC_HANDLE hSvc = OpenService(hSCM, _T("W3SVC"),
SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS);
if (!hSvc) { TRACE(_T("OpenService 失敗: %d\n"), GetLastError());
CloseServiceHandle(hSCM); return; }
// 3. 取得目前狀態
SERVICE_STATUS status;
if (!QueryServiceStatus(hSvc, &status)) {
TRACE(_T("QueryServiceStatus 失敗\n"));
CloseServiceHandle(hSvc); CloseServiceHandle(hSCM); return;
}
// 4. 依狀態決定啟動或停止
if (status.dwCurrentState == SERVICE_RUNNING) {
// --- 停止服務 ---
if (!ControlService(hSvc, SERVICE_CONTROL_STOP, &status)) {
TRACE(_T("ControlService STOP 失敗\n"));
} else {
// 等待真正停止
while (QueryServiceStatus(hSvc, &status)) {
if (status.dwCurrentState == SERVICE_STOPPED) {
AfxMessageBox(_T("服務已停止"));
break;
}
Sleep(status.dwWaitHint > 0 ? status.dwWaitHint : 1000);
}
}
}
else if (status.dwCurrentState == SERVICE_STOPPED) {
// --- 啟動服務 ---
if (!StartService(hSvc, 0, NULL)) {
TRACE(_T("StartService 失敗: %d\n"), GetLastError());
} else {
while (QueryServiceStatus(hSvc, &status)) {
if (status.dwCurrentState == SERVICE_RUNNING) {
AfxMessageBox(_T("服務已啟動"));
break;
}
Sleep(status.dwWaitHint > 0 ? status.dwWaitHint : 1000);
}
}
}
// 5. 清理
CloseServiceHandle(hSvc);
CloseServiceHandle(hSCM);
}
| API | 用途 | 關鍵參數 |
|---|---|---|
OpenSCManager | 連線服務控制管理器 | 機器名(NULL=本機)、資料庫名(NULL=預設)、存取權限 |
OpenService | 取得服務控制代碼 | SCM 控制代碼、服務名稱、存取權限 |
QueryServiceStatus | 取得服務目前狀態 | 服務控制代碼、輸出 SERVICE_STATUS |
StartService | 啟動服務 | 服務控制代碼、引數個數、引數陣列 |
ControlService | 發送控制碼 | 服務控制代碼、控制碼(SERVICE_CONTROL_STOP 等)、輸出狀態 |
CloseServiceHandle | 關閉控制代碼 | SCM 或服務控制代碼 |
OpenService 會傳回 ERROR_ACCESS_DENIED (5)。W3SVC)可用 services.msc 或 sc query 確認。單純 Sleep 輪詢會阻塞 UI 執行緒。建議:
PostMessage 通知 UI 狀態變化。WaitForSingleObject 搭配服務專用事件(需服務支援)。