服务程序编写-------详细介绍如何构建你自己的服务程序(上)

from:http://blog.sina.com.cn/s/blog_61d65e360100np53.html

服务程序编写-------详细介绍如何构建你自己的服务程序(上)

(2010-12-12 13:59:04)
  

服务程序编写详细教程

服务,作为Windows的重要组成部分,一直以来充满了神秘感。网络上流传的相关教程不是代码不全就是讲解的模模糊糊。总之会让你晕头转向直到放弃学习为止。这是我们不愿意看到的。因此,笔者给大家送上完整的解决方案。通过这3节的学习,读者就能够编写出自己的服务程序。

自报家门,我来自东方微点。

代码开始:(visual studio 2005)上编译通过。

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <ntdll.h> (1)
#include <Psapi.h> (2)


#define ServiceNameFirst L"Yankai" (3)
#define ServiceDisplayNameFirst L"Yankai-cleveise" (4)
#define ServiceNameSec L"Liufei" (3)
#define ServiceDisplayNameSec L"Liufei-cleveise" (4)

typedef NTSTATUS (*MyNtTerminateProcess)( HANDLE, NTSTATUS); (X)

/

void WINAPI YankaiMain(DWORD argc,LPTSTR* argv); (5)
void WINAPI LiufeiMain(DWORD argc,LPTSTR* argv); (5)

void InstallService();
///
void WINAPI YankaiServiceCtrlHandler(DWORD dwControl); (6)
void WINAPI LiufeiServiceCtrlHandler(DWORD dwControl);
///
DWORD WINAPI YankaiThreadProc(LPVOID pParam); (7)
DWORD WINAPI LiufeiThreadProc(LPVOID pParam);
///

int a ;
///
HANDLE YankaiMainEvent;
HANDLE LiufeiMainEvent;

HANDLE YankaiThread;
HANDLE LiufeiThread;

DWORD YankaiThreadID;
DWORD LiufeiThreadID;
DWORD NtTerminateProcessAddress;

HANDLE ProcessOne;

///

SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE ServiceStatusHandleYYY;
SERVICE_STATUS_HANDLE ServiceStatusHandleLLL;

int main (int argc , char* argv[]) // 服务进程主入口。
{

SC_HANDLE SCMHandle;
SC_HANDLE ServiceHandle;
SERVICE_TABLE_ENTRY ServiceTable[3]={ServiceNameFirst, YankaiMain,ServiceNameSec, LiufeiMain,NULL, NULL } ; (8)
SCMHandle= OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

ServiceHandle= OpenService(SCMHandle,ServiceNameFirst,SC_MANAGER_ALL_ACCESS);

if (ServiceHandle == 0)

{
InstallService(ServiceNameFirst,ServiceNameSec);
return 0;
}
YankaiMainEvent= CreateEvent(NULL,TRUE,FALSE, L"YankaiEvent");

LiufeiMainEvent= CreateEvent(NULL,TRUE,FALSE, L"LiufeiEvent");
StartServiceCtrlDispatcher(ServiceTable);

CloseServiceHandle(SCMHandle);
CloseServiceHandle(ServiceHandle);
return 0 ;

}

void InstallService()
{
SC_HANDLE SCMhandle;
SC_HANDLE ServiceHandle;
char SzFileName[256];
SCMhandle= OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); (9)

GetModuleFileName(NULL,(LPTSTR)SzFileName, 255);
ServiceHandle=CreateService(SCMhandle,ServiceNameFirst,ServiceDisplayNameFirst,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,(LPTSTR)SzFileName, NULL,
NULL, NULL, NULL, NULL); (10)

if (0==ServiceHandle)
{
return ;
}
ServiceHandle= CreateService(SCMhandle,ServiceNameSec,ServiceDisplayNameSec,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,(LPTSTR)SzFileName, NULL,
NULL, NULL, NULL, NULL); (10)

if (0==ServiceHandle)
{
return ;
}

CloseServiceHandle(SCMhandle);
CloseServiceHandle(ServiceHandle);
}


void WINAPI YankaiMain(DWORD argc,LPTSTR * argv)
{
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS ;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_STOP ;

ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;

SetServiceStatus(ServiceStatusHandleYYY,&ServiceStatus); (11)

ServiceStatusHandleYYY= RegisterServiceCtrlHandler(ServiceNameFirst, YankaiServiceCtrlHandler); (12)
if (ServiceStatusHandleYYY==0)
{
return ;
}
SetServiceStatus(ServiceStatusHandleYYY,&ServiceStatus); (13)

YankaiThread=CreateThread(NULL,0,YankaiThreadProc,NULL,0,&YankaiThreadID);
if (YankaiThread>0)
{
ServiceStatus.dwCurrentState = SERVICE_RUNNING;

}
else
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;

}
SetServiceStatus(ServiceStatusHandleYYY,&ServiceStatus); (14)

//SERVICE RUNNING

WaitForSingleObject(YankaiMainEvent,0); (15)
}

void WINAPI LiufeiMain(DWORD argc,LPTSTR * argv)
{
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_STOP ;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;

SetServiceStatus(ServiceStatusHandleLLL,&ServiceStatus);

ServiceStatusHandleLLL= RegisterServiceCtrlHandler(ServiceNameSec, LiufeiServiceCtrlHandler);
if (0==ServiceStatusHandleLLL)
{
return ;
}

SetServiceStatus(ServiceStatusHandleLLL,&ServiceStatus);

LiufeiThread=CreateThread(NULL,0,LiufeiThreadProc,NULL,0,&LiufeiThreadID);

if (LiufeiThread>0)
{
ServiceStatus.dwCurrentState = SERVICE_RUNNING;

}
else
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;

}
SetServiceStatus(ServiceStatusHandleLLL,&ServiceStatus);
//SERVICE RUNNING
WaitForSingleObject(LiufeiMainEvent,0);
}

void WINAPI YankaiServiceCtrlHandler(DWORD dwControl)
{

switch(dwControl)
{
case SERVICE_CONTROL_PAUSE: (16)
ServiceStatus.dwCurrentState=SERVICE_PAUSED;
SetServiceStatus(ServiceStatusHandleYYY, &ServiceStatus);
SuspendThread(YankaiThread);
break;
case SERVICE_CONTROL_CONTINUE: (17)
ServiceStatus.dwCurrentState=SERVICE_RUNNING;
SetServiceStatus(ServiceStatusHandleYYY, &ServiceStatus);
ResumeThread(YankaiThread);
break;
case SERVICE_CONTROL_STOP: (18)
TerminateThread(YankaiThread,0);
ServiceStatus.dwCurrentState=SERVICE_STOPPED;
SetServiceStatus(ServiceStatusHandleYYY, &ServiceStatus);
break;
case SERVICE_CONTROL_SHUTDOWN: (19)
TerminateThread(YankaiThread,0);
SetEvent(YankaiMainEvent);
break;
case SERVICE_CONTROL_INTERROGATE: (20)
SetServiceStatus(ServiceStatusHandleYYY, &ServiceStatus);
break;
}


}

void WINAPI LiufeiServiceCtrlHandler(DWORD dwControl)
{

switch(dwControl)
{
case SERVICE_CONTROL_PAUSE:
SuspendThread(LiufeiThread);
ServiceStatus.dwCurrentState=SERVICE_PAUSED;
SetServiceStatus(ServiceStatusHandleLLL, &ServiceStatus);
break;
case SERVICE_CONTROL_CONTINUE:
ResumeThread(LiufeiThread);
ServiceStatus.dwCurrentState=SERVICE_RUNNING;
SetServiceStatus(ServiceStatusHandleLLL, &ServiceStatus);
break;
case SERVICE_CONTROL_STOP:
TerminateThread(LiufeiThread,0);
ServiceStatus.dwCurrentState=SERVICE_STOPPED;
SetServiceStatus(ServiceStatusHandleLLL, &ServiceStatus);
break;
case SERVICE_CONTROL_SHUTDOWN:
TerminateThread(LiufeiThread,0);
SetEvent(LiufeiMainEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
SetServiceStatus(ServiceStatusHandleLLL, &ServiceStatus);
break;
}


}


DWORD WINAPI YankaiThreadProc(LPVOID pParam) (21)
{

while(1)
{
Sleep(10000);

};
}


DWORD WINAPI LiufeiThreadProc(LPVOID pParam) (22)
{
do
{
Sleep(10000);

}while(1);


服务程序编写-------详细介绍如何构建你自己的服务程序(中)

(2010-12-12 14:31:15)
  

服务程序编写详细教程

在开始之前,笔者要介绍下windows程序的体系结构。具体有以下几点:

1,windows能加载,运行的文件都必须符合PE结构。我们常见的符合PE结构的文件有:SYS,EXE,DLL。

2,服务可以有两种存在方式:1,封装在EXE里面 2,封装在DLL里面。

3,封装在EXE里面的服务,一般被系统加载或者说你“手动启动”它的时候,其对应的EXE程序将会运行。你可以到进程管理器下查看其进程。

4,封装在DLL里的服务,它的启动必须依赖某个宿主程序,这个宿主程序就是svchost.exe.

5,服务程序运行在用户空间。它属于应用程序范畴。

就目前而言,我们所涉及的程序有:驱动程序,驱动设备,窗口应用程序,控制台应用程序,服务程序。那么他们对应的机制分别是:

1,驱动程序:他的运行机制和控制台应用程序非常相似,就是个程序流。经常使用的同步技术有互斥,事件,信号量,自旋锁,IRQL。

2,驱动设备:驱动设备又叫设备,它是由驱动程序创建。它的运行机制是“IRP”消息机制。

3,窗口应用程序:他的运行机制是消息驱动,不同的消息会执行不同的代码。经常使用的同步技术有互斥,事件,信号量。

4,控制台应用程序:他的运行机制也是程序流。同步技术有互斥,事件,信号量。

5,服务程序:他的运行机制是 “控制驱动”。正如你所看到的,你可以暂停,重启,停止,启动相关服务。因此服务程序一般都会包含相关控制代码。同样,它也会使用同步技术进行必要的同步处理。

关于服务程序(EXE文件),它可以包含1个或多个服务。正如你所看到的,上节中我所举例的代码就是双服务程序代码,很具有代表性和针对性!毕竟网络上流传的所有服务代码都只是单服务,肯定会给很多渴望学会编写多服务程序的朋友带来不爽。这是我不希望看到的。

我们都非常熟悉窗口程序的机制,那么我就联系窗口程序机制来讲解服务程序机制。你将会发现,他们之间在理解上有80%是相同的。OK,我们来分析分析先:(注意上节中的标号,笔者会针对标号来讲解)

1,2,由于笔者自己写程序的时候经常用到NTDLL.DLL和PSAPI.DLL里的函数,因此这2个头文件的包含就没有删除。你在编译上节代码的时候务必把NTDLL.h PSAPI.h这2个文件放到编译程序include目录下。不然会报错。

3,4,正如笔者上面所提到的,一个服务程序里可以包含多个服务,并且上节代码就是一个典型的双服务代码,因此我定义了2个服务名和2个服务显示名。

5,试想一下,我们现在打算把2个服务塞到一个EXE里面,并且很多时候服务之间的运行是彼此独立。因此我们没有理由不为这2个服务都分别定义自己的入口点。

6,上面已经说过,服务这个东东是“控制驱动”,那么很显然要注册一个控制处理函数。正如你编写窗口程序必须注册窗口过程函数,道理是一样的。从代码中你也会发现控制处理函数和窗口过程函数类似,里面也包含 Switch case语句。

7,笔者定义的一个线程回调函数,因为笔者一会要创建一个线程玩玩。

8,标号8的上面一点点有个 main函数,它是程序的入口。请读者注意区别理解程序入口和服务入口。这个地方我定义了一个数组,描述的是我将要创建的服务的服务名和服务入口函数的对应关系。毕竟每个服务都必须有自己对应的入口点,所以必须要告诉系统这些信息。xxx这个地方调用的函数实现上面描述的功能。

9,程序运行的时候我先尝试打开我的服务,如果能够打开,那么就不创建了,如果不能打开,那么就去创建。这点很好理解。

下节继续。。。。。。。。。。。。。。。。。。。。。

服务程序编写-------详细介绍如何构建你自己的服务程序(下)

(2010-12-12 15:35:49)
标签:

杂谈

 

服务程序编写详细教程

10,上面已经尝试打开自己定义的服务,如果打不开,这里就开始创建。由于我这个程序是双服务程序,因此我调用了2次CreateService()函数。

xx,关于每个服务的入口函数,它就相当窗口程序的winmain函数,我们知道,winmain函数如果返回了,那么程序也就退出了。因此我们窗口winmain函数里封装了个死循环(大名鼎鼎的消息循环)。同理,如果某个服务的入口函数返回了,那么就表示此服务停止了。怎么办呢?很简单,创建一个事件对象就可以轻松解决。请读者好好看下代码,自然会明白。

11,现在来看看服务的入口函数。11标号这个地方非常重要,入口函数的开头部分必须设置好此服务的一些属性和状态并立刻通过SetServiceStatus()告诉系统。正如你所看到的,我创建的服务支持暂停,停止,恢复等控制。如果你不及时调用这个函数的话,那么你会发现你的服务就不会支持暂停和恢复控制。这点非常重要。

12,正如我上面所说,服务这个东东会被用户控制,比如暂停,恢复,重启等等。因此我们必须为每个服务都分别定义自己的“控制过程函数”,这所谓的控制处理函数就好像“消息过程函数”一样。它是“控制驱动”机制的灵魂。

13,再次告诉下此时此刻本服务的状态。

14,你会看到,在14标号上面,我创建了一个线程。由于此服务非常简单,笔者的目的就是创建一个线程,既然目的已经达到,所以没有理由不告诉系统此服务已经运行。

15,上面已经说过了,服务的入口函数千万别退出,因此这个地方就是精髓。

接下来的一些标号,都比较的简单,笔者就不讲解了。还请仔细领悟服务编写的精髓。

在笔者看来,只要提供读者详细的,负责任的源代码,那么就是对读者最大的帮助。剩下来的就是读者自己去百度,google了。

OK,服务的讲解到此结束。谢谢大家


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值