用C语言编写Windows服务程序的五个步骤

Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识,C(不是C++)是最佳选择。本文将建立并实现一个简单的服务程序,其功能是查询系统中可用物理内存数量,然后将结果写入一个文本文件。最后,你可以用所学知识编写自己的Windows 服务。

当初他写第一个NT 服务时,他到 MSDN 上找例子。在那里他找到了一篇 Nigel Thompson 写的文章:“Creating a Simple Win32 Service in C++”,这篇文章附带一个 C++ 例子。虽然这篇文章很好地解释了服务的开发过程,但是,他仍然感觉缺少他需要的重要信息。他想理解通过什么框架,调用什么函数,以及何时调用,但 C++ 在这方面没有让他轻松多少。面向对象的方法固然方便,但由于用类对底层 Win32 函数调用进行了封装,它不利于学习服务程序的基本知识。这就是为什么他觉得 C 更加适合于编写初级服务程序或者实现简单后台任务的服务。在你对服务程序有了充分透彻的理解之后,用 C++ 编写才能游刃有余。当他离开原来的工作岗位,不得不向另一个人转移他的知识的时候,利用他用 C 所写的例子就非常容易解释 NT 服务之所以然。

服务是一个运行在后台并实现勿需用户交互的任务的控制台程序。Windows NT/2000/XP 操作系统提供为服务程序提供专门的支持。人们可以用服务控制面板来配置安装好的服务程序,也就是 Windows 2000/XP 控制面板|管理工具中的“服务”(或在“开始”|“运行”对话框中输入 services.msc /s——译者注)。可以将服务配置成操作系统启动时自动启动,这样你就不必每次再重启系统后还要手动启动服务。

本文将首先解释如何创建一个定期查询可用物理内存并将结果写入某个文本文件的服务。然后指导你完成生成,安装和实现服务的整个过程。

第一步:主函数和全局定义
  
首先,包含所需的头文件。例子要调用 Win32 函数(windows.h)和磁盘文件写入(stdio.h):

  #include <windows.h>
#include <stdio.h>
  
接着,定义两个常量:

  #define SLEEP_TIME 5000
#define LOGFILE "C:\\MyServices\\memstatus.txt"
  
SLEEP_TIME 指定两次连续查询可用内存之间的毫秒间隔。在第二步中编写服务工作循环的时候要使用该常量。

LOGFILE 定义日志文件的路径,你将会用 WriteToLog 函数将内存查询的结果输出到该文件,WriteToLog 函数定义如下:

  int WriteToLog(char* str)
{
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL)
return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
  
声明几个全局变量,以便在程序的多个函数之间共享它们值。此外,做一个函数的前向定义:

  SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
  
现在,准备工作已经就绪,你可以开始编码了。服务程序控制台程序的一个子集。因此,开始你可以定义一个 main 函数,它是程序的入口点。对于服务程序来说,main 的代码令人惊讶地简短,因为它只创建分派表并启动控制分派机。
  
 void main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;

// 启动服务的控制分派机线程
  StartServiceCtrlDispatcher(ServiceTable);
}
  
一个程序可能包含若干个服务。每一个服务都必须列于专门的分派表中(为此该程序定义了一个 ServiceTable 结构数组)。这个表中的每一项都要在 SERVICE_TABLE_ENTRY 结构之中。它有两个域:

lpServiceName: 指向表示服务名称字符串的指针;当定义了多个服务时,那么这个域必须指定;
lpServiceProc: 指向服务主函数的指针(服务入口点);

分派表的最后一项必须是服务名和服务主函数域的 NULL 指针,文本例子程序中只宿主一个服务,所以服务名的定义是可选的。

服务控制管理器(SCM:Services Control Manager)是一个管理系统所有服务的进程。当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中每个服务的 ServiceMain 函数(本文例子中只有一个服务)分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。

注意:如果 StartServiceCtrlDispatcher 函数30秒没有被调用,便会报错,为了避免这种情况,他们必须在 ServiceMain 函数中(参见本文例子)或在非主函数的单独线程中初始化服务分派表。本文所描述的服务不需要防范这样的情况。

分派表中所有的服务执行完之后(例如,用户通过“服务”控制面板程序停止它们),或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。

  第二步:ServiceMain 函数

void ServiceMain(int argc, char** argv) 
{
BOOL bRet;

bRet = TRUE;
ServiceStatus.dwServiceType     =SERVICE_WIN32; 
ServiceStatus.dwCurrentState     =SERVICE_START_PENDING; 
ServiceStatus.dwControlsAccepted   =SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode    = 0; 
ServiceStatus.dwServiceSpecificExitCode = 0; 
ServiceStatus.dwCheckPoint     = 0;
ServiceStatus.dwWaitHint     = 0; 
hStatus = RegisterServiceCtrlHandler("SERVICENAME", (LPHANDLER_FUNCTION)ControlHandler); 
if (hStatus == (SERVICE_STATUS_HANDLE)0) 
{
   //登陆失败
   return;
}

// service状态情报更新
ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
SetServiceStatus (hStatus, &ServiceStatus);

while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
   {
      int result = startFunc();
      if (result)
      {
         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
         ServiceStatus.dwWin32ExitCode = -1; 
         SetServiceStatus(hStatus, &ServiceStatus);
         return;
      }
   }

return;
}

第三步:建立自己的startFunc()函数----愿意写点什么就写点什么吧。:)

第四步:安装和配置服务
  
程序编好了,将之编译成 exe 文件。本文例子创建的文件叫 MemoryStatus.exe,将它拷贝到 C:\MyServices 文件夹。为了在机器上安装这个服务,需要用 SC.EXE 可执行文件,它是 Win32 Platform SDK 中附带的一个工具。(译者注:Visaul Studio .NET 2003 IDE 环境中也有这个工具,具体存放位置在:C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\Bin\winnt)。使用这个实用工具可以安装和移除服务。其它控制操作将通过服务控制面板来完成。以下是用命令行安装 MemoryStatus 服务的方法:

sc create MemoryStatus binpath= c:\MyServices\MemoryStatus.exe

发出此创建命令。指定服务名和二进制文件的路径(注意 binpath= 和路径之间的那个空格)。安装成功后,便可以用服务控制面板来控制这个服务(参见图一)。用控制面板的工具栏启动和终止这个服务。
MemoryStatus 的启动类型是手动,也就是说根据需要来启动这个服务。右键单击该服务,然后选择上下文菜单中的“属性”菜单项,此时显示该服务的属性窗口。在这里可以修改启动类型以及其它设置。你还可以从“常规”标签中启动/停止服务。以下是从系统中移除服务的方法:

sc delete MemoryStatus

指定 “delete” 选项和服务名。此服务将被标记为删除,下次西通重启后,该服务将被完全移除

注意:service 服务是XP系统运行在C:\Windows\System32\下的。

2000系统是运行在C\Winnt\system\下的。

所以程序中有关路径的地方一定要注意了。

除了这两个系统,其他系统还没有测试过,不过可以自己测试一下,生成的目录在C:\memstatus.txt中,代码如下:

#include <windows.h>
#include <stdio.h>

#define SLEEP_TIME 3000
#define LOGFILE "C:\\memstatus.txt"

int WriteToLog(char* );

SERVICE_STATUS ServiceStatus; 
SERVICE_STATUS_HANDLE hStatus;

void ServiceMain(int argc, char** argv); 
void ControlHandler(DWORD request); 
//int InitService();

int main() 

    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = "MemoryStatus";
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    
    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;

//
    StartServiceCtrlDispatcher(ServiceTable); 
return 0;
}

void ServiceMain(int argc, char** argv) 

//   int error;

ServiceStatus.dwServiceType =    SERVICE_WIN32; 
   ServiceStatus.dwCurrentState =    SERVICE_START_PENDING; 
   ServiceStatus.dwControlsAccepted   =     SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
   ServiceStatus.dwWin32ExitCode = 0; 
   ServiceStatus.dwServiceSpecificExitCode = 0; 
   ServiceStatus.dwCheckPoint = 0; 
   ServiceStatus.dwWaitHint = 0;

hStatus = RegisterServiceCtrlHandler(
      "MemoryStatus", 
      (LPHANDLER_FUNCTION)ControlHandler); 
   if (hStatus == (SERVICE_STATUS_HANDLE)0) 
   { 
      return; 
   }

ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
   SetServiceStatus (hStatus, &ServiceStatus);

char memory[256];

while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
   {

GetCurrentDirectory(256,memory);

int result = WriteToLog(memory);
      if (result)
      {
         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
         ServiceStatus.dwWin32ExitCode = -1; 
         SetServiceStatus(hStatus, &ServiceStatus);
         return;
      }
      Sleep(SLEEP_TIME);
   }
   return; 
}

void ControlHandler(DWORD request) 

   switch(request) 
   { 
      case SERVICE_CONTROL_STOP: 
         WriteToLog("Monitoring stopped.");

ServiceStatus.dwWin32ExitCode = 0; 
         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
         SetServiceStatus (hStatus, &ServiceStatus);
         return;

case SERVICE_CONTROL_SHUTDOWN: 
         WriteToLog("Monitoring stopped.");

ServiceStatus.dwWin32ExitCode = 0; 
         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
         SetServiceStatus (hStatus, &ServiceStatus);
         return; 
        
      default:
         break;
    }

SetServiceStatus (hStatus, &ServiceStatus);

return; 
}

int WriteToLog(char* str)
{
    FILE* log;
    log = fopen(LOGFILE, "a+");
    if (log == NULL)
    return -1;
    fprintf(log, "%s\n", str);
    fclose(log);
    return 0;
}

////////////////下面看他的代码吧////////////////

//main.cpp

#include <windows.h>
void WINAPI ServiceMain(DWORD , char** ); 
void ControlHandler(DWORD ); 
int IntelligentStart();
void txtinput();
void read();
SERVICE_STATUS ServiceStatus; 
SERVICE_STATUS_HANDLE hStatus;
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR pchCmdLine, int iCmdShow )
{
    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = "IntelligentStart";
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    
    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;

StartServiceCtrlDispatcher(ServiceTable); 
return 0;
   
}

void WINAPI ServiceMain(DWORD ac, char **av) 
{

ServiceStatus.dwServiceType      = SERVICE_WIN32; 
   ServiceStatus.dwCurrentState     = SERVICE_START_PENDING; 
   ServiceStatus.dwControlsAccepted    =   SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
   ServiceStatus.dwWin32ExitCode     = 0; 
   ServiceStatus.dwServiceSpecificExitCode = 0; 
   ServiceStatus.dwCheckPoint      = 0; 
   ServiceStatus.dwWaitHint      = 0;

hStatus = RegisterServiceCtrlHandler("IntelligentStart", (LPHANDLER_FUNCTION)ControlHandler); 
   if (hStatus == (SERVICE_STATUS_HANDLE)0) 
   { 
      // Registering Control Handler failed
      return; 
   }

//Report the running status to SCM. 
   ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
   SetServiceStatus (hStatus, &ServiceStatus);

// The worker loop of a service
   while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
   {
      int result = IntelligentStart();
      if (result)
      {
         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
         ServiceStatus.dwWin32ExitCode = -1; 
         SetServiceStatus(hStatus, &ServiceStatus);
         return;
      }
   }
   return; 
}

void ControlHandler(DWORD request) 

   switch(request) 
   { 
      case SERVICE_CONTROL_STOP: 
         ServiceStatus.dwWin32ExitCode = 0; 
         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
         SetServiceStatus (hStatus, &ServiceStatus);
         return;

case SERVICE_CONTROL_SHUTDOWN: 
         ServiceStatus.dwWin32ExitCode = 0; 
         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
         SetServiceStatus (hStatus, &ServiceStatus);
         return; 
        
      default:
         break;
    }

// Report current status
    SetServiceStatus (hStatus, &ServiceStatus);

return; 
}

int IntelligentStart()
{

txtinput();
return 0;
}

write.cpp

#include <stdio.h>
#include <conio.h>
void txtinput()
{
FILE *fp;
char st[20] = "test new.\n";
fp=fopen("C:\\string.txt","at+");

fputs(st,fp);

fclose(fp);

return ;
}

http://blog.csdn.net/w616589292/article/details/24265739

时间: 2024-08-24 02:16:35

用C语言编写Windows服务程序的五个步骤的相关文章

C语言编写Windows服务程序

原文:C语言编写Windows服务程序 #include <Windows.h> #include <stdio.h> #define SLEEP_TIME 5000 // 间隔时间 #define LOGFILE "C:\\memstatus.txt" // 信息输出文件 SERVICE_STATUS ServiceStatus; // 服务状态 SERVICE_STATUS_HANDLE hStatus; // 服务状态句柄 void ServiceMain

C#编写Windows服务程序图文教程(转载)

Windows Service这一块并不复杂,但是注意事项太多了,网上资料也很凌乱,偶尔自己写也会丢三落四的.所以本文也就产生了,本文不会写复杂的东西,完全以基础应用的需求来写,所以不会对Windows Service写很深入. 本文介绍了如何用C#创建.安装.启动.监控.卸载简单的Windows Service 的内容步骤和注意事项. 一.创建一个Windows Service 1)创建Windows Service项目 2)对Service重命名 将Service1重命名为你服务名称,这里我

c# 编写Windows服务程序

1.Windows服务程序 在没有涉及到这个问题的时候我也不太明白他里面的深刻奥义.后来知道了这是一个能够长时间运行的应用程序,这个服务只要配置自动启动那么在windows开机启动的时候自动运行起,他没有界面.在Windows机器上能够通过管理工具/服务进行系统运行的所有服务的查看和管理.系统的大部分软件和硬件的运行状态监控都是通过Windows服务进行监控的,通过服务不断轮训去请求BIOS提供的端口收集BIOS收集的硬件的运行状态.可能他们又通过不同的媒介进行展示如windows计数器进行性能

使用C语言编写windows服务一般框架

原文:使用C语言编写windows服务一般框架 编写windows服务和编写windows应用程序一样,有一些回调函数必须填写且向windows 服务管理器(service manager)进行注册,否则会导致服务启动失败.因近期写个服务,其中遇到一些有问题,有部分内容想和大家分享一下,请大家指正. windows服务一般框架代码如下: #include <Windows.h> #include <tchar.h> VOID WINAPI ServiceHandler(DWORD

C#编写Windows服务程序 (服务端),client使用 消息队列 实现淘宝 订单全链路效果

需求: 针对 淘宝提出的 订单全链路 产品接入 .http://open.taobao.com/doc/detail.htm?id=102423&qq-pf-to=pcqq.group oms(订单管理系统) 实现  , 完毕后 效果:在千牛工作台 --订单全链路  可看到效果例如以下图   -------------------------------------------------------------------------------------------------------

C#编写Windows服务程序 (服务端),客户端使用 消息队列 实现淘宝 订单全链路效果

需求: 针对 淘宝提出的 订单全链路 产品接入 .http://open.taobao.com/doc/detail.htm?id=102423&qq-pf-to=pcqq.group oms(订单管理系统) 实现  , 完成后 效果:在千牛工作台 --订单全链路  可看到效果如下图   ---------------------------------------------------------------------------------------------------------

用c语言编写windows服务

主要是根据从www.vcbase.com上看到的一篇文章来做这个windows服务的.但是这篇文章一些关键代码并没有贴出来,然而有心人根据作者的描述实现了代码,并且完整的贴了出来,地址是在 http://www.2cto.com/kf/201111/111990.html 我创建的是一个空项目,这个默认的应该是控制台项目.服务的主函数是main而不是winmain,要写一个服务首先要初始化一个SERVICE_TABLE_ENTRY 分派表结构体的列表,然后调用StartServiceCtrlDi

C# 编写Windows Service(windows服务程序)

Windows Service简介: 一个Windows服务程序是在Windows操作系统下能完成特定功能的可执行的应用程序.Windows服务程序虽然是可执行的,但是它不像一般的可执行文件通过双击就能开始运行了,它必须有特定的启动方式.这些启动方式包括了自动启动和手动启动两种.对于自动启动的Windows服务程序,它们在Windows启动或是重启之后用户登录之前就开始执行了.只要你将相应的Windows服务程序注册到服务控制管理器(Service Control Manager)中,并将其启动

C# 编写Windows Service(windows服务程序)【转载】

[转]http://www.cnblogs.com/bluestorm/p/3510398.html Windows Service简介: 一个Windows服务程序是在Windows操作系统下能完成特定功能的可执行的应用程序.Windows服务程序虽然是可执行的,但是它不像一般的可执行文件通过双击就能开始运行了,它必须有特定的启动方式.这些启动方式包括了自动启动和手动启动两种.对于自动启动的Windows服务程序,它们在Windows启动或是重启之后用户登录之前就开始执行了.只要你将相应的Wi