您的位置:首页 > 其它

VC编写系统服务程序笔记

2012-08-24 13:21 399 查看
这里我要把自己写好的程序设置为开机启动了,所以注册为服务程序是最好的方法,先看VC写服务程序的思路  
这里我要把自己写好的程序设置为开机启动了,所以注册为服务程序是最好的方法,先看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;              //初始化服务时并不退出,因此,它们的值为0
MyServiceStatus.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()
{
//获取系统目录地址,失败就返回-1
i = 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息