windows服务怎么写( 二 )


重启电脑系统就会自动运行我们设置的软件 。
2. 如何编写windows服务程序 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 ); // 在这里执行服务线程的创建 。