com流程梳理

Com流程理解(基于接口)

com组件可以说是接口的组合。
ATL中,里面的接口继承IUnKown接口。每个接口的实现对应着一个类。也就是在.idl(仅是说明文件)文件中对应着一个coclass。idl文件中可以包含多个coclass。就是说com组件可以包含多个接口,多个类。
每个coclass(对应着一个类id)可以对应着一个或者多个生成接口(对应着一个接口id),供其他语言平台调用时使用。
通过ATL向导编译后可以生成dll(或者其他)文件和TLB文件,dll文件写入注册表。TLB文件是二进制文件,供其他ide调用生成自身需要的文件和格式。比如c++使用#import引入TLB文件可以生成-i.h和-i.c文件。
com对象生成:创建智能指针或者裸指针(不推荐),调用cocreatinstance函数,该函数会调用cogetclassobject加载com组件,com组件会调用dllgetclassobject生成类工厂,类工厂调用creatinstance生成类实例,返回接口指针。
手工实现com:
定义接口继承IUnKown;
类继承接口,并实现虚函数(QueryInterface/AddRef/Release等);
定义接口和类的GUID。

补充:

静态类:不用生成对象,通过类名可以引用静态方法。
类只可以继承于一个类(。。。。。。。。。错误?)。
类可以继承多个接口(接口是纯虚类)。
智能指针取址,&spiMyCal,会调用Release,p会被置空。
字符串操作使用CComBSTR类。

AddRef()和Release():

  1. 启动组件得到一个接口指针(Interface)后,不要调用AddRef()。因为系统知道你得到了一个指针,所以它已经帮你调用了AddRef()函数。
  2. 通过QueryInterface()得到另一个接口指针后,不要调用AddRef()。原因如上。
  3. 当把接口指针赋值给(保存到)另一个变量中的时候,请调用AddRef()。
  4. 当不需要再使用接口指针的时候,务必执行Release()释放。
  5. 当使用智能指针的时候,可以省略指针的维护工作。

附录:QueryInterface逻辑代码学习

#include <iostream>
using namespace std;
#include <objbase.h>

void trace(const char* msg) 
{ 
	cout << msg << endl;
}
// 接口定义
interface IX : IUnknown
{
	virtual void __stdcall Fx() = 0;
};

interface IY : IUnknown
{
	virtual void __stdcall Fy() = 0;
};

interface IZ : IUnknown
{
	virtual void __stdcall Fz() = 0;
};

// Forward references for GUIDs
extern const IID IID_IX;
extern const IID IID_IY;
extern const IID IID_IZ;

//
// 实现接口 IX,IY(这里表示一个组件)
//
class CA : public IX, public IY
{
	//IUnknown implementation
	virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);            
	virtual ULONG __stdcall AddRef() { return 0;}
	virtual ULONG __stdcall Release() { return 0;}

	// Interface IX implementation
	virtual void __stdcall Fx() { cout << "这里是Fx函数" << endl;}

	// Interface IY implementation
	virtual void __stdcall Fy() { cout << "这里是Fy函数" << endl;}
};

HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{     
	if (iid == IID_IUnknown)
	{
		trace("QueryInterface: Return pointer to IUnknown.");
		*ppv = static_cast<IX*>(this);
	}
	else if (iid == IID_IX)
	{
		trace("QueryInterface: Return pointer to IX.");
		*ppv = static_cast<IX*>(this);
	}
	else if (iid == IID_IY)
	{
		trace("QueryInterface: Return pointer to IY.");
		*ppv = static_cast<IY*>(this);
	}
	else
	{         
		trace("QueryInterface: Interface not supported.");
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef(); // 加计数
	return S_OK;
}

//
// 创建类CA,并返回一个指向IUnknown的指针
//
IUnknown* CreateInstance()
{
	IUnknown* pI = static_cast<IX*>(new CA);
	pI->AddRef();
	return pI ;
}

//
// 下面是各接口的IID
//
// {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IX = 
{0x32bb8320, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

// {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IY = 
{0x32bb8321, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

// {32bb8322-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IZ = 
{0x32bb8322, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

//
// 主函数(这里代表客户)
//
int main()
{
	HRESULT hr;

	trace("Client:获取 IUnknown指针.");
	IUnknown* pIUnknown = CreateInstance();

	trace("Client:获取接口IX.");

	IX* pIX = NULL; 
	hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
	if (SUCCEEDED(hr))
	{
		trace("Client:获取接口IX成功.");
		pIX->Fx();          // 使用 IX.
	}

	trace("Client:获取接口IY.");

	IY* pIY = NULL;
	hr = pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
	if (SUCCEEDED(hr))
	{
		trace("Client:         Succeeded getting IY.");
		pIY->Fy();          // 使用 IY.
	}


	trace("Client:是否支持接口IZ.");

	IZ* pIZ = NULL;
	hr = pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ);
	if (SUCCEEDED(hr))
	{
		trace("Client:获取接口IZ成功.");
		pIZ->Fz();
	}
	else
	{
		trace("Client:获取接口IZ失败,不支持接口IZ.");
	}


	trace("Client:用接口IX查询接口IY.");

	IY* pIYfromIX = NULL;
	hr = pIX->QueryInterface(IID_IY, (void**)&pIYfromIX);
	if (SUCCEEDED(hr))
	{    
		trace("Client:获取接口IY成功.");
		pIYfromIX->Fy();
	}


	trace("Client:用接口IY查询接口IUnknown.");

	IUnknown* pIUnknownFromIY = NULL;
	hr = pIY->QueryInterface(IID_IUnknown, (void**)&pIUnknownFromIY);
	if (SUCCEEDED(hr))
	{
		cout << "IUnknown指针是否相等?";
		if (pIUnknownFromIY == pIUnknown)
		{
			cout << "Yes, pIUnknownFromIY == pIUnknown." << endl;
		}
		else
		{
			cout << "No, pIUnknownFromIY != pIUnknown." << endl;
		}
	}

	// Delete the component.
	delete pIUnknown;

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值