windows服务

本文是Devour Heavens撰写整理的关于windows服务的知识,所有资料均来自于msdn官方文档,欢迎转载。但是为了尊重原作者的劳动,请注明出处!谢谢!

windows服务

1.基本概念

服务是一种在系统中常驻的程序,服务可以在系统启动时自启动(先于用户登录)。当一个应用程序需要常驻在系统,或者随时为其他应用程序提供服务时,可以使用服务应用程序。一般编写网络服务端程序时需要使用服务。windows系统中具有一个服务控制器(SCM)用于控制服务。

1.1 服务控制器(SCM)

服务控制器对系统中所有服务进行管理,SCM管理着系统中已经安装的服务应用程序和设备驱动程序数据库,数据库中保存的信息包括系统安装了哪些服务,每个服务包括包括如何启动每个服务、各个服务的安全属性以及控制接口等。

服务程序、服务配置程序和服务控制程序的设计都需要使用SCM提供的函数。

1.2 服务程序(Service Programs)

一个服务程序包含的可执行代码可以为一个或多个服务使用。服务程序以SERVICE_WIN32_OWN_PROCESS类型创建表示为一个服务拥有,以SERVICE_WIN32_SHARE_PROCESS创建表示为多个服务所共享。SERVICE_FILE_SYSTEM_PROCESS 类型表示文件系统驱动服务,SERVICE_KERNEL_DRIVER 类型表示驱动服务。

一个服务程序至少包括入口函数、服务主函数、控制处理函数。

1.2.1 入口函数

入口函数是可执行程序的起点,服务程序的入口函数与一般可执行程序的入口函数没有区别。

1.2.2 服务主函数ServiceMain

服务主函数一般称作ServiceMain函数。但是服务主函数的名称与线程函数ThreadPro一样,其函数名并没有特殊要求,只是其参数接口和调用类型必须与要求一致。ServiceMain函数的原型如下:

VOID WINAPI ServiceMain( 

 DWORD dwArgc, 

 LPTSTR *lpszArgv);

服务函数的参数与main函数的参数使用方法类似,但是服务主函数的参数不是通过在命令行自启动时设定的,而是通过SCM的相关API进行传递的(StartService)。

向SCM注册服务的主函数StartServiceCtrlDispatcher,服务程序通过调用它设置服务主函数,同时通知SCM。

StartServiceCtrlDispatcher函数的原型如下:

BOOL WINAPI StartServiceCtrlDispatcher( 

const SERVICE_TABLE_ENTRY *lpServiceTable

);

结构体SERVICE_TABLE_ENTRY的原型如下:

typedef struct _SERVICE_TABLE_ENTRY { 

LPTSTR lpServiceName; 

LPSERVICE_MAIN_FUNCTION lpServiceProc;

} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;

其中lpServiceName为服务名称,lpServiceProc为指向ServiceMain的函数指针。只要将函数的指针赋值给lpServiceProc,再调用StartServiceCtrlDispatcher,这个函数就成为了服务主函数。

1.2.3 控制处理函数

控制处理函数用于处理SCM向服务传递的服务控制请求。控制处理函数Handler原型如下:

VOID WINAPI Handler(

  DWORD fdwControl

);

与ServiceMain函数一致,其函数名没有特殊要求。

注册控制管理函数API函数RegisterServiceCtrlHandler用于向SCM设置一个服务的控制处理函数。

SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandler(

  LPCTSTR lpServiceName,

  LPHANDLER_FUNCTION lpHandlerProc

);

其中lpServiceName为服务名称,lpHandlerProc为Handler函数指针。

1.2.4 服务程序解析


#include <windows.h>
SERVICE_STATUS          SplSrvServiceStatus;
SERVICE_STATUS_HANDLE   SplSrvServiceStatusHandle;
VOID SvcDebugOut(LPSTR String, DWORD Status);
VOID WINAPI SplSrvServiceCtrlHandler (DWORD opcode);
VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv);
DWORD SplSrvServiceInitialization (DWORD argc, LPTSTR *argv,
           DWORD *specificError);
VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv)
{
 DWORD status;
 DWORD specificError;
 // 填充SERVICE_STATUS 结构
 SplSrvServiceStatus.dwServiceType        = SERVICE_WIN32;
 SplSrvServiceStatus.dwCurrentState      
  = SERVICE_START_PENDING;  
 SplSrvServiceStatus.dwControlsAccepted  
  = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
 SplSrvServiceStatus.dwWin32ExitCode      = 0;
 SplSrvServiceStatus.dwServiceSpecificExitCode = 0;
 SplSrvServiceStatus.dwCheckPoint         = 0;
 SplSrvServiceStatus.dwWaitHint           = 0;
 // 注册服务控制请求处理例程
 SplSrvServiceStatusHandle = RegisterServiceCtrlHandler(
  "Sample_Srv",
  SplSrvServiceCtrlHandler); 

 if (SplSrvServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
 {
  SvcDebugOut(" [SPLSRV_SERVICE] RegisterServiceCtrlHandler "
   "failed %d\n", GetLastError());
  return;
 } 
 
 status = SplSrvServiceInitialization(argc,argv, &specificError); 
 if (status != NO_ERROR)
 {
  SplSrvServiceStatus.dwCurrentState       = SERVICE_STOPPED;
  SplSrvServiceStatus.dwCheckPoint         = 0;
  SplSrvServiceStatus.dwWaitHint           = 0;
  SplSrvServiceStatus.dwWin32ExitCode      = status;
  SplSrvServiceStatus.dwServiceSpecificExitCode = specificError;

  SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus);
  return;
 }
 SplSrvServiceStatus.dwCurrentState       = SERVICE_RUNNING;
 SplSrvServiceStatus.dwCheckPoint         = 0;
 SplSrvServiceStatus.dwWaitHint           = 0;

 if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus))
 {
  status = GetLastError();
  SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld\n",status);
 }
 SvcDebugOut(" [SPLSRV_SERVICE] Returning the Main Thread \n",0);

 return;
}


DWORD SplSrvServiceInitialization(DWORD   argc,
          LPTSTR  *argv,
          DWORD *specificError)
{
 return(0);
}

VOID WINAPI SplSrvServiceCtrlHandler (DWORD Opcode)
{
 DWORD status;
 switch(Opcode)
 {
 case SERVICE_CONTROL_PAUSE:
  
  SplSrvServiceStatus.dwCurrentState = SERVICE_PAUSED;
  break;
 case SERVICE_CONTROL_CONTINUE:
  
  SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING;
  break;
 case SERVICE_CONTROL_STOP:
  
  SplSrvServiceStatus.dwWin32ExitCode = 0;
  SplSrvServiceStatus.dwCurrentState  = SERVICE_STOPPED;
  SplSrvServiceStatus.dwCheckPoint    = 0;
  SplSrvServiceStatus.dwWaitHint      = 0;

  if (!SetServiceStatus (SplSrvServiceStatusHandle,
   &SplSrvServiceStatus))
  {
   status = GetLastError();
   SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld\n",
    status);
  } 
  SvcDebugOut(" [SPLSRV_SERVICE] Leaving SplSrvService \n",0);
  return;
 case SERVICE_CONTROL_INTERROGATE:
  
  MessageBeep(MB_OK);
  break;
 default:
  SvcDebugOut(" [SPLSRV_SERVICE] Unrecognized opcode %ld\n",
   Opcode);
 }
 if (!SetServiceStatus (SplSrvServiceStatusHandle,  &SplSrvServiceStatus))
 {
  status = GetLastError();
  SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld\n",
   status);
 }
 return;
}

void main( )
{
 SERVICE_TABLE_ENTRY   DispatchTable[] =
 {
  { "Sample_Srv", (LPSERVICE_MAIN_FUNCTION) SplSrvServiceStart },
  { NULL, NULL }
 };
 if (!StartServiceCtrlDispatcher( DispatchTable))
 {
  SvcDebugOut(" [SPLSRV_SERVICE] StartServiceCtrlDispatcher (%d)\n",
   GetLastError());
 }
}

VOID SvcDebugOut(LPSTR String, DWORD Status)
{
 CHAR  Buffer[1024];
 if (strlen(String) < 1000)
 {
  wsprintf(Buffer, String, Status);
  OutputDebugString(Buffer);
 }
}

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值