如何用ACE来实现一个windows Service
2014-11-04 09:10
337 查看
好久没来写技术文章,归结原因依旧是很忙。
有时间就多写一些吧。
最近有朋友在我的开源服务器上做了一个windows服务版本,挺有趣,于是我想把这个功能和我的服务器做一个整合,一开始并不顺利,原因是自己对windows服务的流程不熟悉。走了一些弯路,在这里记录下来,供大家参考。
其实windows下的服务和Linux下的服务大相径庭,linux下的步骤大概在7步,实际上一个function即可完成,windows下的服务必须先注册,再运行,当然,如果你想删除服务,还的有一个删除的步骤。
这篇文章先讨论windows下的服务开启和启动。
首先,先要了解一个类,ACE_NT_Service
这个类是一个标准的windows服务类,我们要创建一个自己的服务,就必须先继承它,
这里有几个函数,我需要再这里说明一下。
class CProgramService : public ACE_NT_Service
{
public:
CProgramService(void);
~CProgramService(void);
virtual int svc(void);
virtual int handle_exception (ACE_HANDLE h);
virtual void handle_control (DWORD control_code);
private:
typedef ACE_NT_Service inherited;
private:
bool m_blsStop;
};class CProgramService : public ACE_NT_Service
{
public:
CProgramService(void);
~CProgramService(void);
virtual int svc(void);
virtual int handle_exception (ACE_HANDLE h);
virtual void handle_control (DWORD control_code);
private:
typedef ACE_NT_Service inherited;
private:
bool m_blsStop;
};
复制代码
svc() 这个函数是用来处理服务运行的,你可以在这里添加你的任意代码,比如一个死循环,或者一个你需要执行的函数。
handle_control ()函数是当windows service管理控制器被操作的时候,比如点击运行,暂停,停止,重新运行等,会对应这些消息被投递到这里。control_code就是这些消息类型。你可以case一下,用作你的处理。
handle_exception ()是当异常发生的时候,通知windows service你的进程当前的状态,从而统一service管理器对你的服务状态的完整监控。
好了,知道以上几个接口,基本能够完成windows service的所有控制了。
那么下面,我们来看怎么控制。
ACE_NT_SERVICE_DEFINE (freeeyes, CProgramService, ACE_TEXT("freeeyes Service"));
复制代码
这行代码是必要的,这个宏的意思是说,把Service对应的接口绑定给CProgramService类,也就是你的ACE_NT_Service。
为了方便测试服务的启动和注册,借用一下ACE例子里面的一个类。
class Process
{
public:
Process (void);
~Process (void);
int run(int argc, ACE_TCHAR* argv[]);
private:
void parse_args (int argc,
ACE_TCHAR* argv[]);
void print_usage_and_die (void);
private:
char progname[128];
int opt_install;
int opt_remove;
int opt_start;
int opt_kill;
int opt_type;
int opt_debug;
int opt_startup;
};
typedef ACE_Singleton<Process, ACE_Mutex> PROCESS;
Process::Process (void)
: opt_install (0),
opt_remove (0),
opt_start (0),
opt_kill (0),
opt_type (0),
opt_debug (0),
opt_startup (0)
{
ACE_OS::strcpy (progname,
"service");
ACE::init ();
}
Process::~Process (void)
{
ACE::fini ();
}
void
Process::print_usage_and_die (void)
{
ACE_DEBUG ((LM_INFO,
"Usage: %s"
" -in -r -s -k -tn -d\n"
" -i: Install this program as an NT service, with specified startup\n"
" -r: Remove this program from the Service Manager\n"
" -s: Start the service\n"
" -k: Kill the service\n"
" -t: Set startup for an existing service\n"
" -d: Debug; run as a regular application\n",
progname,
0));
ACE_OS::exit(1);
}
void
Process::parse_args (int argc, ACE_TCHAR* argv[])
{
ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:rskt:d"));
int c;
while ((c = get_opt ()) != -1)
switch (c)
{
case 'i':
opt_install = 1;
opt_startup = ACE_OS::atoi (get_opt.opt_arg());
if (opt_startup <= 0)
print_usage_and_die ();
break;
case 'r':
opt_remove = 1;
break;
case 's':
opt_start = 1;
break;
case 'k':
opt_kill = 1;
break;
case 't':
opt_type = 1;
opt_startup = ACE_OS::atoi(get_opt.opt_arg());
if (opt_startup <= 0)
print_usage_and_die ();
break;
case 'd':
opt_debug = 1;
break;
default:
// -i can also be given without a value - if so, it defaults
// to defined value.
if (ACE_OS::strcmp (get_opt.argv ()[get_opt.opt_ind () - 1], ACE_TEXT ("-i")) == 0)
{
opt_install = 1;
opt_startup = DEFAULT_SERVICE_INIT_STARTUP;
}
else
{
print_usage_and_die();
}
break;
}
}
int Process::run (int argc, ACE_TCHAR* argv[])
{
App_Service::instance()->name(ACE_TEXT ("freeeyes"), ACE_TEXT ("freeeyes Service"));
parse_args(argc, argv);
if (opt_install && !opt_remove)
{
if (-1 == App_Service::instance ()->insert(opt_startup))
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("insert")));
return -1;
}
return 0;
}
if (opt_remove && !opt_install)
{
if (-1 == App_Service::instance ()->remove())
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("remove")));
return -1;
}
return 0;
}
if (opt_start && opt_kill)
print_usage_and_die ();
if (opt_start)
{
if (-1 == App_Service::instance ()->start_svc())
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("start")));
return -1;
}
return 0;
}
if (opt_kill)
{
if (-1 == App_Service::instance()->stop_svc())
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("stop")));
return -1;
}
return 0;
}
if (opt_type)
{
if (-1 == App_Service::instance ()->startup(opt_startup))
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set startup")));
return -1;
}
return 0;
}
//开始启动服务
ACE_NT_SERVICE_RUN (freeeyes,
App_Service::instance (),
ret);
if (ret == 0)
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("Couldn't start service")));
else
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Service stopped.\n")));
return 0;
}
复制代码
最后,在Main函数里面,添加一行语句即可
int ACE_TMAIN (int argc, ACE_TCHAR* argv[])
{
return PROCESS::instance ()->run(argc, argv);
}
复制代码
这里要说明,并不是这些代码写好了,你就可以直接点运行了,这样你的服务是肯定起不来的。
首先,要注册服务。
你需要打开cmd窗口,切换到你的工程目录下,找到你的exe文件。然后注册一个你的服务。
比如我这个程序, freeeyes.exe -i
注册成功什么都不显示,程序退出,否则显示错误信息。
然后找到"我的电脑" 右键"服务",打开windows服务窗口,查找你添加的服务名称。
然后点击运行
这样,你的服务就启动了。
如果你想删除服务,也简单,同样到cmd下, freeeyes.exe -r 即可。
这里得说一下ACE windows服务下的一些容易出错的地方。
你或许会觉得这段代码永远不会被执行
//开始启动服务
ACE_NT_SERVICE_RUN (freeeyes,
App_Service::instance (),
ret);
if (ret == 0)
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("Couldn't start service")));
else
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下测试通过。
有时间就多写一些吧。
最近有朋友在我的开源服务器上做了一个windows服务版本,挺有趣,于是我想把这个功能和我的服务器做一个整合,一开始并不顺利,原因是自己对windows服务的流程不熟悉。走了一些弯路,在这里记录下来,供大家参考。
其实windows下的服务和Linux下的服务大相径庭,linux下的步骤大概在7步,实际上一个function即可完成,windows下的服务必须先注册,再运行,当然,如果你想删除服务,还的有一个删除的步骤。
这篇文章先讨论windows下的服务开启和启动。
首先,先要了解一个类,ACE_NT_Service
这个类是一个标准的windows服务类,我们要创建一个自己的服务,就必须先继承它,
这里有几个函数,我需要再这里说明一下。
class CProgramService : public ACE_NT_Service
{
public:
CProgramService(void);
~CProgramService(void);
virtual int svc(void);
virtual int handle_exception (ACE_HANDLE h);
virtual void handle_control (DWORD control_code);
private:
typedef ACE_NT_Service inherited;
private:
bool m_blsStop;
};class CProgramService : public ACE_NT_Service
{
public:
CProgramService(void);
~CProgramService(void);
virtual int svc(void);
virtual int handle_exception (ACE_HANDLE h);
virtual void handle_control (DWORD control_code);
private:
typedef ACE_NT_Service inherited;
private:
bool m_blsStop;
};
复制代码
svc() 这个函数是用来处理服务运行的,你可以在这里添加你的任意代码,比如一个死循环,或者一个你需要执行的函数。
handle_control ()函数是当windows service管理控制器被操作的时候,比如点击运行,暂停,停止,重新运行等,会对应这些消息被投递到这里。control_code就是这些消息类型。你可以case一下,用作你的处理。
handle_exception ()是当异常发生的时候,通知windows service你的进程当前的状态,从而统一service管理器对你的服务状态的完整监控。
好了,知道以上几个接口,基本能够完成windows service的所有控制了。
那么下面,我们来看怎么控制。
ACE_NT_SERVICE_DEFINE (freeeyes, CProgramService, ACE_TEXT("freeeyes Service"));
复制代码
这行代码是必要的,这个宏的意思是说,把Service对应的接口绑定给CProgramService类,也就是你的ACE_NT_Service。
为了方便测试服务的启动和注册,借用一下ACE例子里面的一个类。
class Process
{
public:
Process (void);
~Process (void);
int run(int argc, ACE_TCHAR* argv[]);
private:
void parse_args (int argc,
ACE_TCHAR* argv[]);
void print_usage_and_die (void);
private:
char progname[128];
int opt_install;
int opt_remove;
int opt_start;
int opt_kill;
int opt_type;
int opt_debug;
int opt_startup;
};
typedef ACE_Singleton<Process, ACE_Mutex> PROCESS;
Process::Process (void)
: opt_install (0),
opt_remove (0),
opt_start (0),
opt_kill (0),
opt_type (0),
opt_debug (0),
opt_startup (0)
{
ACE_OS::strcpy (progname,
"service");
ACE::init ();
}
Process::~Process (void)
{
ACE::fini ();
}
void
Process::print_usage_and_die (void)
{
ACE_DEBUG ((LM_INFO,
"Usage: %s"
" -in -r -s -k -tn -d\n"
" -i: Install this program as an NT service, with specified startup\n"
" -r: Remove this program from the Service Manager\n"
" -s: Start the service\n"
" -k: Kill the service\n"
" -t: Set startup for an existing service\n"
" -d: Debug; run as a regular application\n",
progname,
0));
ACE_OS::exit(1);
}
void
Process::parse_args (int argc, ACE_TCHAR* argv[])
{
ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:rskt:d"));
int c;
while ((c = get_opt ()) != -1)
switch (c)
{
case 'i':
opt_install = 1;
opt_startup = ACE_OS::atoi (get_opt.opt_arg());
if (opt_startup <= 0)
print_usage_and_die ();
break;
case 'r':
opt_remove = 1;
break;
case 's':
opt_start = 1;
break;
case 'k':
opt_kill = 1;
break;
case 't':
opt_type = 1;
opt_startup = ACE_OS::atoi(get_opt.opt_arg());
if (opt_startup <= 0)
print_usage_and_die ();
break;
case 'd':
opt_debug = 1;
break;
default:
// -i can also be given without a value - if so, it defaults
// to defined value.
if (ACE_OS::strcmp (get_opt.argv ()[get_opt.opt_ind () - 1], ACE_TEXT ("-i")) == 0)
{
opt_install = 1;
opt_startup = DEFAULT_SERVICE_INIT_STARTUP;
}
else
{
print_usage_and_die();
}
break;
}
}
int Process::run (int argc, ACE_TCHAR* argv[])
{
App_Service::instance()->name(ACE_TEXT ("freeeyes"), ACE_TEXT ("freeeyes Service"));
parse_args(argc, argv);
if (opt_install && !opt_remove)
{
if (-1 == App_Service::instance ()->insert(opt_startup))
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("insert")));
return -1;
}
return 0;
}
if (opt_remove && !opt_install)
{
if (-1 == App_Service::instance ()->remove())
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("remove")));
return -1;
}
return 0;
}
if (opt_start && opt_kill)
print_usage_and_die ();
if (opt_start)
{
if (-1 == App_Service::instance ()->start_svc())
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("start")));
return -1;
}
return 0;
}
if (opt_kill)
{
if (-1 == App_Service::instance()->stop_svc())
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("stop")));
return -1;
}
return 0;
}
if (opt_type)
{
if (-1 == App_Service::instance ()->startup(opt_startup))
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set startup")));
return -1;
}
return 0;
}
//开始启动服务
ACE_NT_SERVICE_RUN (freeeyes,
App_Service::instance (),
ret);
if (ret == 0)
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("Couldn't start service")));
else
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Service stopped.\n")));
return 0;
}
复制代码
最后,在Main函数里面,添加一行语句即可
int ACE_TMAIN (int argc, ACE_TCHAR* argv[])
{
return PROCESS::instance ()->run(argc, argv);
}
复制代码
这里要说明,并不是这些代码写好了,你就可以直接点运行了,这样你的服务是肯定起不来的。
首先,要注册服务。
你需要打开cmd窗口,切换到你的工程目录下,找到你的exe文件。然后注册一个你的服务。
比如我这个程序, freeeyes.exe -i
注册成功什么都不显示,程序退出,否则显示错误信息。
然后找到"我的电脑" 右键"服务",打开windows服务窗口,查找你添加的服务名称。
然后点击运行
这样,你的服务就启动了。
如果你想删除服务,也简单,同样到cmd下, freeeyes.exe -r 即可。
这里得说一下ACE windows服务下的一些容易出错的地方。
你或许会觉得这段代码永远不会被执行
//开始启动服务
ACE_NT_SERVICE_RUN (freeeyes,
App_Service::instance (),
ret);
if (ret == 0)
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("Couldn't start service")));
else
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下测试通过。
相关文章推荐
- 如何完成一个实现Pause和Continue这两个功能的Windows Service
- 项目中一个普通的Java类如何获取serviceimpl实现类(二)
- 如何实现一个优质的微服务框架:Apache ServiceComb 的开放性设计
- [11] Windows PowerShell DSC学习系列---如何定制一个基于PowerShell脚本实现的DSC Resource
- 用mfc如何实现将一个文件拷贝到另一个文件夹中例如:C:\WINDOWS\a.txt中的a.txt文件拷贝到D:\Program
- 重温WCF之构建一个简单的WCF(一)(2)通过Windows Service寄宿服务和WCF中实现操作重载
- 在windows中,如何实现一个自己的浏览器
- 如何实现一个只有广播和service的android应用没有activity
- Windows 编程中用Service开启一个外部进程的两种语言实现方式(C++,C#)。
- 如何实现一个与数据库表字段松耦合的j2ee应用
- 如何遍历一个窗体中的某一种控件 c#实现
- 如何遍历一个窗体中的某一种控件 c#实现
- 如何在 Windows XP Service Pack 2 上启用 SQL Server 连接
- 在Java applet中如何实现一个模式对话框?
- 分别用(Windows/Form/Soap/WebService)实现用户身份验证(含示例代码下载)
- 如何制作自己的Windows Service Pack
- 如何实现一个frame中的按钮事件调用另一个frame的服务器控件
- 如何实现一个简单的remoteing实例
- 如何在VB 6.0 sp6 中使用WindowsMediaPlayer控件?编写一个属于自己的多媒体播放器?
- 如何在ASP.net中实现限制一个用户名在多个客户端IE登陆的方法