找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4227|回复: 0

如何用ACE来实现一个windows Service

[复制链接]
发表于 2013-6-14 11:53:21 | 显示全部楼层 |阅读模式
好久没来写技术文章,归结原因依旧是很忙。
有时间就多写一些吧。
最近有朋友在我的开源服务器上做了一个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下测试通过。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?用户注册

×
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-5-7 04:26 , Processed in 0.027753 second(s), 9 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表