如何用ACE来实现一个windows Service

好久没来写技术文章,归结原因依旧是很忙。
有时间就多写一些吧。
最近有朋友在我的 开源 服务器 上做了一个windows服务版本,挺有趣,于是我想把这个功能和我的服务器做一个整合,一开始并不顺利,原因是自己对windows服务的流程不熟悉。走了一些弯路,在这里记录下来,供大家参考。
其实windows下的服务和 Linux 下的服务大相径庭,linux下的步骤大概在7步,实际上一个function即可完成,windows下的服务必须先注册,再运行,当然,如果你想删除服务,还的有一个删除的步骤。
这篇文章先讨论windows下的服务开启和启动。
首先,先要了解一个类, ACE _NT_Service
这个类是一个标准的windows服务类,我们要创建一个自己的服务,就必须先继承它,
这里有几个函数,我需要再这里说明一下。
  1. class CProgramService : public  ACE_NT_Service
  2. {
  3. public:
  4.         CProgramService(void);
  5.         ~CProgramService(void);

  6.         virtual int svc(void);

  7.         virtual int  handle_exception (ACE_HANDLE h);

  8.         virtual void handle_control (DWORD control_code);

  9. private:
  10.         typedef ACE_NT_Service inherited;

  11. private:
  12.         bool m_blsStop;
  13. };class CProgramService : public  ACE_NT_Service
  14. {
  15. public:
  16.         CProgramService(void);
  17.         ~CProgramService(void);

  18.         virtual int svc(void);

  19.         virtual int  handle_exception (ACE_HANDLE h);

  20.         virtual void handle_control (DWORD control_code);

  21. private:
  22.         typedef ACE_NT_Service inherited;

  23. private:
  24.         bool m_blsStop;
  25. };
复制代码
svc() 这个函数是用来处理服务运行的,你可以在这里添加你的任意代码,比如一个死循环,或者一个你需要执行的函数。
handle_control ()函数是当windows service管理控制器被操作的时候,比如点击运行,暂停,停止,重新运行等,会对应这些消息被投递到这里。control_code就是这些消息类型。你可以case一下,用作你的处理。
handle_exception ()是当异常发生的时候,通知windows service你的进程当前的状态,从而统一service管理器对你的服务状态的完整监控。

好了,知道以上几个接口,基本能够完成windows service的所有控制了。
那么下面,我们来看怎么控制。
  1. ACE_NT_SERVICE_DEFINE (freeeyes, CProgramService, ACE_TEXT("freeeyes Service"));
复制代码
这行代码是必要的,这个宏的意思是说,把Service对应的接口绑定给 CProgramService类,也就是你的 ACE_NT_Service。
为了方便测试服务的启动和注册,借用一下ACE例子里面的一个类。
  1. class Process
  2. {
  3. public:
  4.         Process (void);
  5.         ~Process (void);

  6.         int run(int argc, ACE_TCHAR* argv[]);

  7. private:
  8.         void parse_args (int argc,
  9.                 ACE_TCHAR* argv[]);
  10.         void print_usage_and_die (void);

  11. private:
  12.         char progname[128];

  13.         int opt_install;
  14.         int opt_remove;
  15.         int opt_start;
  16.         int opt_kill;
  17.         int opt_type;
  18.         int opt_debug;

  19.         int opt_startup;
  20. };

  21. typedef ACE_Singleton<Process, ACE_Mutex> PROCESS;

  22. Process::Process (void)
  23. : opt_install (0),
  24. opt_remove (0),
  25. opt_start (0),
  26. opt_kill (0),
  27. opt_type (0),
  28. opt_debug (0),
  29. opt_startup (0)
  30. {
  31.         ACE_OS::strcpy (progname,
  32.                 "service");
  33.         ACE::init ();
  34. }

  35. Process::~Process (void)
  36. {
  37.         ACE::fini ();
  38. }

  39. void
  40. Process::print_usage_and_die (void)
  41. {
  42.         ACE_DEBUG ((LM_INFO,
  43.                 "Usage: %s"
  44.                 " -in -r -s -k -tn -d\n"
  45.                 "  -i: Install this program as an NT service, with specified startup\n"
  46.                 "  -r: Remove this program from the Service Manager\n"
  47.                 "  -s: Start the service\n"
  48.                 "  -k: Kill the service\n"
  49.                 "  -t: Set startup for an existing service\n"
  50.                 "  -d: Debug; run as a regular application\n",
  51.                 progname,
  52.                 0));
  53.         ACE_OS::exit(1);
  54. }

  55. void
  56. Process::parse_args (int argc, ACE_TCHAR* argv[])
  57. {
  58.         ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:rskt:d"));
  59.         int c;

  60.         while ((c = get_opt ()) != -1)
  61.                 switch (c)
  62.         {
  63.                 case 'i':
  64.                         opt_install = 1;
  65.                         opt_startup = ACE_OS::atoi (get_opt.opt_arg());
  66.                         if (opt_startup <= 0)
  67.                                 print_usage_and_die ();
  68.                         break;
  69.                 case 'r':
  70.                         opt_remove = 1;
  71.                         break;
  72.                 case 's':
  73.                         opt_start = 1;
  74.                         break;
  75.                 case 'k':
  76.                         opt_kill = 1;
  77.                         break;
  78.                 case 't':
  79.                         opt_type = 1;
  80.                         opt_startup = ACE_OS::atoi(get_opt.opt_arg());
  81.                         if (opt_startup <= 0)
  82.                                 print_usage_and_die ();
  83.                         break;
  84.                 case 'd':
  85.                         opt_debug = 1;
  86.                         break;
  87.                 default:
  88.                         // -i can also be given without a value - if so, it defaults
  89.                         // to defined value.
  90.                         if (ACE_OS::strcmp (get_opt.argv ()[get_opt.opt_ind () - 1], ACE_TEXT ("-i")) == 0)
  91.                         {
  92.                                 opt_install = 1;
  93.                                 opt_startup = DEFAULT_SERVICE_INIT_STARTUP;
  94.                         }
  95.                         else
  96.                         {
  97.                                 print_usage_and_die();
  98.                         }
  99.                         break;
  100.         }
  101. }

  102. int Process::run (int argc, ACE_TCHAR* argv[])
  103. {
  104.         App_Service::instance()->name(ACE_TEXT ("freeeyes"), ACE_TEXT ("freeeyes Service"));

  105.         parse_args(argc, argv);

  106.         if (opt_install && !opt_remove)
  107.         {
  108.                 if (-1 == App_Service::instance ()->insert(opt_startup))
  109.                 {
  110.                         ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("insert")));
  111.                         return -1;
  112.                 }
  113.                 return 0;
  114.         }

  115.         if (opt_remove && !opt_install)
  116.         {
  117.                 if (-1 == App_Service::instance ()->remove())
  118.                 {
  119.                         ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("remove")));
  120.                         return -1;
  121.                 }
  122.                 return 0;
  123.         }

  124.         if (opt_start && opt_kill)
  125.                 print_usage_and_die ();

  126.         if (opt_start)
  127.         {
  128.                 if (-1 == App_Service::instance ()->start_svc())
  129.                 {
  130.                         ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("start")));
  131.                         return -1;
  132.                 }
  133.                 return 0;
  134.         }

  135.         if (opt_kill)
  136.         {
  137.                 if (-1 == App_Service::instance()->stop_svc())
  138.                 {
  139.                         ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("stop")));
  140.                         return -1;
  141.                 }
  142.                 return 0;
  143.         }

  144.         if (opt_type)
  145.         {
  146.                 if (-1 == App_Service::instance ()->startup(opt_startup))
  147.                 {
  148.                         ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set startup")));
  149.                         return -1;
  150.                 }
  151.                 return 0;
  152.         }

  153.         //开始启动服务
  154.         ACE_NT_SERVICE_RUN (freeeyes,
  155.                 App_Service::instance (),
  156.                 ret);
  157.         if (ret == 0)
  158.                 ACE_ERROR ((LM_ERROR,
  159.                 ACE_TEXT ("%p\n"),
  160.                 ACE_TEXT ("Couldn't start service")));
  161.         else
  162.                 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Service stopped.\n")));

  163.         return 0;
  164. }
复制代码
最后,在Main函数里面,添加一行语句即可
  1. int ACE_TMAIN (int argc, ACE_TCHAR* argv[])
  2. {
  3.         return PROCESS::instance ()->run(argc, argv);
  4. }
复制代码
这里要说明,并不是这些代码写好了,你就可以直接点运行了,这样你的服务是肯定起不来的。
首先,要注册服务。
你需要打开cmd窗口,切换到你的工程目录下,找到你的exe文件。然后注册一个你的服务。
比如我这个程序, freeeyes.exe -i
注册成功什么都不显示,程序退出,否则显示错误信息。
然后找到"我的电脑" 右键"服务",打开windows服务窗口,查找你添加的服务名称。
然后点击运行
这样,你的服务就启动了。
如果你想删除服务,也简单,同样到cmd下, freeeyes.exe -r 即可。
这里得说一下ACE windows服务下的一些容易出错的地方。
你或许会觉得这段代码永远不会被执行
  1. //开始启动服务
  2.         ACE_NT_SERVICE_RUN (freeeyes,
  3.                 App_Service::instance (),
  4.                 ret);
  5.         if (ret == 0)
  6.                 ACE_ERROR ((LM_ERROR,
  7.                 ACE_TEXT ("%p\n"),
  8.                 ACE_TEXT ("Couldn't start service")));
  9.         else
  10.                 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Service stopped.\n")));
复制代码
实际上,这段代码非常重要,在你的服务注册以后,当启动的时候,windows服务管理器会直接运行freeeyes.exe,这个程序,这时候,代码会自己走到这个里面调用 ACE_NT_SERVICE_RUN这个宏,实际上,只有当 freeeyes这个服务正确注册的时候,才会被启动,否则会返回1053错误。这里一定要注意。还有,要运行这个测试用例,一定要把 ACEd.dll拷贝到当前目录下啊。否则服务会因为找不到dll而启动不起来。
好啦,废话少说,把我的这个样例代码贴在下面吧。
此代码windows7 ACE6.1.0下测试通过。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值