如何编写windows服务程序

 我来答
u盘启动盘制作工具
2016-06-20 · TA获得超过777个赞
知道大有可为答主
回答量:2417
采纳率:60%
帮助的人:3906万
展开全部
Windows提供了一套后台服务程序编程接口,用户在编写后台服务程序时需要遵循一定的编程框架,否则服务程序不能正常运行。
服务程序通常编写成控制台类型的应用程序,总的来说,一个遵守服务控制管理程序接口要求的程序 包含下面三个函数:
1)服务程序主函数(main):调用系统函数 StartServiceCtrlDispatcher 连接程序主线程到服务控制管理程序。
和其它进程一样,Main函数是服务进程的入口函数,服务控制管理器(SCM)在启动服务程序时,会从服务程序的main函数开始执行。在进入点函数里面要完成ServiceMain的初始化,准确点说是初始化一个SERVICE_TABLE_ENTRY结构数组,这个结构记录了这个服务程序里面所包含的所有服务的名称和服务的进入点函数。然后再调用接口StartServiceCtrlDispatcher 。
Main函数的函数框架如下:
int _tmain(int argc, _TCHAR* argv[])
{
//服务入口点函数表
SERVICE_TABLE_ENTRY dispatchTable[]=
{
{TEXT(SZSERVICENAME),(LPSERVICE_MAIN_FUNCTION)Service_Main},
{ NULL,NULL}
};
if((argc>1)&&((*argv[1]==‘-‘)||(argv[1]=="/")))
{
/*
参数个数大于1是安装或者删除服务,该操作是由用户来执行的
当然也可以讲这一部分功能另写一个程序来实现
*/
if(_stricmp("install",argv[1]+1)==0)
{
installService();
}
else if(_stricmp("remove",argv[1]+1)==0)
{
removeService();
}
else if(_stricmp("debug",argv[1]+1)==0)
{
bDebugServer=true;
debugService(argc,argv);
}

}
else
{
/*
如果未能和上面的如何参数匹配,则可能是服务控制管理程序来启动该程序。 立即调用StartServiceCtrlDispatcher 函数
*/
g_logout.Logout("%s\n", "enter StartServiceCtrlDispatcher...");

//通知服务管理器为每一个服务创建服务线程
if(!StartServiceCtrlDispatcher(dispatchTable))
g_logout.Logout("%s\n", "StartServiceCtrlDispatcher failed.");
else
g_logout.Logout("%s\n", "StartServiceCtrlDispatcher OK.");
}

return 0;

}
SCM启动一个服务程序之后,它会等待该程序的主线程去调StartServiceCtrlDispatcher。如果那个函数在两分钟内没有被调用,SCM将会认为这个服务有问题,并调用TerminateProcess去杀死这个进程。这就要求你的主线程要尽可能快的调用StartServiceCtrlDispatcher。

2)服务入口点函数(ServiceMain):执行服务初始化任务,同时执行多个服务的服务进程有多个服务入口函数。
在服务入口函数里,必须立即注册服务控制回调函数。然后调用函数SetServiceStatus 通知SCM 服务现在的状态,否则SCM会认为服务启动失败。
ServiceMain函数框架如下:
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
{
//注册服务控制处理函数
sshStatusHandle=RegisterServiceCtrlHandler(TEXT(SZSERVICENAME),Service_Ctrl);
//如果注册失败
if(!sshStatusHandle)
{
g_logout.Logout("%s\n", "RegisterServiceCtrlHandler failed...");
return;
}

//初始化 SERVICE_STATUS 结构中的成员
ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; //可执行文件中只有一个单独的服务
ssStatus.dwServiceSpecificExitCode=0;
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; //允许用SCP去停止该服务

//更新服务状态
if(ReportStatusToSCMgr(SERVICE_START_PENDING,//服务状态,服务仍在初始化
NO_ERROR,
3000)) //等待时间
SvcInit( dwArgc, lpszArgv ); //服务初始化函数
else
g_logout.Logout("%s\n", "ReportStatusToSCMgr SERVICE_START_PENDING failed...");

}

服务初始化函数SvcInit:
该函数的写法比较重要。在函数中创建一个等待事件,然后一直等待该事件。该线程在服务接到请求之前一直处于挂起状态,直到接到服务停止消息。
VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)
{
/*创建事件*/
ghSvcStopEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual reset event
FALSE, // not signaled
NULL); // no name

if ( ghSvcStopEvent == NULL)
{
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}

// Report running status when initialization is complete.

ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

// 在这里执行服务线程的创建...

while(1)
{
// 等待停止事件被触发

WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}
}

3)控制服务处理程序函数(Handler):在服务程序收到控制请求时由控制分发线程引用。(此处是Service_Ctrl)。
void WINAPI Service_Ctrl(DWORD dwCtrlCode)
{
//处理控制请求码
switch(dwCtrlCode)
{
//先更新服务状态为 SERVICDE_STOP_PENDING,再停止服务。
case SERVICE_CONTROL_STOP:
ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
ServiceStop(); //由具体的服务程序实现
/*ssStatus.dwCurrentState=SERVICE_STOPPED;*/

//其它控制请求...

default:
break;
}
}

3. 注意事项
1)安装服务可以另写一个程序,也可以并在服务程序当中,比较简单,这里就不介绍了。
2)服务初始化函数SvcInit里创建等待事件比较重要,在服务接收到服务停止消息后,触发该事件。
3)Service_Main在等待事件触发后立即返回,服务进程就会退出了
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式