网上有很多关于编写ATL服务程序的代码和文章,但多数仍使用Visual C++ 6.0的ATL服务程序框架。对于XP系统,Visual C++ 6.0提供的框架能够正常工作,但对于Vista、Windows7 系统来说,VC++6.0提供的框架显然不够安全,也无法保证在Vista、Windows7系统上能正常运行。而在Windows Vista 之后,系统引入了Session0 隔离机制,导致在XP下能够正常运行的服务程序,无法正常运行在Vista和Windows 7系统上。因此,我完整的整理了一下关于ATL服务程序编写方面的内容。
主要内容如下:
1、ATL服务程序的编写
2、服务层与应用层内核对象的访问
3、创建用户桌面进程(突破Session0隔离机制)
今天,先进行第一项内容,ATL服务程序的建立。
首先,打开VS2010,建立ATL项目,命名为ATLDemo。
在项目类型中选择“服务(EXE)”,单击“完成”。
在工程左侧的项目文件列表中,找到“ATLDemo.cpp”,双击打开。
修改默认的接口函数如下:
#include "stdafx.h" #include "resource.h" #include "ATLDemo_i.h" #include <atlcomcli.h> /*注意,要包含此头文件*/ class CATLDemoModule : public ATL::CAtlServiceModuleT< CATLDemoModule, IDS_SERVICENAME > { public : DECLARE_LIBID(LIBID_ATLDemoLib) DECLARE_REGISTRY_APPID_RESOURCEID(IDR_ATLDEMO, "{9ED05BD2-AA2F-48F5-8FE2-2E41C54F469E}") HRESULT InitializeSecurity() throw() { // TODO : 调用 CoInitializeSecurity 并为服务提供适当的安全设置 // 建议 - PKT 级别的身份验证、 // RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别 // 以及适当的非 null 安全说明符。 //return S_OK; return CoInitializeSecurity(NULL,-1,NULL,NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL,EOAC_NONE,NULL);//创建安全说明符 } //这里要对一些函数进行重写 void OnPause() throw(); //暂停 void OnStop() throw();//停止 void Handler(DWORD dwOpcode) throw();//处理不同的服务控制消息 void OnContinue() throw();//继续运行 HRESULT PreMessageLoop(int nShowCmd) throw();//消息响应 HRESULT RegisterAppId(bool bService = false) throw();//服务注册 };
下面依次实现每个重写的函数,首先是RegisterAppId()函数。
HRESULT CATLDemoModule::RegisterAppId( bool bService /*= false*/ ) throw() { HRESULT hr = S_OK; BOOL res = __super::RegisterAppId(bService); if (bService) { if (IsInstalled())//服务已经安装 { SC_HANDLE hSCM = ::OpenSCManager(NULL,NULL,SERVICE_CHANGE_CONFIG);//打开服务管理器 SC_HANDLE hService = NULL; if (hSCM == NULL) { hr = ATL::AtlHresultFromLastError(); } else { //打开服务,m_szServiceName为基类成员变量,代表当前服务名称 //可以在资源文件列表的String Table中修改 hService = OpenService(hSCM,m_szServiceName,SERVICE_CHANGE_CONFIG); if (hService != NULL) { //修改服务配置 ChangeServiceConfig(hService, SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,//独立进程、允许交互 SERVICE_AUTO_START,//服务自动启动 NULL,NULL,NULL,NULL,NULL,NULL,NULL, m_szServiceName); //服务描述信息 SERVICE_DESCRIPTION sDescription; TCHAR szDescription[1024]; ZeroMemory(szDescription,1024); ZeroMemory(&sDescription,sizeof(SERVICE_DESCRIPTION)); //服务描述 lstrcpy(szDescription,L"ATLDemo服务测试!"); sDescription.lpDescription = szDescription; //修改服务描述信息 ChangeServiceConfig2(hService,SERVICE_CONFIG_DESCRIPTION,&sDescription); //关闭服务句柄 CloseServiceHandle(hService); } else { hr = ATL::AtlHresultFromLastError(); } } //关闭服务管理器句柄 ::CloseServiceHandle(hSCM); } } return hr; }
然后是PreMessageLoop()函数:
HRESULT CATLDemoModule::PreMessageLoop( int nShowCmd ) throw() { //让服务允许暂停和继续操作 m_status.dwControlsAccepted = m_status.dwControlsAccepted|SERVICE_ACCEPT_PAUSE_CONTINUE; HRESULT hr = __super::PreMessageLoop(nShowCmd); if (hr == S_FALSE) { hr = S_OK;//这里有Bug,必须这样写,后面才能继续 } //将服务状态设置为启动 SetServiceStatus(SERVICE_RUNNING); //写入系统日志 LogEvent(L"ATLDemo Service Start Successfully~!"); return hr; }
void CATLDemoModule::Handler( DWORD dwOpcode ) throw() { switch(dwOpcode) { case SERVICE_CONTROL_PAUSE://暂停 { OnPause(); break; } case SERVICE_CONTROL_CONTINUE://继续 { OnContinue(); break; } default: break; } __super::Handler(dwOpcode); }
void CATLDemoModule::OnPause() throw() { //设置服务状态为暂停 SetServiceStatus(SERVICE_PAUSED); __super::OnPause(); }
void CATLDemoModule::OnStop() throw() { //设置服务状态为停止 SetServiceStatus(SERVICE_STOPPED); __super::OnStop(); }
void CATLDemoModule::OnContinue() throw() { //设置服务状态为启动 SetServiceStatus(SERVICE_RUNNING); __super::OnContinue(); }
安装服务:
ATLDemo.exe /Service
net start ATLDemo
打开系统服务管理器,就可以看到刚才注册的服务程序了:
卸载服务
net stop ATLDemo
ATLDemo.exe /UnRegServer
至此,ATL服务程序的编写已经完成。
下一篇,将说明服务层与应用层的内核对象访问的问题。
本帖为原创,转帖请说明出处,谢谢合作。
本帖地址:http://blog.csdn.net/sonsie007/article/details/8834269