Windows 服務程序簡介:

int main(void) { SERVICE_TABLE_ENTRYA ServTable[2]; // 創建服務分派表。 ServTable[0].lpServiceName = "Test"; // 服務名稱。類似於 Win32 應用程序的窗口名稱。每個服務代表一項功能。 ServTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; //服務入口函數。 ServTable[1].lpServiceName = NULL; // 每一個服務分派表代表一個服務,分派表的最后一項必須是服務名和服務主函數域的 NULL 指針。 ServTable[1].lpServiceProc = NULL; // 我們稱之為“哨兵”(所有值都為NULL),表示該服務表末尾。 StartServiceCtrlDispatcher(ServTable); // 啟動控制分派機制。
return 0; }
SERVICE_TABLE_ENTRYA 結構體:
typedef struct _SERVICE_TABLE_ENTRYA { LPSTR lpServiceName; // 服務名稱。 LPSERVICE_MAIN_FUNCTIONA lpServiceProc; // 服務入口函數。 } SERVICE_TABLE_ENTRYA, *LPSERVICE_TABLE_ENTRYA;
StartServiceCtrlDispatcher() 介紹 :
功能:連接程序主線程到服務控制管理程序。
BOOL StartServiceCtrlDispatcher( CONST SERVICE_TABLE_ENTRYA *lpServiceStartTable // SERVICE_TABLE_ENTRYA 結構體變量。 );
返回值:非零表示成功,零表示失敗。
服務控制管理器 (SCM:Services Control Manager) 是一個管理系統所有服務的進程。
當 SCM 啟動某個服務時,它等待某個進程的主線程來調用 StartServiceCtrlDispatcher 函數,
將分派表傳遞給 StartServiceCtrlDispatcher。
這將把調用進程的主線程轉換為控制分派器。該分派器啟動一個新線程,
該線程運行分派表中每個服務的 ServiceMain 函數分派器還監視程序中所有服務的執行情況。
然后分派器將控制請求從 SCM 傳給服務。
分派表中所有的服務執行完之后,或者發生錯誤時。StartServiceCtrlDispatcher 調用返回。然后主進程終止。
SCM 開始啟動一個服務程序時,總是等待這個服務程序去調用 StartServiceCtrlDispatcher()。
而當服務開始運行時,main() 將會調用 ServiceMain(), 直到 ServiceMain() 執行完畢或發生錯誤而退出,
StartServiceCtrlDispatcher() 返回,主線程將會終止。
ServiceMain() 服務入口函數,它的作用就是:將你需要執行的任務放到該函數中循環執行即可。這就是服務程序的工作函數。
在ServiceMain執行你的任務前,需要給SERVICE_TABLE_ENTRY 分派表結構體進行賦值。
典型代碼如下:
// SERVICE_STATUS ServiceStatus; //這段代碼應聲明為全局變量,因多處使用。
// SERVICE_STATUS_HANDLE hStatus; //這段代碼應聲明為全局變量,因多處使用。
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv) { // 初始化狀態設置。 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; // 即服務目前狀態為 正在初始化。 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
// 這個通知 SCM 服務接收哪個域。本例包含 停止,暫停和繼續,關機等命令。 ServiceStatus.dwWin32ExitCode = 0; // 這個域在終止服務並報告細節時很有用。下面這四個值一般不用關心,通常設置為 0。 ServiceStatus.dwCheckPoint = 0; // 用來報告它當前的事件進展情況的。 ServiceStatus.dwServiceSpecificExitCode = 0; // 這個域在終止服務並報告細節時也很有用。 ServiceStatus.dwWaitHint = 0; // 根據初始化過程的長短而定。 // 注冊控制函數。 hStatus = RegisterServiceCtrlHandler("ServiceName", // 注冊服務控制程序,注冊成功后將會返回一個服務狀態句柄。 (LPHANDLER_FUNCTION)ServiceHandler); // ServiceHandle 是服務控制程序。類似與 Windows 應用程序的窗口過程。 if (!hStatus)
{
printf("Register Service Error!\n");
system("pause"); return;
}
SetServiceStatus(hStatus, &ServiceStatus); // 設置服務狀態。通過調用 SetServiceStatus 函數,向 SCM 報告服務的狀態。
if (GetLastError != NO_ERROR) // 返回調用線程最近的錯誤代碼值,檢查是否出錯。 { // 如果出錯,將其重設為停止狀態。 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus);
printf("Start Error!\n");
system("pause"); return; }
// 沒有錯誤就繼續運行。
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);
// 創建線程執行特定功能
HANDLE hThread = CreateThread(NULL, 0, MyWork, NULL, 0, NULL); // MyWOrk 是特定功能的函數,如后門程序。
if(hThread = NULL)
return; }
SERVICE_STATUS 結構體:
typedef struct _SERVICE_STATUS { DWORD dwServiceType; // 服務類型。 DWORD dwCurrentState; // 服務的當前狀態。 DWORD dwControlsAccepted; // 服務在其處理函數中接受和處理的控制代碼。 DWORD dwWin32ExitCode; // 服務用於報告啟動或停止時發生錯誤的錯誤代碼。 DWORD dwServiceSpecificExitCode; // 服務在啟動或停止時發生錯誤時返回的錯誤代碼。 DWORD dwCheckPoint; // 服務在長時間啟動、停止、暫停或繼續操作期間定期遞增以報告其進度的檢查點值。 DWORD dwWaitHint; // 將要進行 開始、停止、暫停或繼續服務 操作所需的估計時間 (以毫秒為單位)。 } SERVICE_STATUS, *LPSERVICE_STATUS;
dwServiceType 的值:(可組合)
值 | 含義 |
SERVICE_FILE_SYSTEM_DRIVER | 該服務是一個文件系統驅動程序 |
SERVICE_KERNEL_DRIVER | 該服務是一個設備驅動程序 |
SERVICE_WIN32_OWN_PROCESS | 服務在自己的進程中運行(通常使用這個) |
SERVICE_USER_OWN_PROCESS | 該服務在登錄用戶帳戶下在其自己的進程中運行 |
dwCurrentState 的值:
值 | 含義 |
SERVICE_CONTINUE_PENDING | 服務處於從暫停狀態恢復的過程中 |
SERVICE_PAUSE_PENDING | 服務正在暫停過程中,但還有沒完全進入暫停狀態 |
SERVICE_PAUSED | 服務已經暫停了 |
SERVICE_RUNNING | 服務正在運行了 |
SERVICE_START_PENDING | 服務在啟動過程中,但還沒有准備好對請求進行響應 |
SERVICE_STOP_PENDING | 服務正在停止過程中,但還沒有完全進入停止狀態 |
SERVICE_STOPPED | 服務已經停止了 |
dwControlsAccepted 的值: (可組合)
值 | 含義 |
---|---|
SERVICE_ACCEPT_NETBINDCHANGE | 該服務是一個網絡組件,並且能夠在服務在服務不重啟的情況下,改變其所網絡接收的綁定,接收SERVICE_CONTROL_NETBINDADD、SERVICE_CONTROL_NETBINDREMOVE、SERVICE_CONTROL_NETBINDENABLE、SERVICE_CONTROL_NETBINDDISABLE 的通知 |
SERVICE_ACCEPT_PARAMCHANGE | 服務在不重啟的情況下能夠重新讀取其配置參數,接收 SERVICE_CONTROL_PARAMCHANGE 通知 |
SERVICE_ACCEPT_PAUSE_CONTINUE | 服務支持暫停和重啟,服務能夠接收到 SERVICE_CONTROL_PAUSE 和SERVICE_CONTROL_CONTINUE的通知 |
SERVICE_ACCEPT_PRESHUTDOWN | 系統在關閉前,能夠收到系統的 SERVICE_CONTROL_PRESHUTDOWN 通知,用來處理一些關閉前的清理,xp之前不支持此控制碼 |
SERVICE_ACCEPT_SHUTDOWN | 能夠接收系統退出時的 SERVICE_CONTROL_SHUTDOWN 的通知,以便處理一些回收 |
SERVICE_ACCEPT_STOP | 能夠接收 SERVICE_CONTROL_STOP 的通知來處理一些回收任務 |
SetServiceStatus() 介紹:
功能:更新服務控制管理器調用服務的狀態信息。
函數原型:BOOL SetServiceStatus(
SERVICE_STATUS_HANDLE hServiceStatus, //服務狀態信息結構的句柄, 由 RegisterServiceCtrlHandler() 返回。
LPSERVICE_STATUS lpServiceStatus // 指向 SERVICE_STATUS 結構的指針包含呼叫服務的最新狀態信息。
);
返回值:非零表示成功,零表示失敗。
RegisterServiceCtrlHandler() 介紹:
功能:注冊一個函數以處理服務控制請求。
函數原型:SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler(
LPCSTR lpServiceName, //調用線程運行的服務的名稱, 即在 CreateService() 中指定的服務控制程序的服務名稱。
LPHANDLER_FUNCTION lpHandlerProc // 指向要注冊的處理程序的函數。
);
返回值:如果函數成功, 則返回值為服務狀態句柄。如果函數失敗, 返回值為零。
CreateThread() 介紹:
功能:該函數在 主線程 的基礎上創建一個新線程。線程 終止運行后,
線程對象仍然在系統中,必須通過 CloseHandle() 來關閉該線程對象。
函數原型:HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
參數:
lpThreadAttributes
指向 SECURITY_ATTRIBUTES 結構的指針, 它確定返回的句柄是否可以由子進程繼承。
如果 lpThreadAttributes 為 NULL, 則無法繼承句柄。
dwStackSize
堆棧的初始大小 (以字節為單位)。系統將此值舍入到最近的頁面。
如果此參數為零, 則新線程將使用可執行文件的默認大小。
lpStartAddress
指向要由線程執行的應用程序定義的函數。此指針表示線程的起始地址。
lpParameter
指向要傳遞給線程的變量的指針。
dwCreationFlags
控制線程創建的標志。通常情況下為 0。
lpThreadId
指向接收線程標識符的變量的指針。如果此參數為 NULL, 則不返回線程標識符。
返回值:如果函數成功, 則返回值是新線程的句柄。如果函數失敗, 返回值為 NULL。
ServiceHandle() 服務控制函數,典型代碼如下:
void WINAPI ServiceHandler(DWORD fdwControl) { switch (fdwControl) { case SERVICE_CONTROL_PAUSE: ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); return;
default: break; } SetServiceStatus(hStatus, &ServiceStatus); // 重設服務狀態。 return; }
入門代碼如下:(目前的代碼仍然不能當做服務來運行,還需要 SCM 進行安裝)
#include<stdio.h> #include<Windows.h> SERVICE_STATUS ServiceStatus; SERVICE_STATUS_HANDLE hStatus; void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv); void WINAPI ServiceHandler(DWORD fdwControl);
DWORD WINAPI MyWork(LPVOID lpParam); int main(void) { SERVICE_TABLE_ENTRY ServTable[2]; ServTable[0].lpServiceName = (LPSTR)"Test"; ServTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; ServTable[1].lpServiceName = NULL; ServTable[1].lpServiceProc = NULL; StartServiceCtrlDispatcher(ServTable); return 0; } void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) { ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwWaitHint = 0; hStatus = RegisterServiceCtrlHandler("ServiceName", (LPHANDLER_FUNCTION)ServiceHandler); if (!hStatus)
{
printf("Register Service Error!\n");
system("pause");
return;
}
SetServiceStatus(hStatus, &ServiceStatus); if (GetLastError() != NO_ERROR) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus);
printf("Start Service Error!\n");
system("pause"); return; }
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus, &ServiceStatus);
// 從這里開始可以放入你想服務為你所做的事情。
HANDLE hThread = CreateThread(NULL, 0, MyWork, NULL, 0, NULL);
if(hThread = NULL)
return; } void WINAPI ServiceHandler(DWORD fdwControl) { switch (fdwControl) { case SERVICE_CONTROL_PAUSE: ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); return;
default: break; } SetServiceStatus(hStatus, &ServiceStatus); return; }
DWORD WINAPI MyWork(LPVOID lpParam)
{
return 0;
}