[MFC]动态模板库ATL的概述

概述

一  概要

ATL(Active Template Library)动态模板库,它是一套C++模板库。使用ATL能够快速的开发出高效简洁的代码,同时对COM组件的开发提供了最大限度的代码自动生成以及可视化支持。封装了COM组件的各种细节和COM SDK,可以方便用户进行组件开发。

COM的实现在ATL产生以前,是使用COM SDK直接开发COM组件。ATL的基本目标就是使COM应用开发尽可能自动化。ATL的各个版本对Microsoft的基于COM的各种新的组件技术如MTS、ASP等都有很好的支持,ATL对新技术的反应速度大大快于MFC。

常用的ATL类:

  • CComObjectRootBase:定义了一个引用计数和内部函数。其子类有CComObjectRootEx(实现了两个函数InternalAddRef(),InternalRelease)
  • CComSingleThreadModel:对引用计数做”++”,”--”操作
  • CComMultiThreadModel:对引用计数做原子锁的加减操作
  • CComObject:实现了IUnknown接口的三个函数(计数加减,函数查询),完成了组件的定义;AddRef-InternalAddRef;Release-InternalRelease;QueryInterface-_InternalQueryInterface 

组件的实现:

  • 1.添加CComObjectRootEx父类
  • 2.stdafx.h中添加:#include;Extern CComModule _Module;;#include
  • 3.添加接口映射:  BEGIN_COM_MAP(CImpMath) -----  COM_INTERFACE_ENTRY(IMath) ----  END_COM_MAP()
  • 4.添加接口函数的实现

组件的创建:CComObjectRootBase-->-CComObjectRootEx->CImpMath-->CComObject;

二  类厂-----组件的创建

类厂:用于创建组件的组件,类厂也是一个组件,作用创建其它组件;类厂的接口IClassFactory;ATLCComCoClass

类厂的实现:

  • 2.1 组件类添加父类CComCoClass
  • 2.2 在组件类中添加宏:DECLARE_REGISTRY_RESOURCE
  • 2.3 将组件ID和组件建立映射关系:BEGIN_OBJECT_MAP(objectmap)------OBJECT_ENTRY(CLSID_Math,CImpMath)-------END_OBJECT_MAP() 
  • 2.4 将映射关系保存到_Module:_Module.Init(objectmap,(HINSTANCE)hModule);

类厂创建:使用_Module.GetClassObject获取指定组件的类厂;使用类厂创建组件对象,并返回接口

三 组件的使用

微软提供CoCreateInstance创建组件并返回接口
STDAPI CoCreateInstance(
REFCLSID rclsid, //组件ID
LPUNKNOWN pUnkOuter, //聚合接口,不使用时,NULL
DWORD dwClsContext, //组件的运行方式
REFIID riid, //接口的ID
LPVOID *ppv //接口的地址
);

3.1. 使用ATL向导生成的工程中包含的四个函数

  •    3.1.1 DllCanUnloadNow:询问组件所在的DLL是否可以卸载
  •    3.1.2 DllGetClassObject:根据组件ID获取指定组件类厂
  •    3.1.3 DllRegisterServer:注册组件,将组件的信息写入注册表
  •    3.1.4 DllUnregisterServer:卸载组件,将组件的信息从注册表删除

 3.2 组件注册

  •      3.2.1 注册表信息:*.rgs,设置注册信息
  •      3.2.2 CLSID -组件ID;ProgID-方便记忆组件CLSID,使用字符串表示一个组件;CLSID->ProgID;IP地址->域名;InprocServer32-保存组件所在的dll文件路径
  •      3.2.3 组件注册:regedit-打开注册表;regsvr32 *.dll 注册组件;regsvr32 /u *.dll 卸载组件;组件只有在注册后,才能使用

  3.3 组件的使用

  •       3.3.1 CoInitialize:初始化COM库。必须在使用组件之间调用
  •       3.3.2 CoCreateInstance:创建对象,并返回接口
  •       3.3.3 CoUninitialize:卸载COM库,常在程序结束时调用

  3.4 组件的创建

  •       3.4.1 CoCreateInstance首先使用CLSID,在注册表中查找组件
  •       3.4.2 找到对应的项后,获取组件所在的Dll文件的路径
  •       3.4.3 加载dll
  •       3.4.4 获取DllGetClassObject函数,并创建组件所对应的类厂
  •       3.4.5 使用类厂创建组件并获取接口

  3.5 COM的智能指针类: 用于自动维护接口指针,包括创建和释放;CComPtr -完成基本接口指针的维护;CComQIPtr-类似于CComPtr,可以自动完成查询功能 

实例

一 创建ATL项目COMMath

1.新建ATL项目COMMath:下一步-->应用程序类型:动态链接库DLL;支持选项:支持COM+1.0,支持部件注册器-->完成。

2.添加MathAdd类:右击--添加--类-->选择ATL简单对象-->简称:MathAdd;别的默认;COM  ProgID:COMMath.MathAdd-->下一步,下一步,完成。

3.添加接口方法Add():在类视图中,右击IMathAdd接口,选择 添加---方法 -->方法名:Add,参数特性 HRESULT Add([in] int nAdd1, [in] int nAdd2, [out,retval] int* nResult);

4.添加Add()方法的实现:在MathAdd.cpp中添加:

STDMETHODIMP CMathAdd::Add(int nAdd1, int nAdd2, int* nResult)
{ 
	*nResult=nAdd1+nAdd2;
	return S_OK;
}

二创建使用ATL项目COMMath的MFC dialog的UseCOMMath项目
1.在用一个解决方案中创建MFC dialog UseCOMMath项目

2.在UseCOMMath.cpp中:

BOOL CUseCOMMathApp::InitInstance()
{
	CoInitialize(0); // 现在初始化COM
    ...

	return FALSE;
}
int CUseCOMMathApp::ExitInstance()
{
	CoUninitialize();// 卸载COM
	return CWinApp::ExitInstance();
}

3.按钮代码

#include "../COMMath/COMMath_i.h"
#include "../COMMath/COMMath_i.c"
void CUseCOMMathDlg::OnBnClickedButton1()
{  	
	IUnknown* piUnknown=NULL;
	CoCreateInstance(CLSID_MathAdd,NULL,CLSCTX_SERVER,IID_IUnknown,(LPVOID*)&piUnknown);//创建组件,并返回IUnknown接口
	IMathAdd* piMath=NULL;
	piUnknown->QueryInterface(IID_IMathAdd,(LPVOID*)&piMath);//查询IMathAdd接口
	piUnknown->Release();//释放IUnknown接口
	int nResult=0;
	piMath->Add(10,10,&nResult);//使用IMathAdd接口
	piMath->Release();//释放IMathAdd接口
	CString strResult;
	strResult.Format(L"nResult:%d",nResult);
	MessageBox(strResult);	//输出结果	
}
void CUseCOMMathDlg::OnBnClickedButton2()
{ 
	IMathAdd* piMath=NULL;
	CoCreateInstance(CLSID_MathAdd,NULL,CLSCTX_SERVER,IID_IMathAdd,(LPVOID*)&piMath);//创建组件,返回IMathAdd接口
	int nResult=0;
	piMath->Add(20,-30,&nResult);//使用IMathAdd接口
	piMath->Release();//释放IMathAdd接口
	CString strResult;
	strResult.Format(L"nResult:%d",nResult);
	MessageBox(strResult);//输出结果
}
void CUseCOMMathDlg::OnBnClickedButtonProgid()
{ 
	CLSID clsid={0};
	CLSIDFromProgID(L"COMMath.MathAdd",&clsid);//根据ProgID来获取clsid
	IMathAdd* piMath=NULL;
	HRESULT hr=CoCreateInstance(clsid,NULL,CLSCTX_SERVER,IID_IMathAdd,(LPVOID*)&piMath);//创建组件,并返回IMathAdd接口
	int nResult=0;
	if (piMath)
	{
		piMath->Add(-50,100,&nResult);//使用IMathAdd接口
		piMath->Release();//释放IMathAdd接口 
		CString strResult;
		strResult.Format(L"nResult:%d",nResult);
		MessageBox(strResult);//输出结果
	}
}
void CUseCOMMathDlg::OnBnClickedButtonCcomptr()
{ 
	CComPtr piUnknown;
	piUnknown.CoCreateInstance(L"COMMath.MathAdd");
	CComPtr piMath;
	piUnknown->QueryInterface(&piMath);

	int nResult=0;
	piMath->Add(50,50,&nResult);//使用IMathAdd接口
	//piMath->Release();//释放IMathAdd接口 
	CString strResult;
	strResult.Format(L"nResult:%d",nResult);
	MessageBox(strResult);
}
void CUseCOMMathDlg::OnBnClickedButtonCcomqiptr()
{ 
	CComQIPtr piMath;
	piMath.CoCreateInstance(L"COMMath.MathAdd");
	int nResult=0;
	piMath->Add(100,100,&nResult);//使用MathAdd接口
	//piMath->Release();//释放IMathAdd接口 
	CString strResult;
	strResult.Format(L"nResult:%d",nResult);
	MessageBox(strResult);//输出结果
}

4.结果:

你可能感兴趣的:(MFC基础)