說明
第一個程序是服務,第二個程序控制服務 好像需要管理員權限,不然啟動失敗..
效果
服務程序 名字是 MiSaKaService.exe 在同一個文件夾中
源碼
#include
SERVICE_STATUS SplSrvServiceStatus;
SERVICE_STATUS_HANDLE SplSrvServiceStatusHandle;
VOID SvcDebugOut(LPSTR String, DWORD Status);
VOID WINAPI SplSrvServiceCtrlHandle(DWORD opcode);
VOID WINAPI SplSrvServiceStart(DWORD argc, LPTSTR *argv);
DWORD SplSrvServiceInitialization(DWORD argc, LPTSTR *argv, DWORD *specificError);
//啟動服務函數
VOID WINAPI SplSrvServiceStart(DWORD argc, LPTSTR *argv){
DWORD status;
DWORD specificError;
//填充結構
SplSrvServiceStatus.dwServiceType = SERVICE_WIN32;
SplSrvServiceStatus.dwCurrentState = SERVICE_START_PENDING;//服務在運行
SplSrvServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
SplSrvServiceStatus.dwWin32ExitCode = 0;
SplSrvServiceStatus.dwServiceSpecificExitCode = 0;
SplSrvServiceStatus.dwCheckPoint = 0;
SplSrvServiceStatus.dwWaitHint = 0;
//注冊服務控制請求處理例程
SplSrvServiceStatusHandle = RegisterServiceCtrlHandler(
"MiSaKaService",//服務名
//SERVICE_WIN32_OWN_PROCESS在插件服務時使用了,所以本參數忽略
SplSrvServiceCtrlHandle//控制請求處理函數名
);
if (SplSrvServiceStatusHandle == (SERVICE_STATUS_HANDLE)0){
SvcDebugOut("注冊服務失敗: %d\n", GetLastError());
return;
}
//初始化,本示例未使用,函數為空
status = SplSrvServiceInitialization(argc, argv, &specificError);
//初始化失敗
if (status != NO_ERROR){
SplSrvServiceStatus.dwCurrentState = SERVICE_STOPPED;
SplSrvServiceStatus.dwCheckPoint = 0;
SplSrvServiceStatus.dwWaitHint = 0;
SplSrvServiceStatus.dwWin32ExitCode = status;
SplSrvServiceStatus.dwServiceSpecificExitCode = specificError;
SetServiceStatus(SplSrvServiceStatusHandle, &SplSrvServiceStatus);
return;
}
//初始化完成,設置運行狀態
SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING;
SplSrvServiceStatus.dwCheckPoint = 0;
SplSrvServiceStatus.dwWaitHint = 0;
if (!SetServiceStatus(SplSrvServiceStatusHandle, &SplSrvServiceStatus)){
status = GetLastError();
SvcDebugOut("服務初始化失敗: %d\n", status);
}
//自行修改,用戶完成服務的工作
SvcDebugOut("MiSaKa Servise 運行主線程\n", 0);
return;
}
//初始化工作,這里未進行任何工作,帶讀者修改
DWORD SplSrvServiceInitialization(DWORD argc, LPTSTR *argv, DWORD *specificError){
return 0;
}
//服務控制請求處理函數,與ControlService函數配合
VOID WINAPI SplSrvServiceCtrlHandle(DWORD opcode){
DWORD status;
switch (opcode){
case SERVICE_CONTROL_PAUSE:
//完成相關功能
SplSrvServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
//完成相關功能
SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
//完成相關功能
SplSrvServiceStatus.dwWin32ExitCode = 0;
SplSrvServiceStatus.dwCurrentState = SERVICE_STOPPED;
SplSrvServiceStatus.dwCheckPoint = 0;
SplSrvServiceStatus.dwWaitHint = 0;
if (!SetServiceStatus(SplSrvServiceStatusHandle, &SplSrvServiceStatus)){
status = GetLastError();
SvcDebugOut("設置服務狀態錯誤 %ld\n", status);
}
SvcDebugOut("MiSaKa Service 服務結束,控制碼 %ld\n ", opcode);
break;
case SERVICE_CONTROL_INTERROGATE:
//完成相關功能 收到此請求發出響聲,演示服務控制請求的處理過程,可執行修改
MessageBeep(MB_OK);
break;
default:
SvcDebugOut("未知的控制指令 %ld\n", opcode);
}
//當前狀態
if (!SetServiceStatus(SplSrvServiceStatusHandle, &SplSrvServiceStatus)){
status = GetLastError();
SvcDebugOut("設置服務狀態錯誤 %ld\n", status);
}
return;
}
//顯示信息給調試器
VOID SvcDebugOut(LPSTR String, DWORD Status){
CHAR Buffer[1024];
if (strlen(String)< 1000){
wsprintf(Buffer, String, Status);
OutputDebugString(Buffer);
}
}
//主函數
void main(){
//設置SERVICE_TABLE_ENTRY結構,以NULL結束
//作為StartServiceCtrlDispatcher函數的參數
SERVICE_TABLE_ENTRY DispatchTable[] = {
{ "MiSaKaService" ,(LPSERVICE_MAIN_FUNCTION)SplSrvServiceStart},
{NULL,NULL}
};
if (!StartServiceCtrlDispatcher(DispatchTable)){
SvcDebugOut("MiSaKa Service StartServiceCtrlDispatcher 錯誤 %d\n", GetLastError());
}
}
源碼
#include
#include
SC_HANDLE schService;//全局服務句柄
SC_HANDLE schSCManager;//SCM句柄
LPTSTR szServiceName = TEXT("MiSaKaService");//服務名
//創建服務 SCM句柄 服務程序路徑 服務名
BOOL CreateSampleService(SC_HANDLE schSCManager, LPTSTR szPath, LPSTR szServiceName){
schService = CreateService(
schSCManager,//SCM句柄
szServiceName,//服務名
TEXT("御坂網絡服務"),//顯示的服務名
SERVICE_ALL_ACCESS,//存取權限
SERVICE_WIN32_OWN_PROCESS,//服務類別
SERVICE_DEMAND_START,//啟動類別
SERVICE_ERROR_NORMAL,//錯誤控制類別
szPath,//服務的可執行文件路徑
NULL,//不屬于任何用戶組
NULL,//使用已存在的標簽
NULL,//獨立服務
NULL,//本地系統賬戶
NULL//密碼為空
);
if (schService == NULL){
printf("創建服務失敗 %d\n", GetLastError());
return FALSE;
} else{
printf("創建服務成功\n");
CloseServiceHandle(schService);
return TRUE;
}
}
//刪除服務 服務的名字
BOOL DeleteSampleService(LPTSTR szNameOfService){
schService = OpenService(
schSCManager,//SCM句柄
szNameOfService,//服務名
DELETE//可刪除
);
if (schService == NULL){
printf("打開服務失敗 %d\n", GetLastError());
return FALSE;
}
//刪除服務
if (!DeleteService(schService)){
printf("刪除服務失敗 %d\n", GetLastError());
return FALSE;
} else{
printf("刪除服務成功\n");
}
CloseServiceHandle(schService);
return TRUE;
}
//啟動服務 SCM句柄 服務名
BOOL StartSampleService(SC_HANDLE schSCManager, LPTSTR szServiceName){
SC_HANDLE schService;
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
DWORD dwBytesNeeded;
//打開服務
schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
if (schService == NULL){
return 0;
}
//啟動服務
if (!StartService(
schService,//服務的句柄
0,//參數個數為0
NULL//參數指針為NULL,沒有參數
)){
printf("啟動服務失敗 %u", GetLastError());
return 0;
} else{
printf("服務啟動成功...\n");
}
//驗證狀態
if (!QueryServiceStatusEx(
schService,//服務的句柄
SC_STATUS_PROCESS_INFO,//服務狀態信息
&ssStatus,//結構體地址
sizeof(SERVICE_STATUS_PROCESS),//結構體大小
&dwBytesNeeded//存儲狀態信息所用的字節數
)){
return 0;
}
//tick count & checkpoint
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
//查詢狀態,確定PENDING狀態結束
while (ssStatus.dwCurrentState == SERVICE_START_PENDING){
//等待一段時間愛你
dwWaitTime = ssStatus.dwWaitHint / 10;
if (dwWaitTime< 1000){
dwWaitTime = 1000;
} else if (dwWaitTime>10000){
dwWaitTime = 10000;
}
Sleep(dwWaitTime);
//再次查詢
if (!QueryServiceStatusEx(
schService,//服務的句柄
SC_STATUS_PROCESS_INFO,//服務狀態信息
&ssStatus,//結構體地址
sizeof(SERVICE_STATUS_PROCESS),//結構體大小
&dwBytesNeeded//存儲狀態信息所用的字節數
)){
break;
}
if (ssStatus.dwCheckPoint>dwOldCheckPoint){
//進程創建中
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
} else{
if (GetTickCount() - dwStartTickCount>ssStatus.dwWaitHint){
//WaitHint 時間到
break;
}
}
}
//關閉句柄
CloseServiceHandle(schService);
//判斷是否創建成功 狀態由 PENDING 變為 RUNNING
if (ssStatus.dwCurrentState == SERVICE_RUNNING){
printf("創建服務成功\n");
return 1;
} else{
printf("創建服務失敗:\n");
printf("當前開始 %d\n", ssStatus.dwCurrentState);
printf("退出代碼 %d\n", ssStatus.dwWin32ExitCode);
printf("服務特定退出代碼 %d\n", ssStatus.dwServiceSpecificExitCode);
printf("檢查點 %d\n", ssStatus.dwCheckPoint);
printf("等待提示 %d\n", ssStatus.dwWaitHint);
return 0;
}
}
//向服務發送控制碼
BOOL ControlSampleService(DWORD fdwControl){
SERVICE_STATUS ssStatus;
DWORD fdwAccess;
DWORD dwStartTickCount;
DWORD dwWaitTime;
switch (fdwControl){
case SERVICE_CONTROL_STOP:
fdwAccess = SERVICE_STOP;
break;
case SERVICE_CONTROL_PAUSE:
caseSERVICE_CONTROL_CONTINUE:
fdwAccess = SERVICE_PAUSE_CONTINUE;
break;
case SERVICE_CONTROL_INTERROGATE:
fdwAccess = SERVICE_INTERROGATE;
break;
default:
fdwAccess = SERVICE_INTERROGATE;
}
//打開服務
schService = OpenService(
schSCManager,//SCM句柄
szServiceName,//服務名
fdwAccess//存取權限
);
if (schService == NULL){
printf("打開服務失敗 %d\n", GetLastError());
return FALSE;
}
//發送控制碼
if (!ControlService(
schService,//服務句柄
fdwControl,//控制碼
&ssStatus//狀態
)){
printf("控制服務失敗 %d\n", GetLastError());
return FALSE;
}
//顯示狀態
printf("御坂網絡服務狀態:\n");
printf("服務類型 0x%x\n", ssStatus.dwServiceType);
printf("當前狀態 0x%x\n", ssStatus.dwCurrentState);
printf("接受控制 0x%x\n", ssStatus.dwControlsAccepted);
printf("退出代碼 %d\n", ssStatus.dwWin32ExitCode);
printf("服務特定退出代碼 %d\n", ssStatus.dwServiceSpecificExitCode);
printf("檢查點 %d\n", ssStatus.dwCheckPoint);
printf("等待提示 %d\n", ssStatus.dwWaitHint);
return TRUE;
}
//停止服務 SCM句柄 服務名 是否結束依賴的服務 超時
DWORD StopService(SC_HANDLE hSCM, LPTSTR szServiceName, BOOL fStopDependencies, DWORD dwTimeout){
SERVICE_STATUS_PROCESS ssp;
SERVICE_STATUS ss;
DWORD dwStartTime = GetTickCount();
DWORD dwBytesNeeded;
//打開服務
SC_HANDLE hService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS);
//查詢狀態,確定是否已經停止
if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){
return GetLastError();
}
if (ssp.dwControlsAccepted == SERVICE_STOPPED){
return ERROR_SUCCESS;
}
//如果是STOP_PENDING狀態,則只需等待
while (ssp.dwCurrentState == SERVICE_STOP_PENDING){
Sleep(ssp.dwWaitHint);
//循環查詢,知道狀態改變
if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){
return GetLastError();
}
if (ssp.dwCurrentState == SERVICE_STOPPED){
return ERROR_SUCCESS;
}
if (GetTickCount() - dwStartTime>dwTimeout){
return ERROR_TIMEOUT;
}
}
//先結束依賴服務
if (fStopDependencies){
DWORD i;
DWORD dwBytesNeeded;
DWORD dwCount;
LPENUM_SERVICE_STATUS lpDependencies = NULL;
ENUM_SERVICE_STATUS ess;
SC_HANDLE hDepService;
//使用0大小的buf,獲取buf的大小
//如果EnumDependentServices函數返回從,說明沒有依賴服務
if (!EnumDependentServices(hService, SERVICE_ACTIVE, lpDependencies, 0, &dwBytesNeeded, &dwCount)){
if (GetLastError() != ERROR_MORE_DATA){
return GetLastError();//意外的錯誤
}
lpDependencies = (LPENUM_SERVICE_STATUS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded);
if (!lpDependencies){
return GetLastError();
}
//獲得依賴服務
if (!EnumDependentServices(hService, SERVICE_ACTIVE, lpDependencies, dwBytesNeeded, &dwBytesNeeded, &dwCount)){
return GetLastError();
}
for (i = 0; i< dwCount; i++){
ess = *(lpDependencies + i);
//打開服務
hDepService = OpenService(hSCM, ess.lpServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS);
if (!hDepService){
return GetLastError();
}
//結束服務
if (!ControlService(hDepService, SERVICE_CONTROL_STOP, &ss)){
return GetLastError();
}
//等待服務結束
while (ss.dwCurrentState != SERVICE_STOPPED){
Sleep(ss.dwWaitHint);
if (!QueryServiceStatusEx(hDepService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){
if (ss.dwCurrentState == SERVICE_STOPPED){
break;
}
if (GetTickCount() - dwStartTime>dwTimeout){
return ERROR_TIMEOUT;
}
}
}
//關閉服務
CloseServiceHandle(hDepService);
}
//是否內存
HeapFree(GetProcessHeap(), 0, lpDependencies);
}
}
//所有依賴服務以及結束,技術指定服務
if (!ControlService(hService, SERVICE_CONTROL_STOP, &ss)){
return GetLastError();
}
while (ss.dwCurrentState != SERVICE_STOPPED){
Sleep(ss.dwWaitHint);
if(!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)){
return GetLastError();
}
if (ss.dwCurrentState == SERVICE_STOPPED){
break;
}
if (GetTickCount()-dwStartTime>dwTimeout){
return ERROR_TIMEOUT;
}
}
return ERROR_SUCCESS;
}
int main(int argc, TCHAR *argv[]){
TCHAR szBinFilePath[MAX_PATH];
PTCHAR pTemp;
DWORD dwStopError;
//構造服務可執行程序的路徑
GetModuleFileName(NULL, szBinFilePath, MAX_PATH);
pTemp = szBinFilePath + lstrlen(szBinFilePath);
while (*--pTemp != '\\');
lstrcpy(pTemp, TEXT("\\MiSaKaService.exe"));
//打開SCM
schSCManager = OpenSCManager(
NULL,//本機
NULL,//ServicesActive數據庫
SC_MANAGER_ALL_ACCESS//完全存取權限
);
if (schSCManager == NULL){
printf("打開SCM失敗 %d\n", GetLastError());
}
//創建服務
CreateSampleService(schSCManager, szBinFilePath, szServiceName);
//啟動服務
StartSampleService(schSCManager, szServiceName);
//發送請求控制
ControlSampleService(SERVICE_CONTROL_INTERROGATE);
ControlSampleService(SERVICE_CONTROL_CONTINUE);
//停止服務
dwStopError = StopService(schSCManager, szServiceName, TRUE, 1000);
if (dwStopError == ERROR_SUCCESS){
printf("服務成功停止\n");
} else{
printf("服務停止失敗\n");
}
//刪除服務
DeleteSampleService(szServiceName);
CloseServiceHandle(schSCManager);
getchar();
return 0;
}