在windows中,服務是一種特殊的程序,可以說它和使用者無關,它的作用不是完成使用者任務,而是進行一些管理類的操作或者通用的服務類操作,實際上windows服務就是一個可執行檔案,但是遠遠不隻是這些。
Windows NT的服務架構非常複雜,是整個系統架構中獨立的一塊。windows服務執行的往往都是一些無須使用者介入的任務,也就是說它執行的任務不是具體的,而是具有支撐性質的,比較底層的,比如網絡登入,檔案驅動,裝置驅動,ftp等等,其他的程序往往就和登入使用者密切相關了,畢竟計算機就是讓使用者使用的,而其上執行的任務也就是使用者要求的,是以使用者是windows程序一個很重要的屬性,同時也是作業系統本身一個很重要的性質,可以實作安全管理等相關操作。
windows服務主要由三部分組成,一是服務本身;二是服務控制管理器(SCM);三是服務控制程式(SCP)。SCM是個管理中心,管理着所有的線上服務,所謂線上服務就是已經安裝的服務,SCP和SCM互動來管理服務本身,注意服務本身并不需要直接和SCM互動,這樣就可以讓寫一個服務變得更加容易,人們可以像寫普通的應用程式一樣來完成一個服務的程式設計,唯一需要附加的就是和SCP接口就可以了,這樣看來雖然windows服務的架構非常複雜,但是三者之間的耦合度卻很低,足見設計的精妙。SCM維護着一個資料庫,該資料庫儲存着已安裝的服務和驅動程式的資訊,SCM管理着它們,SCM根據這些資訊控制服務的關閉和啟動等行為,服務可以從SCM接收指令然後采取一定的動作,注意它是通過SCP來接收指令的,服務本身就是一個一直運作的應用程式,SCP作為一個 接口提供出來,使用者可以通過它控制服務的行為,SCM同時也和SCP互動,在這繁複的資料流背後是成熟的RPC,windows中信号是不流行的,但是RPC卻非常普遍,下面通過一個簡單例子說明一下枝枝蔓蔓:
#include "stdafx.h"
#include.h>
void Install(char * name);
void Uninstall(char *name);
char *a = "mee11";
BOOL Running = TRUE;
SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS status;
SC_HANDLE hSCM;
int option(int argc, TCHAR* argv[])
{
hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (argc <= 1) return 0;
if (_wcsicmp(argv[1], _T("-i")) == 0)
Install(a);
::CloseServiceHandle(hSCM);
return 1;
}
if (_wcsicmp(argv[1], _T("-u")) == 0)
Uninstall(a);
return 0;
void Install(char *name ) //安裝服務,實際上就是将該新服務的資訊寫入SCM管理的資料庫中
if (!hSCM) return 0;
char szFilePath[260];
::GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath));
SC_HANDLE hService = ::CreateServiceA(hSCM,(LPCSTR)name,(LPCSTR)name,SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,szFilePath,NULL,NULL,NULL,NULL,NULL);
if (!hService) {
return ;
char szKey[256];
HKEY hKey = NULL;
strcpy(szKey, "SYSTEM//CurrentControlSet//Services//EventLog//Application//");
strcat(szKey, name);
if (::RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) {
::CloseServiceHandle(hService);
return;
::RegSetValueEx(hKey,_T("EventMessageFile"),0,REG_EXPAND_SZ, (CONST BYTE*)szFilePath,strlen(szFilePath) + 1);
DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
::RegSetValueEx(hKey,_T("TypesSupported"),0,REG_DWORD,(CONST BYTE*)&dwData,sizeof(DWORD));::RegCloseKey(hKey);
void Uninstall(char *name)
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return ;
SC_HANDLE hService = ::OpenServiceA(hSCM,name,DELETE);
if (hService) {
if (::DeleteService(hService))
static void WINAPI Handler(DWORD dwOpcode)
{ //注意是在這個Handler回調中處理的SCM發來的指令,這裡要做的就是設定控制變量,間接改變服務的運作行為。
switch (dwOpcode) {
case SERVICE_CONTROL_STOP:
status.dwCurrentState = SERVICE_STOP_PENDING;
::SetServiceStatus(hServiceStatus, &status);
Running = FALSE;
break;
default:
static void WINAPI ServiceMaina(DWORD dwArgc, LPTSTR* lpszArgv)
hServiceStatus = RegisterServiceCtrlHandlerA(a,Handler);
status.dwCurrentState = SERVICE_RUNNING;
while (Running)
//做具體的服務吧,就像這是一個普通的應用程式一樣
::SetServiceStatus(hServiceStatus, &status);//最後告訴SCM,這個服務停止了。
void StartService()
SERVICE_TABLE_ENTRY st[] = {
{(LPWSTR)a, ServiceMain},{NULL, NULL}};
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwCurrentState = SERVICE_STOPPED;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
status.dwWin32ExitCode = 0;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
::StartServiceCtrlDispatcher(st);//分派器開始,服務即将開始運作
int _tmain(int argc, _TCHAR* argv[])
if(!option(argc, argv))
StartService();
看到在RegisterServiceCtrlHandlerA中注冊的Handler了吧,Handler就相當于一個控制器,這個Handler就是負責接收和處理指令的,它和主服務在不同的線程當中,主服務也就是上面例子中的while循環線程可以旁若無人的做任何事情,控制變量是全局的,可以在别的線程被改變,這個變量控制着服務的關閉行為,一切就是這麼簡單。關于服務的調試,可以用遠端調試的辦法進行。
windows專門為服務這個東西設計了如此複雜的機制,看得出服務的重要性,不過也不一定,windows本身就是微核結構而且内部大量使用了C/S架構,它為任何東西單獨設計一個機制都不足為奇。它的API相當複雜,之是以這樣就使因為windows是面向使用者的,而使用者是很難纏的,是以其api就提供了很多政策性的東西,當然也就相對複雜,windows服務僅僅是其中的一塊而已,不過即使這樣,windows的設計者還是做的很不錯,程式員幾乎不用費力就可以完成一個服務架構,當然如果深入一些,還有更加複雜的,不過那就涉及到一個新機制了,這就是svchost,很熟悉吧,不過不說了,我不喜歡讨論網上一搜一堆的東西,我比較喜歡思想性的東西,最起碼還可能遭到一些反駁...
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1273461