VC编写系统服务程序笔记

来源:互联网 发布:中文域名安全性 编辑:程序博客网 时间:2024/05/21 09:41

这里我要把自己写好的程序设置为开机启动了,所以注册为服务程序是最好的方法,先看VC写服务程序的思路  

 

服务程序通常编写成控制台类型的应用程序,总的来说,一个遵守服务控制管理程序接口要求的程序包含下面三个函数:

  1.服务程序主函数(main):调用系统函数 StartServiceCtrlDispatcher 连接程序主线程到服务控制管理程序

  StartServiceCtrlDispatcher 函数有一个 SERVICE_TABLE_ENTRY 作为参数,里面指定了 Service 的名字和入口点。 如果 StartServiceCtrlDispatcher 函数调用成功,被调用线程不会在 Service 进程结束以前返回。

  SERVICE_TABLE_ENTRY 结构具体描述如下:

typedef struct _SERVICE_TABLE_ENTRY {LPTSTR lpServiceName;  //一个以 NULL 结尾的字符串,标识服务名,如果是 SERVICE_WIN32_OWN_PROCESS 类型的服务,这个字符串会被忽略LPSERVICE_MAIN_FUNCTION lpServiceProc;  //指向服务入口点函数} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY; 


2.服务入口点函数(ServiceMain):执行服务初始化任务,同时执行多个服务的服务进程有多个服务入口函数
  

  标准的ServiceMain 函数需要执行以下任务:

  1.马上调用 RegisterServiceCtrlHandlerEx 去注册一个 处理函数(HandlerEx) 去处理 Service 的 控制要求。返回值是通知 SCM 的 Service 状态处理的 Handle

  2.执行初始化单元,如果初始化代码的执行时间少于1秒或很短,可以在 ServiceMain 里执行,如果 初始化时间很长,最好先调用 SetServiceStatus 函数,指定状态为 SERVICE_START_PENDING (启动中)。

  如果初始化时间超过30秒,就必须建立另外的线程完成这些共同的初始化工作,从而保证服务程序主函数能及时地调用 StartServiceCtrlDispatcher 函数

  如果 初始化 或 运行 过程中出现了错误,应该调用 SetServiceStatus 并指定 SERVICE_STOP_PENDING(正在停止) 。完成清场工作后,再指定现在状态为 SERVICE_STOPPED, 记得在 SERVICE_STATUS 结构中指定成员 dwServiceSpecificExitCode 和 dwWin32ExitCode 的值,用来指定错误的类型。

  3.控制服务处理程序函数(Handler):在服务程序收到控制请求时由控制分发线程引用。

  当SCM发出控制请求的时候,控制处理函数必须在30秒内返回,否则 SCM 会返回错误。

 

好了,思路有了,下面是每个步骤详细的写法,这里有现成的说明我就不自己写了:http://www.vckbase.com/index.php/wv/1193

另附服务应用程序详细介绍:http://blog.csdn.net/showna/article/details/1543517

 

我写的源码,东拼西凑的,不对的地方希望能指出啊:

 

// Services_test.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "Windows.h"//全局变量SERVICE_STATUS         MyServiceStatus;SERVICE_STATUS_HANDLE  MyServiceStatusHandle;TCHAR szServiceName[] = TEXT("ServiceTest");DWORD i = 0;//向前声明void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);  //服务主函数void WINAPI ControlHandler(DWORD dwMsg);            //服务控制函数int  InitService();                                 //服务初始化函数int _tmain(int argc, _TCHAR* argv[]){//初始化一个分配表SERVICE_TABLE_ENTRY ServiceTable[] ={{ szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain },{ NULL, NULL } //分派表的最后一项必须是服务名和服务主函数域的 NULL 指针,所以这两项为NULL};    if(!StartServiceCtrlDispatcher(ServiceTable))  // 启动服务的控制分派机线程{OutputDebugString(TEXT("分派机启动服务失败!"));}return 0;}void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) {int error;//指定服务特征和其当前状态MyServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;  //服务类型MyServiceStatus.dwCurrentState = SERVICE_START_PENDING;     //指定服务的当前状态MyServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;   //这个成员表示哪些控制通执服务是可接受的MyServiceStatus.dwWin32ExitCode = 0;                        //这两个域在你终止服务并报告退出细节时很有用。MyServiceStatus.dwServiceSpecificExitCode = 0;              //初始化服务时并不退出,因此,它们的值为0MyServiceStatus.dwCheckPoint = 0;                           //这二个成员允许MyServiceStatus.dwWaitHint = 0;                             //一个服务回报它的进度//注册服务控制    MyServiceStatusHandle = RegisterServiceCtrlHandler(szServiceName, ControlHandler);     if (NULL == MyServiceStatusHandle){//注册失败就返回OutputDebugString(TEXT("注册服务失败!"));return; }error = InitService(); //初始化数据if (error) {// 初始化失败,终止服务MyServiceStatus.dwCurrentState = SERVICE_STOPPED; MyServiceStatus.dwWin32ExitCode = -1; SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus); //向 SCM 报告服务的状态return; // 退出 ServiceMain}// 如果初始化成功,向 SCM 报告运行状态 MyServiceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus);while (MyServiceStatus.dwCurrentState == SERVICE_RUNNING){//这里放你要实现的功能函数if(i != 100)return;MessageBeep(0);Sleep(3000);}    return; } int InitService(){//获取系统目录地址,失败就返回-1i = 100;return 0;}void WINAPI ControlHandler(DWORD dwMsg) {    switch(dwMsg)    {   case SERVICE_CONTROL_STOP:    //响应停止服务控制   MyServiceStatus.dwWin32ExitCode = 0;    MyServiceStatus.dwCurrentState = SERVICE_STOPPED;    SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus);   return;    default:   break;    }     //向 SCM 报告服务的状态    SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus);    return; }


http://blog.csdn.net/pgshow/article/details/7677583

原创粉丝点击