使用C++Builder在WIN2000環(huán)境下編制Service
發(fā)表時(shí)間:2024-02-26 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]Windows 2000與Windows 9x有一個(gè)非常重要的區(qū)別,即Windows 2000提供了很多功能強(qiáng)大的Service(服務(wù))。這些Service可以隨著WIN2000的啟動(dòng)而自啟動(dòng),也可以讓用戶通過(guò)控制面板啟動(dòng),還可以被Win32應(yīng)用程序起停。甚至在沒(méi)有用戶登錄系統(tǒng)的情況下,這些Ser...
Windows 2000與Windows 9x有一個(gè)非常重要的區(qū)別,即Windows 2000提供了很多功能強(qiáng)大的Service(服務(wù))。這些Service可以隨著WIN2000的啟動(dòng)而自啟動(dòng),也可以讓用戶通過(guò)控制面板啟動(dòng),還可以被Win32應(yīng)用程序起停。甚至在沒(méi)有用戶登錄系統(tǒng)的情況下,這些Service也能執(zhí)行。許多FTP、WWW服務(wù)器和數(shù)據(jù)庫(kù)就是以Service的形式存在于WIN2000上,從而實(shí)現(xiàn)了無(wú)人值守。就連最新版的"黑客"程序Back Orifice 2000也是以Service形式在WIN2000上藏身的。由于Service的編程較復(fù)雜,許多開(kāi)發(fā)者想開(kāi)發(fā)自己的Service但往往都望而卻步。鑒于此,下面我們就從頭到尾來(lái)構(gòu)造一個(gè)全新的Service,讀者只要在程序中注明的地方加上自己的代碼,那么就可以輕松擁有一個(gè)自己的Service。在編寫(xiě)Service之前,先介紹一下幾個(gè)重要的函數(shù):
1. SC_HANDLE OpenSCManager( LPCTSTR lpMachineName, LPCTSTR lpDatabaseName, DWORD dwDesiredAccess)
OpenSCManager 函數(shù)打開(kāi)指定計(jì)算機(jī)上的service control manager database。其中參數(shù)lpMachineName指定計(jì)算機(jī)名,若為空則指定為本機(jī)。LpDatabaseName為指定要打開(kāi)的service control manager database名, 默認(rèn)為空。dwDesiredAccess指定操作的權(quán)限, 可以為下面取值之一:
SC_MANAGER_ALL_ACCESS //所有權(quán)限
SC_MANAGER_CONNECT //允許連接到service control manager database
SC_MANAGER_CREATE_SERVICE //允許創(chuàng)建服務(wù)對(duì)象并把它加入database
SC_MANAGER_ENUMERATE_SERVICE //允許枚舉database 中的Service
SC_MANAGER_LOCK //允許鎖住database
SC_MANAGER_QUERY_LOCK_STATUS //允許查詢database的封鎖信息
函數(shù)執(zhí)行成功則返回一個(gè)指向service control manager database的句柄,失敗則返回NULL。注意:WIN2000通過(guò)一個(gè)名為service control manager database的數(shù)據(jù)庫(kù)來(lái)管理所有的Service,因此對(duì)Service的任何操作都應(yīng)打開(kāi)此數(shù)據(jù)庫(kù)。
2. SC_HANDLE CreateService(SC_HANDLE hSCManager,
LPCTSTR lpServiceName,
LPCTSTR lpDisplayName,
DWORD dwDesiredAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCTSTR lpBinaryPathName,
LPCTSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCTSTR lpDependencies,
LPCTSTR lpServiceStartName,
LPCTSTR lpPassword)
CreatService函數(shù)產(chǎn)生一個(gè)新的SERVICE。其中參數(shù)hSCManager為指向service control manager database 的句柄,由OpenSCManager返回。LpServiceName為SERVICE的名字,lpDisplayName為Service顯示用名,dwDesiredAccess是訪問(wèn)權(quán)限,本程序中用SERVICE_ALL_ACCESS。wServiceType,指明SERVICE類型,本程序中用SERVICE_WIN32_OWN_PROCESS SERVICE_INTERACTIVE_PROCESS。dwStartType為Service啟動(dòng)方式,本程序采用自啟動(dòng),即dwStartType等于SERVICE_AUTO_START。 dwErrorControl說(shuō)明當(dāng)Service在啟動(dòng)中出錯(cuò)時(shí)采取什么動(dòng)作,本程序采用SERVICE_ERROR_IGNORE即忽約錯(cuò)誤,讀者可以改為其他的。LpBinaryPathName指明Service本體程序的路徑名。剩下的五個(gè)參數(shù)一般可設(shè)為NULL。如函數(shù)調(diào)用成功則返回這個(gè)新Service的句柄,失敗則返回NULL。與此函數(shù)對(duì)應(yīng)的是DeleteService( hService),它刪除指定的Service。
3. SC_HANDLE OpenService(SC_HANDLE hSCManager,LPCTSTR lpServiceName, DWORD dwDesiredAccess )
OpenService函數(shù)打開(kāi)指定的Service。其中參數(shù)hSCManager為指向service control manager database 的句柄,由OpenSCManager返回。LpServiceName為Service的名字,dwDesiredAccess是訪問(wèn)權(quán)限,其可選值比較多,讀者可以參看SDK Help. 函數(shù)調(diào)用成功則返回打開(kāi)的Service句柄,失敗則返回NULL。
4. BOOL StartService( SC_HANDLE hService, DWORD dwNumServiceArgs,LPCTSTR *lpServiceArgVectors )
StartService函數(shù)啟動(dòng)指定的Service。其中參數(shù)hService 為指向Service的句柄,由OpenService返回。dwNumServiceAr為啟動(dòng)服務(wù)所需的參數(shù)的個(gè)數(shù)。lpszServiceArgs 為 啟 動(dòng) 服務(wù)所需的參數(shù)。函數(shù)執(zhí)行成功則返回True, 失敗則返回False。
5. BOOL ControlService(SC_HANDLE hService DWORD dwControl,LPSERVICE_STATUS lpServiceStatus )
Service程序沒(méi)有專門的停止函數(shù),而是用ControlService函數(shù)來(lái)控制Service的暫停、繼續(xù)、停止等操作。參數(shù)dwControl指定發(fā)出的控制命令,可以為以下幾個(gè)值:
SERVICE_CONTROL_STOP //停止Service
SERVICE_CONTROL_PAUSE //暫停Service
SERVICE_CONTROL_CONTINUE //繼續(xù)Service
SERVICE_CONTROL_INTERROGATE //查詢Service的狀態(tài)
SERVICE_CONTROL_SHUTDOWN //讓ControlService調(diào)用失效
參數(shù)lpServiceStatus是一個(gè)指向SERVICE_STATUS的指針。SERVICE_STATUS是一個(gè)比較重要的結(jié)構(gòu),它包含了Service的各種信息,如當(dāng)前狀態(tài)、可接受何種控制命令等等。
6. BOOL QueryServiceStatus( SC_HANDLE hService,LPSERVICE_STATUS lpServiceStatus )
QueryServiceStatus函數(shù)比較簡(jiǎn)單,它查詢并返回當(dāng)前Service的狀態(tài)。
編制一個(gè)Service一般需要兩個(gè)程序,一個(gè)是Service本體,一個(gè)是用于對(duì)Service進(jìn)行控制的控制程序。通常Service本體是一個(gè)console程序,而控制程序則是一個(gè)普通的Win32應(yīng)用程序(當(dāng)然,用戶不用控制程序而通過(guò)控制面板也可對(duì)Service進(jìn)行啟、停,但不能進(jìn)行添加、刪除操作。)
首先,我們來(lái)編寫(xiě)Service本體。對(duì)于Service本體來(lái)說(shuō),它一般又由以下三部分組成:main()、ServiceMain()、Handler(),下面是main()的源代碼:(注:由于篇幅的關(guān)系,大部分程序都沒(méi)進(jìn)行錯(cuò)誤處理,讀者可以自己添上)
int main(int argc, char **argv)
{
SERVICE_TABLE_ENTRY ste[2];
//一個(gè)Service進(jìn)程可以有多個(gè)線程,這是每個(gè)
//線程的入口表
ste[0].lpServiceName="W.Z.SERVICE"; //線程名字
ste[0].lpServiceProc=ServiceMain;
//線程入口地址
ste[1].lpServiceName=NULL;
//最后一個(gè)必須為NULL
ste[1].lpServiceProc=NULL;
StartServiceCtrlDispatcher(ste);
return 0;
}
main()是Service的主線程。當(dāng)servie control manager開(kāi)始一個(gè)Service進(jìn)程時(shí),它總是等待這個(gè)Service去調(diào)用StartServiceCtrlDispatcher()函數(shù)。main( )作為這個(gè)進(jìn)程的主線程應(yīng)該在程序開(kāi)始后盡快調(diào)用StartServiceCtrlDispatcher()。StartServiceCtrlDispatcher()在被調(diào)用后并不立即返回,它把本Service的主線程連接到service control manager,從而讓service control manager通過(guò)這個(gè)連接發(fā)送開(kāi)始、停止等控制命令給主線程。主線程在這時(shí)就扮演了一個(gè)命令的轉(zhuǎn)發(fā)器的角色,它或者調(diào)用Handle( )去處理停止、繼續(xù)等控制要求,或者產(chǎn)生一個(gè)新線程去執(zhí)行ServiceMain。StartServiceCtrlDispatcher()在整個(gè)Service結(jié)束時(shí)才返回。
ServiceMain()是Service真正的入口點(diǎn),必須在main()中進(jìn)行了正確的定義。ServiceMain( )的兩個(gè)參數(shù)是由StartService()傳遞過(guò)來(lái)的。下面是ServiceMain()的源代碼:
void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{
ssh=RegisterServiceCtrlHandler
("W.Z.SERVICE",Handler);
ss.dwServiceType=SERVICE_WIN32_OWN
_PROCESS SERVICE_INTERACTIVE_PROCESS;
ss.dwCurrentState=SERVICE_START_PENDING;
//如用戶程序的代碼比較多
(執(zhí)行時(shí)間超過(guò)1秒),這兒要設(shè)成SERVICE_
START_PENDING,待用戶程序完成后再設(shè)為SERVICE_RUNNING。
ss.dwControlsAccepted=SERVICE_ACCEPT_
STOP;//表明Service目前能接受的命令是停止命令。
ss.dwWin32ExitCode=NO_ERROR;
ss.dwCheckPoint=0;
ss.dwWaitHint=0;
SetServiceStatus(ssh, &ss);
//必須隨時(shí)更新數(shù)據(jù)庫(kù)中Service的狀態(tài)。
Mycode(); //這兒可放入用戶自己的代碼
ss.dwServiceType=SERVICE_WIN32_OWN_
PROCESS SERVICE_INTERACTIVE_PROCESS;
ss.dwCurrentState=SERVICE_RUNNING;
ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
ss.dwWin32ExitCode=NO_ERROR;
ss.dwCheckPoint=0;
ss.dwWaitHint=0;
SetServiceStatus(ssh,&ss);
Mycode();// 這兒也可放入用戶自己的代碼
}
在ServiceMain()中應(yīng)該立即調(diào)用
RegisterServiceCtrlHandler()注冊(cè)一個(gè)Handler去處理控制程序或控制面板對(duì)Service的控制要求。
Handler()被轉(zhuǎn)發(fā)器調(diào)用去處理要求,
下面是Handler()的源代碼:
void WINAPI Handler(DWORD Opcode)
{
switch(Opcode)
{
case SERVICE_CONTROL_STOP: //停止Service
Mycode();//這兒可放入用戶自己的相關(guān)代碼
ss.dwWin32ExitCode = 0;
ss.dwCurrentState =SERVICE_STOPPED;
//把Service的當(dāng)前狀態(tài)置為STOP
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
SetServiceStatus (ssh,&ss);
/必須隨時(shí)更新數(shù)據(jù)庫(kù)中Service的狀態(tài)
break;
case SERVICE_CONTROL_INTERROGATE:
SetServiceStatus (ssh,&ss);
/必須隨時(shí)更新數(shù)據(jù)庫(kù)中Service的狀態(tài)
break;
}
}
好了,Service本體程序已基本完成,我們接著來(lái)看一下Service的控制程序:
控制程序是一個(gè)標(biāo)準(zhǔn)的window程序,上面主要有四個(gè)按紐:Create Service、Delete Service、start、stop,分別用來(lái)產(chǎn)生、刪除、開(kāi)始和停止Service。下面是它們的部分源代碼:
1. 產(chǎn)生Service
void __fastcall TForm1::CreateBtnClick
(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,
SC_MANAGER_CREATE_SERVICE);
if (scm!=NULL){
svc=CreateService(scm,
"W.Z.SERVICE","W.Z.SERVICE",//Service名字
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS
SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START,
//以自動(dòng)方式開(kāi)始
SERVICE_ERROR_IGNORE,
"C:\\Ntservice.exe", //Service本體程序路徑,
必須與具體位置相符
NULL,NULL,NULL,NULL,NULL);
if (svc!=NULL)
CloseServiceHandle(svc);
CloseServiceHandle(scm);
}
}
2. 刪除Service
void __fastcall TForm1::DeleteBtnClick
(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,
SC_MANAGER_CONNECT);
if (scm!=NULL){
svc=OpenService(scm,"W.Z.SERVICE",
SERVICE_ALL_ACCESS);
if (svc!=NULL){
QueryServiceStatus(svc,&ServiceStatus);
if (ServiceStatus.dwCurrentState==
SERVICE_RUNNING)//刪除前,先停止此Service.
ControlService(svc,
SERVICE_CONTROL_STOP,&ServiceStatus);
DeleteService(svc);
CloseServiceHandle(svc);
//刪除Service后,最好再調(diào)用CloseServiceHandle
}
//以便立即從數(shù)據(jù)庫(kù)中移走此條目。
CloseServiceHandle(scm);
}
}
3. 開(kāi)始Service
void __fastcall TForm1::StartBtnClick(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT);
if (scm!=NULL){
svc=OpenService(scm,"W.Z.SERVICE",SERVICE_START);
if (svc!=NULL){
StartService(svc,0,NULL);//開(kāi)始Service
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
}
4.停止Service
void __fastcall TForm1::StopBtnClick
(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,
SC_MANAGER_ALL_ACCESS);
if (scm!=NULL){
svc=OpenService(scm,"W.Z.SERVICE",
SERVICE_STOP SERVICE_QUERY_STATUS);
if (svc!=NULL){
QueryServiceStatus(svc,&ServiceStatus);
if (ServiceStatus.dwCurrentState==
SERVICE_RUNNING)
ControlService(svc,
SERVICE_CONTROL_STOP,&ServiceStatus);
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
}
本程序在C++Builder 5.0和Windows 2000下編譯通過(guò)。