COM编程基础
Table of contents
一、IUnknown 接口
我们先简单看下IUnknown接口的定义:
MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
IUnknown
{
public:
BEGIN_INTERFACE
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
template<class Q>
HRESULT
#ifdef _M_CEE_PURE
__clrcall
#else
STDMETHODCALLTYPE
#endif
QueryInterface(_COM_Outptr_ Q** pp)
{
return QueryInterface(__uuidof(Q), (void **)pp);
}
END_INTERFACE
};
IUnknown接口包含了3个基础方法,分别是QueryInterface,AddRef,Release。
- AddRef 和 Release 通过控制对象的引用计数来控制生命周期。
- QueryInterface 是该对象其他接口的查询方法,参数分别是要查询接口的 IID 和 一个传出参数,以供查询者接收。
例如:
MIDL_INTERFACE("eabd8132-1ac2-4cf2-99aa-e94d1189ea2b")
InfComDemo : IUnknown
{
virtual HRESULT STDMETHODCALLTYPE Method1() = 0;
virtual HRESULT STDMETHODCALLTYPE Method2() = 0;
};
MIDL_INTERFACE("13fb16b2-25ff-4c83-a7fa-375107e00267")
InfComDemoEx : InfComDemo
{
virtual HRESULT STDMETHODCALLTYPE Method3() = 0;
virtual HRESULT STDMETHODCALLTYPE Method4() = 0;
};
CComPtr<InfComDemo> pInfComDemo;
CComPtr<InfComDemoEx> pInfComDemoEx;
loader->CreateInstance(pInfComDemo);
pInfComDemoEx->QueryInterface(&pInfComDemo);
CComPtr<InfComDemoEx> pInfComDemo3;
pInfComDemo3 = pInfComDemo;
这里没有使用原始的接口指针来实现,而是使用了ATL标准库提供的模板类CComPtr对指针进行管理。
通常来说,可以简单的通过QueryInterface来判断该对象对某个接口的支持程度是一个不错的办法。
二、COM对象的实现
我们基于上述的两个接口,先简单的实现一个类
2.1 ClsComDemoImpl.h
class ClsComDemoImpl
: public InfComDemoEx
, public CComObjectRootEx<CComMultiThreadModel>
{
public:
using ThisClass = ClsComDemoImpl;
using ThisCoClass = CComObject<ThisClass>;
using ThisCoAggClass = CComAggObject<ThisClass>;
public:
ClsComDemoImpl();
~ClsComDemoImpl();
BEGIN_COM_MAP(ClsComDemoImpl)
COM_INTERFACE_ENTRY(InfComDemo)
COM_INTERFACE_ENTRY(InfComDemoEx)
END_COM_MAP()
DECLARE_COM_MY_INSTANCE_CREATER(ThisClass)
public: //InfComDemo
virtual HRESULT STDMETHODCALLTYPE Method1() override;
virtual HRESULT STDMETHODCALLTYPE Method2() override;
public: //InfComDemoEx
virtual HRESULT STDMETHODCALLTYPE Method3() override;
virtual HRESULT STDMETHODCALLTYPE Method4() override;
};
2.2 ClsComDemo.h
class ATL_NO_VTABLE ClsComDemo
: public ClsComDemoImpl
, public CComCoClass<ClsComDemoImpl, &CLSID_ClsComDemo>
{
public:
ClsComDemo() = default;
~ClsComDemo() = default;
DECLARE_CLASSFACTORY()
DECLARE_REGISTRY_RESOURCEID(IDR_CLSCOMDEMO)
DECLARE_AGGREGATABLE(ThisClass)
DECLARE_COM_MY_INSTANCE_CREATER(ThisClass)
};
OBJECT_ENTRY_AUTO(CLSID_ClsComDemo, ClsComDemo);
先看这两个文件
三、COM对象的创建
- 3.1 模块内的COM对象创建
CComPtr<CComObject<ClsComDemo>> pTarget; CComObject<ClsComDemo>::CreateInstance(&pTarget);