如果test1这一程序只是一个普通的win32程序,那么这样做了之后还是不行,服务程序有它自己的一些结构特点。那么怎么编写这些服务程序? 建立一个服务程序的最简单的方法是用VC中的ATL COM向导。主菜单中选择新建,然后选Projects中的ATL COM AppWizard,输入一个项目名,选择了所在目录后,点OK按钮,在出现的对话框中选择Service(EXE),点Finish即可。然后编译生成test1.exe。 运行test1.exe /regserver可以注册程序为服务,test1.exe /unregserver是取消注册。test1.exe运行时的参数是在: Project->Settings->Debug->Program arguments中设置。
三、怎么在建立的服务程序中加入自己的代码?
我们看一下刚才生成的test1项目的结构。
我们看到test1有一个类CServiceModule和一些Globals的内容。Globals包括一个_tWinMain函数,也就是程序的入口,其中使用了FindOneOf这一与分析命令行有关的函数,还剩下一个全局变量_Module。 _tWinMain函数中,_Module初始化并设置m_bService为TRUE,在一些分析命令行和判断是否为服务的代码之后,使用_Module.Start()进入主要的执行部分。CServiceModule::Start()中,结构体SERVICE_TABLE_ENTRY建立了服务名与相应处理函数的映射。在这里,如果m_bService为TRUE,则调用StartServiceCtrlDispatcher进入一种类似win32程序的消息处理的过程,用SERVICE_TABLE_ENTRY中的处理函数让程序执行下去。如果m_bService不为TRUE,则直接执行Run()函数。 在SERVICE_TABLE_ENTRY中,我们看到服务处理函数为_ServiceMain,继续跟踪下去,发现是ServiceMain函数。在ServiceMain中又调用RegisterServiceCtrlHandler为服务增加了一个_Handler函数。对服务程序来说,我们可以在前面打开的服务列表中对它们进行“启动”,“停止”,“暂停”,“恢复”等操作。这实际上是由_Handler来处理不同的信号。_Handler内部调用Handler,在Handler中,对传入的dwOpcode参数作出处理。比如如果是SERVICE_CONTROL_STOP,也就是我们“停止”服务时,将使用PostThreadMessage对主线程发出一个退出的信号。回到ServiceMain函数,在里面同样是在调用Run()函数。也就是说程序以服务身份和非服务身份运行时,区别在于以服务身份运行时多了一个Handler函数,处理用户对服务程序发出的一些信号。 需要注意的是,这个程序注册为服务时并不是直接写注册表,而是在Install中使用了OpenSCManager,CreateService等函数来完成的任务。显然,这比直接写注册表要好一些,因为有时候我们并不太清楚要怎么去修改注册表项的值来适应不同的服务程序配置,而这些函数有参数可以做到。
说到这里,就涉及到我们自己编写的代码了。 比如现在我们已经建立了一个MFC的程序,想让它成为一个服务程序,那要怎么做呢? 我现在建立一个MFC EXE的项目mfc1,基于对话框。那么把它变为一个服务程序的最简单的方法就是把CServiceModule给拿过来使用。因为我们已经看到CServiceModule类已经把安装服务,卸载服务,运行服务这些操作封装得很好。 打开test1的stdafx.h文件,复制CServiceModule的声明及相关头文件和变量到mfc1的stdafx.h中。 然后是把test1的test1.cpp中对CServiceModule类的实现,复制到mfc1中的mfc1.cpp中。 在stdafx.h中CServiceModule类声明前加上#include <winsvc.h>,它里面是对结构体SERVICE_STATUS_HANDLE的声明。 编译后出现以下类似错误: D:\vc6_test\mfc1\mfc1.cpp(52) : error C2065: ''IDR_Test1'' : undeclared identifier
D:\vc6_test\mfc1\mfc1.cpp(336) : error C2065: ''CoInitializeSecurity'' : undeclared identifier
D:\vc6_test\mfc1\mfc1.cpp(337) : error C2065: ''EOAC_NONE'' : undeclared identifier
D:\vc6_test\mfc1\mfc1.cpp(362) : error C2065: ''IDS_SERVICENAME'' : undeclared identifier
D:\vc6_test\mfc1\mfc1.cpp(362) : error C2065: ''LIBID_TEST1Lib'' : undeclared identifier
我们可以在test1中找到IDR_Test1的声明,放到mfc1中,解决第一条错误。但我们也可以去掉CServiceModule中与COM有关的一些代码。这里我们删除RegisterServer,UnregisterServer两个函数,并让Run函数成为
(编辑:aniston)
|