三、开发Windows服务程序
前言
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。通过活动模板库,可以建立COM组件,然后通过ASP页面中的脚本对COM对象进行调用。这种COM组件可以包含属性页、对话框等控件。
ATL中所使用的基本技术包括以下几个方面:
- COM技术
- C++模板类技术(Template)
- C++多继承技术(Multi-Inheritance)
3.1 创建ALT服务应用程序
文件-》新建-》项目->选择ALT项目->exe服务程序
MyService:用于生成ALT服务对应的可执行文件。
MyServicePS:动态库DLL类型,是·1服务程序与客户端进行通信的代理,御用负责服务程序与客户端的通信。
注意:
当你开发的组件需要用到代理/存根(即IPC(LPC+RPC)),就需要MyServicePS,否则MyServicePS无用
MyService.cpp是MyService项目的主文件。其中,CMyServiceModule是实现服务的类,也是从CAltServiceModuleT派生的,IDS_SERVICENAME是服务的资源表示符。_ALTModule是CMyServiceModule的对象,也是运行的服务实例。_tWinMain()是服务程序的入口函数,它是AtlModule.WinModule.WinMain()函数来初始化和加载服务。
可以运行一下。
注意:服务程序都是需要管理权限,所以exe需要配置默认以管理员运行。
右键属性-》配置属性-》链接器-》清单文件-》UAC执行级别
设置为 requireAdministrator (/level=‘requireAdministrator’)
3.2 安装和卸载ALT服务
安装
生成09.3.1MyService.exe,使用命令行安装:
09.3.1MyService.exe /Service
从任务管理服务查看已安装的服务
卸载
卸载服务命令
09.3.1MyService.exe /unRegService
我竟然没卸载成功
用sc命令卸载的
sc Delete 09.3.1MyService
3.3 设置服务的属性
设置服务的名称
打开09.3.1MyService.rc
IDS_SERVICENAME
:此处为服务名,修改即可修改服务名。
设置服务描述和启动方式
inline HRESULT RegisterAppId(_In_ bool bService = false) throw()
CAtlServiceModuleT::RegisterAppId()函数用于在注册表中注册服务,在CMyServiceModule类中重载RegisterAppId函数,可以在注册服务时设置服务的描述和启动方式。
以下代码实现修改服务描述和启动方式:
HRESULT CMyServiceModule::RegisterAppId(bool bService = false) throw() { HRESULT hr = S_OK; BOOL res = __super::RegisterAppId(bService); // 调用父类的RegisterAppId()函数 if (bService) { if(IsInstalled()) // 如果服务安装成功 { // 以修改配置的权限打开服务控制器 SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL,SERVICE_CHANGE_CONFIG); SC_HANDLE hService = NULL; if (hSCM == NULL) hr = AtlHresultFromLastError(); else { // 以修改配置的权限打开安装的服务 hService = ::OpenService(hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG); if (hService != NULL) { ::ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START,// 修改服务为自动启动 NULL, NULL, NULL, NULL, NULL, NULL, NULL, m_szServiceName); // 通过修改资源IDS_SERVICENAME 修改服务的显示名字 // 设置服务描述信息 SERVICE_DESCRIPTION Description; TCHAR szDescription[1024]; ZeroMemory(szDescription, 1024); ZeroMemory(&Description, sizeof(SERVICE_DESCRIPTION)); lstrcpy(szDescription, _T("我的第1个服务")); Description.lpDescription = szDescription; ::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description); ::CloseServiceHandle(hService); } else hr = AtlHresultFromLastError(); ::CloseServiceHandle(hSCM); } } } return hr; }
如果服务安装成功,则程序调用ChangeServiceConfig函数和ChangeServiceConfig2函数设置服务的启动方式和描述。
四、增加和使用组件
如何在ATL服务中增加组件类以及在客户端程序中使用组件类的方法。
4.1 增加组件
右键项目 添加->新建项->Vistual C++ ATL ->ATL 简单对象
MyMath
注意:
- 添加组件类时会同时添加一个*.regs文件,作用是注册组件类,以使在客户端程序中可以调用组件类。
- *.regs文件中添加AppID时,以指定服务程序的ID,如果不添加,则客户端创建组件时会超时报错并报错误。
MyMath.regs
HKCR { //需要添加的AppID代码部分 NoRemove AppID { '%APPID%' = s 'MyService' 'MyService.EXE' { val AppID = s '%APPID%' } } NoRemove CLSID { ForceRemove {0973bc39-d603-48ec-b784-41d7ca69c58f} = s 'MyMath class' { ForceRemove Programmable LocalServer32 = s '%MODULE%' { val ServerExecutable = s '%MODULE_RAW%' } TypeLib = s '{15f0d8bf-d610-45b6-b643-7ab15f7b31b3}' Version = s '1.0' } } }
组件类中添加函数
打开vs 类视图,可以找到IMyMath
选中MyMath右键-》添加方法,然后按如图设置参数和返回参数
查看
MyMath.cpp 添加Sum实现:
STDMETHODIMP CMyMath::Sum(LONG a, LONG b, LONG* s) { // TODO: 在此处添加实现代码 *s = a + b; return S_OK; }
MyService.idl中添加
注意:最后要生成一个tbl文件,用于客户端访问。