Windows服务程序的原理及实现(服务分为WIN32服务和系统服务)

今天给大家讲下怎样做一个服务程序...本来是想详细讲的,不过写着写着累得要命..很多

地方就没详细...不过代码我加了点注...如果还有一些不明白的自己查下MSDN......便宜

环境,,VC++6.0...代码有俩段,一段是服务程序的..另一段是安装服务程序的...这个程序

的功能是开机发出滴滴声....安装成功后自己点启动...下次开机就自动起动了....

load.exe的实现是比较简单,本来想弄个汇编版本...不过真的累...就算了..这里一个服

务的基本框架就完成了...剩下的只是添加你自己的功能代码...

怎样安装::我在C盘建一个名为sysnap的文件夹..里面放着俩个EXE..一个是sv.exe 另一

个是svload.exe 然后cmd到这个文件夹,输入svload.exe则服务安装成功...开机后就有一

个服务进程sv.exe...这样我们就有了一个名为sysnap的服务..在注册表里可以找到相关

信息....当然你可以把服务名改为你自己的....svload.exe的代码很简单..我没有注

释,,,,如果需要我回帖再注..我现在累

一个服务的基本框架

1感性认识什么是服务

2用INF文件安装服务

3关于服务的一些基本理论知识

4一个服务的创建流程和基本组成

5详说各个基本函数

6所用到的一些数据结构和API说明

7开始我们的第一个服务,完整代码

8运行我们的服务,完整代码

1感性认识什么是服务

在运行框输入SERVICES.MSC..看到没,,这些都是windows的服务..里面有一些是windows自己的,有一些是第三方服务,,比如我们的杀毒软件大部分都有一个服务

那服务有什么用呢,..让我们先看一下服务的定义吧

服务:是一种应用程序类型,它在后台运行。

可见如果我们把程序做成服务后也可以照样运行起来...如果是设置成手动的,那开机后我们的服务程序就自动运行起来...所以很多木马都搞成服务启动,,这比在注册表里什么RUN

要隐蔽多了

系统有俩种服务.一种叫win32服务,他运行在用户态,对应的映像文件是.EXE或.DLL..我们这里讲的就是win32服务

另外一种叫系统服务,它运行在内核态,对应的映像文件是.SYS也就是驱动程序..其实这俩个概念现在也没必要细分了吧..区别除了运行态不同外,另外还有一个区别,就是在注册表中除了在HKEY_LOCAL_MACHINE/SYSTE/CurrentControlSet/Services下都有一个服务名外,系统服务还多了一个设备硬健HKEY_LOCAL_MACHINESystem/CurrentControlSet/Enum子键,因为是驱动程序嘛,在删除一些内核木马时.这个建默认是无法删除的,因为需要SYSTEM权限..不过右键->权限->添加->高级就可以搞定

2用INF文件安装服务

现在我们就用.INF文件来把我们的EXE程序变成服务..随开机的运行而运行,这个EXE文件我是用我前几天在吧里发的哪个小程序,依然是输出电脑的用户名...在C盘建一个文件夹,命名为SYSNAP..把我们的程序sysnap.exe放进去

打开笔记本,那下面代码写进去,保存为sysnap.inf

[Version]

Signature="$WINDOWS NT$"

[DefaultInstall.Services]

AddService=sysnap,,My_AddService_Name

[My_AddService_Name]

DisplayName=sysnap

Description=显示电脑用户名

ServiceType=0x10

StartType=2

ErrorControl=0

ServiceBinary=C:/SYSNAP/sysnap.exe

说明一下

1、ServiceType服务类型:0x10为独立进程服务,0x20为共享进程服务(比如svchost)

2、StartType启动类型:0 系统引导时加载,1 OS初始化时加载,2 由SCM(服务控制管理器)自动启动,3 手动启动,4 禁用(注意,0和1只能用于驱动程序)

3、ErrorControl错误控制:0 忽略,1 继续并警告,2 切换到LastKnownGood的设置,3蓝屏

4、ServiceBinary服务程序位置

好了..在CMD下运行命令

rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:/SYSNAP/sysnap.inf

这样就安装了一个名为sysnap的服务,是不是很简单呢..当然后.INF文件安装服务有时候是不太好,,,下面我们就通过编成来实现,,,也是主要的目的..先讲一下理论吧

3关于服务的一些基本理论知识

WIN32服务由三部分组成:服务应用程序、服务控制程序SCP,和服务控制管理器SCM。

服务应用程序:就是接下来我们要实现的程序,他是一个EXE文件..也可以是.DLL,这里我们是sysnap.exe

服务控制程序:控制服务应用程序的功能块,也是服务应用程序同服务管理器(SCM)之间的桥梁

服务控制管理器:负责加载和初始化AUTO_ATRT的服务程序,SCM维护着注册表中的服务数据库,位于:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services。其下的子键就是安装的服务和驱动服务。每个子键的名称就是服务名,当安装的时候由服务安全程序的CreateService 函数指定

还有就不写了..可以参考<<inside windows 2000>>他们讲的已经足够好了...,不够里面涉及的东西很多.建议看下后面的程序...不懂的再去参考他们比较好..因为这个程序不要求你全要理解他们

4一个服务的创建流程一个服务的创建流程和基本组成

A编写我们的main()函数,该函数必须在30秒内调用StartServiceCtrlDispatcher 函数..这样我们的EXE文件就在SCM里注册了

B编写我们的ServiceMain(),ServiceMain()要立即调用RegisterServiceCtrlHandler 注册服务控制处理函数,然后用RegisterServiceCtrlHandler返回的句柄向SCM发送状态信息,接着开始完成实际的服务任务和工作线程,一旦线程开始,ServiceMain()就等待一个事件的发生,知道服务停止,ServiceMain()才返回

C编写我们的控制处理器ServiceCtrlHandler,接受来自SCM的请求并作出反应,其实请求一般是下面几个值(也可以自己定义)

停止服务:SERVICE_CONTROL_STOP

暂停服务:SERVICE_CONTROL_PAUSE

恢复被暂停的服务:SERVICE_CONTROL_CONTINUE

返回服务的更新状态信息:SERVICE_CONTROL_INTERROGATE

D编写这个服务要实现的功能函数,也就是我们这个服务要完成什么功能,这里依然是输出电脑用户名

可见,一个完整的服务包括:

main():他告诉SCM 关于ServiceMain()的一些信息

ServiceMain():开始ServiceThread(),告诉SCM关于控制处理器的一些信息

ServiceCtrlHandler:接受来自SCM的请求并做出响应

InitThread():由ServiceMain()打开,执行我们的任务,,就是建立一个线程来运行我们的任务

5详说各个基本函数

A main()

SCM是一个管理系统所有服务的进程,当SCM启动某个服务时,它等待某个进程的主线程来调用StartServiceCtrlDispatcher(),这样把调用进程的住线程转换为控制分配器,控制分配器启动一个新线程,新线程运行分配表里每个服务的ServiceMain()

B ServiceMain()

是服务的入口点.它运行在一个单独的线程中,主要是为服务注册控制处理器,它指示控制分配器调用ServiceCtrlHandler()来处理SCM的请求,注册完成后将返回一个句柄

通过调用SetServiceStatus,用这个句柄和SERVICE_STATUS向SCM报告服务状态,,,因为这样的动作经常发生,,,所以我们把这个过程写成一个函数ReportStatusToSCMgr()

RegisterServiceCtrlHandler(strServiceName, (LPHANDLER_FUNCTION)ServiceCtrlHandler);

接着调用ReportStatusToSCMgr()向SCM报告服务状态 ReportStatusToSCMgr();

创建一个事件,在函数的最后将调用该事件来保持函数的运行知道SCM发出停止请求才返回 CreateEvent();

创建一个线程来运行我们的服务函数 sysnap();

最后ServiceThread()完成后返回ServiceMain(),ServiceMain()调用 WaitForSingleObject()

C ServiceCtrlHandler()

检查SCM发送了什么请求并且做出反应...当用户关闭系统,所有的控制处理要调用SetServiceStatus设置SERVICE_ACCEPT_SHUTDOWN控制码去接收SERVICE_CONTROL_SHUTDOWN控制码,如果服务需要时间去清除,它可以发送 STOP_PENDING状态消息,连同一个等待时间,这样,服务控制器在报告系统服务关闭之前才知道应该待多长时间,无论如何,都有一个服务控制器需要等待的时间,防止服务停留在shutdown状态。要改变这个时间限制,可以修改HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control中的WaitToKillServiceTimeout值。

switch(nControlCode)

{

case SERVICE_CONTROL_SHUTDOWN:

case SERVICE_CONTROL_STOP:

nServiceCurrentStatus=SERVICE_STOP_PENDING;

success=ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,0,1,3000);

KillService();

return;

default:

break;

}

6所用到的一些数据结构和API说明

本来想写,,算了.自己查MSDN///累....下面代码我会加点注射

下面就直接代码吧...可以自己编译

sv.exe的代码

#include <stdio.h>

#include <windows.h>

#include <winsvc.h>

//定义一些全局变量和函数

void ServiceMain(DWORD argc, LPTSTR *argv);

void ServiceCtrlHandler(DWORD dwControlCode);

//SCM报告服务状态信息

BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode,

DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,

DWORD dwWaitHint);

BOOL InitThread(); //创建线程来运行我们的任务

DWORD sysnap(LPDWORD param); //我们这个服务所要完成的任务

HANDLE hServiceThread;

void KillService();

char *strServiceName = "sysnap"; ////标识服务的内部名

SERVICE_STATUS_HANDLE nServiceStatusHandle; //存储调用RegisterServiceCtrlHandler返回的句柄

HANDLE killServiceEvent;

BOOL nServiceRunning;

DWORD nServiceCurrentStatus;

void main(int argc, char* argv[])

{

// SERVICE_TABLE_ENTRY 结构类型的数组,他包含了调用进程所提供的每个服务的入口函数和字符串名。表中的最后一个元素必须为 NULL,指明入口表结束

SERVICE_TABLE_ENTRY servicetable[]=

{

{strServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},

{NULL,NULL}

};

BOOL success;

// StartServiceCtrlDispatcher 函数负责把程序主线程连接到服务控制管理程序

success=StartServiceCtrlDispatcher(servicetable);

if(!success)

{

printf("fialed!");

}

}

void ServiceMain(DWORD argc, LPTSTR *argv)

{

BOOL success;

//把ServiceCtrlHandler注册为服务控制器,接受来自SCM的请求并做出处理,

nServiceStatusHandle=RegisterServiceCtrlHandler(strServiceName,

(LPHANDLER_FUNCTION)ServiceCtrlHandler);

//判断是否注册成功,否则返回

if(!nServiceStatusHandle)

{

return;

}

//注册成功后向SCM报告服务状态信息,因为服务还没初始化完成,所以当前服务状态为SERVICE_START_PENDING

success=ReportStatusToSCMgr(SERVICE_START_PENDING,NO_ERROR,0,1,3000);

if(!success)

{

return;

}

//创建一个事件,在函数的最后将用该事件来保持函数的运行直到SCM发出停止请求才返回

killServiceEvent=CreateEvent(0,TRUE,FALSE,0);

if(killServiceEvent==NULL)

{

return;

}

//向SCM报告服务状态信息

success=ReportStatusToSCMgr(SERVICE_START_PENDING,NO_ERROR,0,2,1000);

if(!success)

{

return;

}

//InitThread()创建一个线程来运行我们的sysnap()函数

success=InitThread();

if(!success)

{

return;

}

//我们的服务开始运行任务了,当前状态设置为SERVICE_RUNNING

nServiceCurrentStatus=SERVICE_RUNNING;

success=ReportStatusToSCMgr(SERVICE_RUNNING,NO_ERROR,0,0,0);

if(!success)

{

return;

}

//sysnap()函数运行完了之后返回ServiceMain(),ServiceMain()调用WaitForSingleObject,因为服务被停止之前ServiceMain()不会结束

WaitForSingleObject(killServiceEvent,INFINITE);

CloseHandle(killServiceEvent);

}

//向SCM报告服务状态信息,可以说是更新信息吧,它接受的参数都是SERVICE_STATUS结构成员

BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode,

DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,

DWORD dwWaitHint)

{

BOOL success;

SERVICE_STATUS nServiceStatus; //定义一个SERVICE_STATUS类型结构nServiceStatus

nServiceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; //表示我们的服务是独占一个进程的服务

nServiceStatus.dwCurrentState=dwCurrentState; //当前服务状态

//

if(dwCurrentState==SERVICE_START_PENDING)

{

nServiceStatus.dwControlsAccepted=0; //服务的初始化没有完成

}

else

{

nServiceStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP //通知 SCM 服务接受哪个域。这里允许 STOP 和SHUTDOWN 请求

|SERVICE_ACCEPT_SHUTDOWN;

}

//dwServiceSpecificExitCode在你终止服务并报告退出细节时很有用。初始化服务时并不退出,因此值为 0

if(dwServiceSpecificExitCode==0)

{

nServiceStatus.dwWin32ExitCode=dwWin32ExitCode;

}

else

{

nServiceStatus.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;

}

nServiceStatus.dwServiceSpecificExitCode=dwServiceSpecificExitCode;

//

nServiceStatus.dwCheckPoint=dwCheckPoint;

nServiceStatus.dwWaitHint=dwWaitHint;

//设置好nServiceStatus后,向SCM报告服务状态

success=SetServiceStatus(nServiceStatusHandle,&nServiceStatus);

if(!success)

{

KillService();

return success;

}

else

return success;

}

BOOL InitThread()

{

DWORD id;

hServiceThread=CreateThread(0,0,

(LPTHREAD_START_ROUTINE)sysnap,

0,0,&id);

if(hServiceThread==0)

{

return false;

}

else

{

nServiceRunning=true;

return true;

}

}

DWORD sysnap(LPDWORD param)

{

while(nServiceRunning)

{

Beep(450,150);

Sleep(4000);

}

return 0;

}

void KillService()

{

nServiceRunning=false;

SetEvent(killServiceEvent);

ReportStatusToSCMgr(SERVICE_STOPPED,NO_ERROR,0,0,0);

}

void ServiceCtrlHandler(DWORD dwControlCode)

{

BOOL success;

switch(dwControlCode)

{

case SERVICE_CONTROL_SHUTDOWN:

case SERVICE_CONTROL_STOP:

nServiceCurrentStatus=SERVICE_STOP_PENDING;

success=ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,0,1,3000);//先更新服务状态为SERVICDE_STOP_PENDING,再停止服务

KillService();

return;

default:

break;

}

ReportStatusToSCMgr(nServiceCurrentStatus,NO_ERROR,0,0,0);

}

svload.exe的代码

#include <stdio.h>

#include <windows.h>

#include <winsvc.h>

int main(int argc, char* argv[])

{

char* showInfo="sysnap's first Windows service";      //注意宽字符的转换(L)

char* showName="sysnap";

char* sv_Path="C://sysnap//sv.exe";

SC_HANDLE Hsysnap;

SC_HANDLE hSCManager;

hSCManager=OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);

if(!hSCManager)

{

printf("failed");

return 1;

}

Hsysnap=CreateService(hSCManager,TEXT(showName),

TEXT(showInfo),

SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,

SERVICE_ERROR_NORMAL,

sv_Path,

0,0,0,0,0);

if(!Hsysnap)

{

CloseServiceHandle(hSCManager);

printf("failed");

return 1;

}

CloseServiceHandle(Hsysnap);

CloseServiceHandle(hSCManager);

return 0;

}

俩个EXE文件一共334K....如果不想编译我可以把他们发到你邮葙

哈哈..谢谢给个精品..当时在写的时候认为很清晰..不过现在自己再看一遍..是比较长..我把他的整体弄上来,,,看了才不灰乱

void main() 

调用StartServiceCtrlDispatcher(),把控制交给控制分配器,控制分配器新建一个线程来运行ServiceMain..也就是真正进入服务 
}

void ServiceMain(DWORD argc, LPTSTR *argv) 
{

RegisterServiceCtrlHandler注册为服务控制器,接受来自SCM的请求并做出处理

创建一个事件,在函数的最后将用该事件来保持函数的运行直到SCM发出停止请求 才返回

创建一个线程来运行我们的函数

函数运行完了之后返回ServiceMain(),ServiceMain()调用  
}

BOOL ReportStatusToSCMgr() 

 填充SERVICE_STATUS 成员..并把它做为参数传给etServiceStatus()向SCM报告服务状 态

}

BOOL InitThread() 

创建运行sysnap()的线程 
}

DWORD sysnap(LPDWORD param) 

 我们要做的工作 
}

void KillService() 

停止服务 
}

void ServiceCtrlHandler(DWORD dwControlCode) 

接受来自SCM的请求并做出反应..这里要自己实现几个函数; 
}

总之记住看的时候以main(),ServiceMain()和ServiceCtrlHandler()为中心..其他函数都是比较简单的

http://blog.csdn.net/jiangxinyu/article/details/5265673

上一篇:Atitit.工作流系统的本质是dsl 图形化的dsl  4gl


下一篇:Tomcat 7最大并发连接数的正确修改方法(转)