莘庄地铁站附近停车场:windows服务程序编写

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 08:03:50

windows服务程序编写

本帖最后由 tishion 于 2009-6-30 14:50 编辑

服务
就是运行在系统后台,不需要与用户进行交互的进程.
打开  控制面板>管理工具>服务
就可以看到系统当前所安装的服务的状态.
服务无需与用户交互的特点可以很方便的处理很多事务,比如一般程序的升级服务(前段时间暴风导致的断网就是由于暴风服务程序),以及一些特别的监控程序如杀毒软件防火墙等等,当然不排除木马病毒后门等.

Windows系统的程序都有自己的结构特点,就像窗口应用程序一样服务程序也有自己独特的结构特点,所以服务程序的编写需要了解windows系统的服务管理控制机制.
先打开服务控制面板
如下:这是一张表,表里面列出的是已经安装的服务程序(启动与否是另一回事)
表中的每一个服务名称都对应了一个可执行二进制文件.
双击其中的任一项:我选择ClipBook服务(剪贴板)
弹出该服务控制属性窗口如下

:
其中可:执行文件路径(H)一栏里面的地址就是我们所要编写的服务程序,也就是我们编码后生成的可执行文件.
介绍上面的主要是想说明,要在系统里面添加一个服务项必要条件是有个可执行文件(不一定是服务程序),然后我们可以通过cmd命令将该可执行文件来添加到服务管理器里面,这样我们就可以在服务管理器里面控制服务的启动与停止,当然如果添加的不是服务程序是不可能启动的管理器会报错.
关于服务控制管理器的的命令简单介绍一点:
创建[添加]一项服务到服务管理器
sc create [服务名] binpath=[可执行文件地址]
服务名是必须指定的,可以在命名规则内任意命名  该名称会在上图中的显示名称中显示,
可执行文件地址就是服务程序的地址,注意等号后面紧跟一个空格!!!
sc delete [服务名称]
删除服务.

上面是介绍服务的管理器
下面开始介绍编写服务程序

服务程序是控制台(console)应用程序的一种,所以 main()函数是必不可少的,而服务程序的特殊函数是void ServiceMain(int argc, char* argv);
这是服务程序的入口
一个二进制文件被添加到服务管理器后当你点击启动按钮时main函数里面代码执行最后然后调用ServiceMain()函数如果找不到该函数就启动失败,报错终止.
还有一个函数void WINAPI ControlHandler(DWORD request);
这个是服务控制处理器函数,他的作用是接收来自服务控制管理器传送进来的消息然后做出对应处理,比如你点击了停止按钮,服务控制管理器就给指定的服务程序传送一个SERVICE_CONTROL_STOP消息,然后执行对应这个分支选择后面的代码.详细过程请参阅windows消息机制,函数用法及消息映射请参阅MSDN.


主要函数就是这三个下面给出一段模板代码,

/*======================================

//

//Windwos Service.

//By:tishion

//09.3.22

//

/*======================================*/

#include

#include

//=======准备数据====================


SERVICE_STATUS ServiceStatus =


{


SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,

//这个重要,服务类型,关系到启动类型和能否禁用,

//文件系统服务和引导服务都不能被禁用而且权限很高,

//可以在引导系统的时候自动启动.
SERVICE_STOPPED,

SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_PAUSE_CONTINUE,

0,0,0,0

};


//
定义服务状态(一个结构体,详细信息请参阅MSDN)


TCHAR szSvName[]=TEXT("Myservice");
//
定义服务名称


SERVICE_STATUS_HANDLE hStatus;

//
定义服务状态句柄


SC_HANDLE SCMger;
//
定义服务控制管理器句柄



//=============函数前向声明=================


void yourfunction();
//
服务功能实现函数


void WINAPI ControlHandler(DWORD request);
//
服务控制处理器函数


void ServiceMain(int argc, char* argv);
//
服务入口函数



int main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
//服务分派表存放服务入口函数,一个服务程序可以有多个服务入口函数,
//这里只举例一个的,注意表容量一定比服务入口函数大一,
//因为表的最后一项一定要为NULL;
ServiceTable[0].lpServiceName = szSvName;
ServiceTable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc= NULL;
// 启动服务的控制分派机线程
if(StartServiceCtrlDispatcher(ServiceTable)==0)CreateMyService();
}




void ServiceMain(int argc, char* argv)


{



hStatus = RegisterServiceCtrlHandler(szSvName,ControlHandler);



//
注册服务控制处理器 ,得到控制句柄



ServiceStatus.dwCurrentState = SERVICE_START_PENDING;



//
设置服务的当前状态为正在启动



ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;



//
设置服务的控制权限,,这里设置的是只接受关机消息,其他控制无法操作



//
下面向SCM 报告运行状态,因为上面只是对储存服务状态的结构体变量进行赋值并没有把设置情况传递给服务,所以要通过服务控制处理器来把服务状态设置成上面的各个值.



SetServiceStatus(hStatus,&ServiceStatus);


//关联服务控制处理器句柄和服务状态


//这行代码执行时我们可以看到正在启动服务的窗口


//下面是将服务设置成已经启动的状态



ServiceStatus.dwWin32ExitCode = NO_ERROR;



ServiceStatus.dwCheckPoint = 0;



ServiceStatus.dwWaitHint = 0;



ServiceStatus.dwCurrentState = SERVICE_RUNNING;



//
设置完毕下面继续关联服务控制处理器句柄和服务状态



SetServiceStatus(hStatus,&ServiceStatus);



//
这行代码执行时会显示服务启动成功窗口




//
下面开始服务功能函数(就是你自己要完成的工作)



yourfunction();



//
工作完成,下面设置服务状态停止



ServiceStatus.dwCurrentState = SERVICE_STOPPED;



SetServiceStatus(hStatus,&ServiceStatus);


//关联服务控制处理器句柄和服务状态 变为停止


}



void WINAPI ControlHandler(DWORD request){



switch(request)



{



case SERVICE_CONTROL_SHUTDOWN:



ServiceStatus.dwCurrentState = SERVICE_STOPPED;



SetServiceStatus(hStatus,&ServiceStatus);



break;


//根据前面的设置,实现控制代码,如果只设置了只接受一个消息就可以只写一个分支,如果不接受任何消息也可以不写.,



}


}



void yourfunction()


{


…….


//注意这里面的不能出现和用户交互的任何代码,否则服务启动出错.


}



=====================================================================
当然可以让这个二进制文件自动把自己添加到服务管理控制器中
实现方法是添加一个函数
void CreateMyService()
{
  SCMger=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
   CreateService(
   SCMger,
   szSvName,
   szSvName,
   SERVICE_START,
   SERVICE_WIN32_OWN_PROCESS,
   SERVICE_AUTO_START,
   SERVICE_ERROR_IGNORE,
   TEXT("c:\\myservice.exe"),              //程序自身的地址
   NULL,
   NULL,
   NULL,
   NULL,
   NULL);
};

然后主函数中最后一行这样写

if(StartServiceCtrlDispatcher(ServiceTable)==0)CreateMyService();