转载自:http://blog.csdn.net/pgshow/article/details/7677583
- 这里我要把自己写好的程序设置为开机启动了,所以注册为服务程序是最好的方法,先看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;
- }