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

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


VS2010 ATL服务程序编写全攻略(一) - 建立ATL服务_第1张图片


项目类型中选择“服务(EXE)”,单击“完成”。



工程左侧的项目文件列表中,找到“ATLDemo.cpp”,双击打开。


VS2010 ATL服务程序编写全攻略(一) - 建立ATL服务_第2张图片


修改默认的接口函数如下:

#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, 在如图位置修改:

VS2010 ATL服务程序编写全攻略(一) - 建立ATL服务_第3张图片



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

VS2010 ATL服务程序编写全攻略(一) - 建立ATL服务_第4张图片


打开系统服务管理器,就可以看到刚才注册的服务程序了:





卸载服务

net stop ATLDemo

ATLDemo.exe /UnRegServer



至此,ATL服务程序的编写已经完成。


下一篇,将说明服务层与应用层的内核对象访问的问题。


本帖为原创,转帖请说明出处,谢谢合作。

本帖地址:http://blog.csdn.net/sonsie007/article/details/8834269



你可能感兴趣的:(系统服务,Visual,Studio,2010,atl)