最近写关于window服务程序的心得

最近的任务---老大让我把linux上的一个把键盘码解析成“行为”再给服务器发,使得键盘控制与服务器相连的摄像机的程序在window上用VC 写成window服务程序。

 

在这之前,小弟没有接触过window服务程序的编写,不过不要紧,有google嘛

 

进入正题,在google上看了很多关于window服务程序的编写,说法挺多,其实到最后都是一样的,就是那几个步骤。

 

这里我以自己的理解介绍个我感觉挺容易理解的版本:

首先yourfunction();函数,(这个函数就是你的工作函数,你服务程序要完成的工作)这很容易理解。

但是你的这个程序要放在ServiceMain(int argc, char* argv)函数中,ServiceMain函数是服务程序入口,就是说如果你的服务程序写好了,当你启动服务程序时,它是从这个函数进入的。在ServiceMain里你要完成的工作是为服务器注册控制处理器,就是下面这个函数:

hStatus = RegisterServiceCtrlHandler(szSvName,ControlHandler);

 if (NULL == hStatus) 
    { 
        //注册失败就返回  
        OutputDebugString(TEXT("注册服务失败!")); 
        return;  
    } 其中hStatus是SERVICE_STATUS_HANDLE类型,就是个句柄

然后设置服务的控制权限

ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP;

你需要服务可以被几个选项控制就 | 几个选项。SHUTDOWN 是关机 STOP是停止

对于相应的选择后面我们还要写对应的回应,就是ControlHandler(DWORD request)函数,它里面是个switch语句。

void WINAPI ControlHandler(DWORD request){

 switch(request)

 {

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

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

 break;

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

 

注册好后,就设置服务当前状态,现在我们刚刚进入服务程序,当然要设置成正在启动状态:

ServiceStatus.dwCurrentState = SERVICE_START_PENDING;

这样写完系统还是不知道服务的状态,我们需要把他发送出去,就用SetServiceStatus(hStatus,&ServiceStatus); 函数就行了

然后error = InitService(); //初始化数据

    if (error)  
    { 
        // 初始化失败,终止服务  
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;   //停止
        ServiceStatus.dwWin32ExitCode = -1;  
        SetServiceStatus(hStatus, &ServiceStatus); //向 SCM 报告服务的状态  
        return; // 退出 ServiceMain  
    } 

其实这个函数的作用就是“确认”的作用InitService里面的内容是自己写的,一般很简单这里的int InitService() 

    //获取系统目录地址,失败就返回-1  
    k = 100; 
    return 0; 
} 有时候我觉得也可以不写的

然后就是把当前状态设置成正在运行

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

后面就是放入我们的工作函数了

     while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) 
    {  
         if(k != 100) 
            return;  
          Sleep(3000); 
  yourfunction();
    }

最后写个

return;

这样ServiceMain就完成了,但是这样我们的服务程序还是没有完成,我们还需要MSC知道有这个服务,我们要让我们的服务在MSC窗口中出现,所以我们还要写个main函数,注意是main函数,但是却是相当简单的,如下;

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();
 return 0;
}
其中主要的就是 SERVICE_TABLE_ENTRY ServiceTable[2];数组和StartServiceCtrlDispatcher函数和CreateMyService函数

我们可以看到ServiceTable里面就是服务名和服务入口函数,当然我们这里简单,只有一个服务入口函数,当服务程序复杂时,有多个服务名和服务入口函数,到时候就有相互关联的问题了。
最后一定要有一对NULL!!

然后用StartServiceCtrlDispatcher函数就可启动服务的控制分派机线程 CreateMyService();函数的作用是使得你的服务出现在MSC上

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("E:\\devwork\\kbdresponse\\Debug\\kbdresponse.exe"),              //程序自身的地址
   NULL,
   NULL,
   NULL,
   NULL,
   NULL);
};

里面主要就是OpenSCManager和CreateService函数了

 

所以呢 我们要先main函数   ( 开启控制分派机线程)

再ServiceMain函数。       (为服务器注册控制处理器   按逻辑设置服务状态

ServiceMain函数里放我们的工作函数    

 

服务程序的调试问题

比如我们现在在MSC启动了服务,(VC6.0用,VC2005以上有附加到进程功能,但是VC6.0这方面不好使)到任务管理器里选择它,右键点击调试进入VC6.0环境,现在是出现汇编语句,这时你点击open打开你的主程序.cpp文件,在里面设置断点,就可以调试了,但是程序的有些地方调不了 这和你的内容有关。

 

还有遇到的socket在你开的线程里出现“不可用的套接字”错误,而主线程却没有错的问题,那可能是你开线程时的if判断语句写错,使得你虽然线程开成功了,却进入了if语句close掉了sock。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值