用C++ Builder在WINNT下体例一个Service
副标题#e#
Windows NT与Windows 9x有一个很是重要的区别,即Windows NT提供了许多成果强大的Service(处事)。这些Service可以跟着NT的启动而自启动,也可以让用户通过节制面板启动,还可以被Win32应用措施起停。甚至在没有用户登录系统的环境下,这些Service也能执行。很多FTP、WWW处事器和数据库就是以Service的形式存在于NT上,从而实现了无人值守。就连最新版的“黑客”措施Back Orifice 2000也是以Service形式在NT上藏身的。由于Service的编程较巨大,很多开拓者想开拓本身的Service但往往都望而却步。鉴于此,下面我们就从新到尾来结构一个全新的Service,读者只要在措施中注明的处所加上本身的代码,那么就可以轻松拥有一个本身的Service。在编写Service之前,先先容一下几个重要的函数:
1. SC_HANDLE OpenSCManager( LPCTSTR lpMachineName, LPCTSTR lpDatabaseName, DWORD dwDesiredAccess)
OpenSCManager 函数打开指定计较机上的service control manager database。个中参数lpMachineName指定计较机名,若为空则指定为本机。LpDatabaseName为指定要打开的service control manager database名, 默认为空。dwDesiredAccess指定操纵的权限, 可觉得下面取值之一:
SC_MANAGER_ALL_ACCESS //所有权限
SC_MANAGER_CONNECT //答允毗连到service control manager database
SC_MANAGER_CREATE_SERVICE //答允建设处事工具并把它插手database
SC_MANAGER_ENUMERATE_SERVICE //答允列举database 中的Service
SC_MANAGER_LOCK //答允锁住database
SC_MANAGER_QUERY_LOCK_STATUS //答允查询database的封闭信息
函数执行乐成则返回一个指向service control manager database的句柄,失败则返回NULL。留意:WINNT通过一个名为service control manager database的数据库来打点所有的Service,因此对Service的任何操纵都应打开此数据库。
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函数发生一个新的SERVICE。个中参数hSCManager为指向service control manager database 的句柄,由OpenSCManager返回。LpServiceName为SERVICE的名字,lpDisplayName为Service显示用名,dwDesiredAccess是会见权限,本措施顶用SERVICE_ALL_ACCESS。wServiceType,指明SERVICE范例,本措施顶用SERVICE_WIN32_OWN_PROCESS| SERVICE_INTERACTIVE_PROCESS。dwStartType为Service启动方法,本措施回收自启动,即dwStartType便是SERVICE_AUTO_START。 dwErrorControl说明当Service在启动中堕落时采纳什么行动,本措施回收SERVICE_ERROR_IGNORE即忽约错误,读者可以改为其他的。LpBinaryPathName指明Service本体措施的路径名。剩下的五个参数一般可设为NULL。如函数挪用乐成则返回这个新Service的句柄,失败则返回NULL。与此函数对应的是DeleteService( hService),它删除指定的Service。
3. SC_HANDLE OpenService(SC_HANDLE hSCManager,LPCTSTR lpServiceName, DWORD dwDesiredAccess )
OpenService函数打开指定的Service。个中参数hSCManager为指向service control manager database 的句柄,由OpenSCManager返回。LpServiceName为Service的名字,dwDesiredAccess是会见权限,其可选值较量多,读者可以参看SDK Help. 函数挪用乐成则返回打开的Service句柄,失败则返回NULL。
4. BOOL StartService( SC_HANDLE hService, DWORD dwNumServiceArgs,LPCTSTR *lpServiceArgVectors )
StartService函数启动指定的Service。个中参数hService 为指向Service的句柄,由OpenService返回。dwNumServiceAr为启动处事所需的参数的个数。lpszServiceArgs 为 启 动 处事所需的参数。函数执行乐成则返回True, 失败则返回False。
5. BOOL ControlService(SC_HANDLE hService DWORD dwControl,LPSERVICE_STATUS lpServiceStatus )
Service措施没有专门的遏制函数,而是用ControlService函数来节制Service的暂停、继承、遏制等操纵。参数dwControl指定发出的节制呼吁,可觉得以下几个值:
SERVICE_CONTROL_STOP //遏制Service
SERVICE_CONTROL_PAUSE //暂停Service
SERVICE_CONTROL_CONTINUE //继承Service
SERVICE_CONTROL_INTERROGATE //查询Service的状态
SERVICE_CONTROL_SHUTDOWN //让ControlService挪用失效
参数lpServiceStatus是一个指向SERVICE_STATUS的指针。SERVICE_STATUS是一个较量重要的布局,它包括了Service的各类信息,如当前状态、可接管何种节制呼吁等等。
#p#副标题#e#
6. BOOL QueryServiceStatus( SC_HANDLE hService,LPSERVICE_STATUS lpServiceStatus )
QueryServiceStatus函数较量简朴,它查询并返回当前Service的状态。
体例一个Service一般需要两个措施,一个是Service本体,一个是用于对Service举办节制的节制措施。凡是Service本体是一个console措施,而节制措施则是一个普通的Win32应用措施(虽然,用户不消节制措施而通过节制面板也可对Service举办启、停,但不能举办添加、删除操纵。)
#p#分页标题#e#
首先,我们来编写Service本体。对付Service本体来说,它一般又由以下三部门构成:main()、ServiceMain()、Handler(),下面是main()的源代码:(注:由于篇幅的干系,大部门措施都没举办错误处理惩罚,读者可以本身添上)
int main(int argc, char **argv)
{
SERVICE_TABLE_ENTRY ste[2];
//一个Service历程可以有多个线程,这是每个线程的进口表
ste[0].lpServiceName="W.Z.SERVICE"; //线程名字
ste[0].lpServiceProc=ServiceMain;
//线程进口地点
ste[1].lpServiceName=NULL;
//最后一个必需为NULL
ste[1].lpServiceProc=NULL;
StartServiceCtrlDispatcher(ste);
return 0;
}
main()是Service的主线程。当servie control manager开始一个Service历程时,它老是期待这个Service去挪用StartServiceCtrlDispatcher()函数。main( )作为这个历程的主线程应该在措施开始后尽快挪用StartServiceCtrlDispatcher()。StartServiceCtrlDispatcher()在被挪用后并不当即返回,它把本Service的主线程毗连到service control manager,从而让service control manager通过这个毗连发送开始、遏制等节制呼吁给主线程。主线程在这时就饰演了一个呼吁的转发器的脚色,它可能挪用Handle( )去处理惩罚遏制、继承等节制要求,可能发生一个新线程去执行ServiceMain。StartServiceCtrlDispatcher()在整个Service竣事时才返回。
ServiceMain()是Service真正的进口点,必需在main()中举办了正确的界说。ServiceMain( )的两个参数是由StartService()通报过来的。下面是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;
//如用户措施的代码较量多(执行时间高出1秒),这儿要设成SERVICE_START_PENDING,待用户措施完成后再设为SERVICE_RUNNING。
ss.dwControlsAccepted=SERVICE_ACCEPT_
STOP;//表白Service今朝能接管的呼吁是遏制呼吁。
ss.dwWin32ExitCode=NO_ERROR;
ss.dwCheckPoint=0;
ss.dwWaitHint=0;
SetServiceStatus(ssh, &ss);
//必需随时更新数据库中Service的状态。
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()中应应当即挪用
RegisterServiceCtrlHandler()注册一个Handler
去处理惩罚节制措施或节制面板对Service的节制要求。
Handler()被转发器挪用去处理惩罚要求,
下面是Handler()的源代码:
void WINAPI Handler(DWORD Opcode)
{
switch(Opcode)
{
case SERVICE_CONTROL_STOP: //遏制Service
Mycode();//这儿可放入用户本身的相关代码
ss.dwWin32ExitCode = 0;
ss.dwCurrentState =SERVICE_STOPPED;
//把Service的当前状态置为STOP
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
SetServiceStatus (ssh,&ss);
/必需随时更新数据库中Service的状态
break;
case SERVICE_CONTROL_INTERROGATE:
SetServiceStatus (ssh,&ss);
//必需随时更新数据库中Service的状态
break;
}
}
好了,Service本体措施已根基完成,我们接着来看一下Service的节制措施:
节制措施是一个尺度的window措施,上面主要有四个按纽:Create Service、Delete Service、start、stop,别离用来发生、删除、开始和遏制Service。下面是它们的部门源代码:
1. 发生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, //以自动方法开始
SERVICE_ERROR_IGNORE,
"C:\\ntservice.exe", //Service本体措施路径,必需与详细位置相符
NULL,NULL,NULL,NULL,NULL);
if (svc!=NULL)
CloseServiceHandle(svc);
CloseServiceHandle(scm);
}
}
2. 删除Service
#p#分页标题#e#
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后,最好再挪用CloseServiceHandle
}
//以便当即从数据库中移走此条目。
CloseServiceHandle(scm);
}
}
3. 开始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);//开始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);
}
}