VS2010 ATL服务程序编写全攻略(一) - 建立ATL服务

来源:互联网 发布:程序员必须掌握的算法 编辑:程序博客网 时间:2024/05/23 20:35

网上有很多关于编写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;}

代码中提到的m_szServiceName, 在如图位置修改:




然后是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



原创粉丝点击