TN038:MFC/OLE IUnknown实现
说明 |
---|
以下技术声明,则它在联机文档,首先包括了不更新。因此,某些过程和主题可能已过时或不正确。有关最新信息,建议您搜索议题在联机文档的索引。 |
在 OLE 2 核心是 “OLE 组件对象模型 (com)”或 COM。COM 定义团队的对象的标准通信。互相。这包括操作的详细信息 “对象”的外观,包括方法在对象中计划。COM 还定义了一个基类,所有 COM 兼容的类派生。该基类是 IUnknown。虽然 IUnknown 接口称为 c. C++ 类, COM 不是特定于任何一种语言 —它可以实现在 C、 PASCAL,也可以支持 COM 对象的二进制格式的其他语言。
OLE 引用某 IUnknown 派生的任何类为 “接口”。,因为在 “接口”例如 IUnknown 不具有与其实现,这是一个重要的区别。它定义对象进行通信,而不是特定的协议某些实现。对于允许以最大限度地提高灵活性系统是合理的。是 MFC 的工作才能实现 MFC/C++ 程序的默认行为。
若要了解 IUnknown 的 MFC 的实现必须先了解此接口是。IUnknown 的简化版本的定义如下:
class IUnknown
{
public:
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
说明 |
---|
某些必要的调用约定详细信息,例如 __stdcall 对此图开除。 |
AddRef 和 释放 成员函数控制对象的内存管理。COM 使用绑定模式的引用记录对象。对象从不直接引用,则在 C++ 一样。相反, COM 对象通过指针始终引用。若要释放对象,在使用它时,所有者执行,对象的 释放 成员调用 (使用 delete 运算符相反,为传统 C++ 对象将执行)。计数框架的引用允许多个对要管理的唯一对象。AddRef 和 释放 的实现可以在对象的引用计数 —对象不会删除,直到其引用计数达到零时。
AddRef 和 释放 从实现位置非常简单。这是一个无足轻重的实现:
ULONG CMyObj::AddRef()
{
return ++m_dwRef;
}
ULONG CMyObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
QueryInterface 成员函数更加有趣的。具有唯一的成员函数是 AddRef 和 释放 —的对象非常不感兴趣的调用对象执行更多操作比 IUnknown 提供好。这是 QueryInterface 很有用的位置。它允许您获得不同的 “接口”在同一对象。这些接口从 IUnknown 通常派生并通过添加新成员函数添加附加功能。COM 接口不具有声明的成员变量。接口,因此,所有成员函数声明为纯虚。例如,
class IPrintInterface : public IUnknown
{
public:
virtual void PrintObject() = 0;
};
获取 IPrintInterface ,如果只有 IUnknown使用 IPrintInterface的 IID ,,调用 IUnknown::QueryInterface 。IID 是唯一地标识接口的 128 位数字。您或 OLE 定义的每个接口的 IID 。如果 拒绝 是指向 IUnknown 对象,检索 IPrintInterface 的代码是从可能是:
IPrintInterface* pPrint = NULL;
if (pUnk->QueryInterface(IID_IPrintInterface,
(void**)&pPrint) == NOERROR)
{
pPrint->PrintObject();
pPrint->Release();
// release pointer obtained via QueryInterface
}
这如何看起来非常简单,但是,您是否实现支持 IPrintInterface 和 IUnknown 接口的对象?在这种情况下它是简单的,因为 IPrintInterface 直接从派生 IUnknown —通过实现 IPrintInterface, IUnknown 自动支持。例如:
class CPrintObj : public CPrintInterface
{
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
virtual void PrintObject();
};
完全相同的与实现的 AddRef 和 释放 的实现上面。CPrintObj::QueryInterface 相仿:
HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
可以看到,因此,如果接口标识符 (IID) 被识别出来,指针返回到对象;否则错误。另外请注意成功的 QueryInterface 导致提示的 AddRef。当然,您还必须实现 CEditObj::Print。,因为 IPrintInterface 从 IUnknown 接口,直接派生了这是简单的。但是,如果希望支持两个不同接口,两个从 IUnknown派生的,考虑以下几点:
class IEditInterface : public IUnkown
{
public:
virtual void EditObject() = 0;
};
尽管有多种不同的方法来支持 IEditInterface 和 IPrintInterface的类,包括使用 C++ 多重继承,此说明将针对使用嵌套类实现此功能。
class CEditPrintObj
{
public:
CEditPrintObj();
HRESULT QueryInterface(REFIID iid, void**);
ULONG AddRef();
ULONG Release();
DWORD m_dwRef;
class CPrintObj : public IPrintInterface
{
public:
CEditPrintObj* m_pParent;
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_printObj;
class CEditObj : public IEditInterface
{
public:
CEditPrintObj* m_pParent;
virtual ULONG QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_editObj;
};
整个实现如下所示包括的:
CEditPrintObj::CEditPrintObj()
{
m_editObj.m_pParent = this;
m_printObj.m_pParent = this;
}
ULONG CEditPrintObj::AddRef()
{
return ++m_dwRef;
}
CEditPrintObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = &m_printObj;
AddRef();
return NOERROR;
}
else if (iid == IID_IEditInterface)
{
*ppvObj = &m_editObj;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG CEditPrintObj::CEditObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CEditObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CEditObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
ULONG CEditPrintObj::CPrintObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CPrintObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CPrintObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
大多数 IUnknown 实现放置到 CEditPrintObj 类而不是) 在 CEditPrintObj::CEditObj 和 CEditPrintObj::CPrintObj 的代码的通知。这将减少代码量并避免 bug。关键点这是一个从的 IUnknown 接口调用 QueryInterface 检索所有接口对象可能支持是可能的,因此,从这些接口中的每一个执行也是可能的。这意味着所有 QueryInterface 功能可从每个接口必须行为方式相同。对这些嵌入对象可以调用 “外部对象的”实现,使用隐藏指针 (m_pParent)。在 CEditPrintObj 构造函数中, m_pParent 指针初始化。然后将实现 CEditPrintObj::CPrintObj::PrintObject 和 CEditPrintObj::CEditObj::EditObject。位代码相当中添加一个功能 —能够编辑对象。不过,只有一个成员函数接口相当罕见的 (尽管它发生),在该示例中, EditObject 和 PrintObject 通常将合并到单个接口中。
这是大量声明和大量代码这样一个简单的情况中。MFC/OLE 类提供更简单的替代方案。MFC 实现使用一种类似于消息将使用消息映射方式窗口。该计算机将在下一节将调用 Interface Maps 和讨论。
MFC 接口映射
MFC/OLE 包括 “接口的实现映射”类似于 MFC “消息映射”, “安排在概念和执行映射”。MFC 的接口映射核心功能如下:
IUnknown的标准实现,内置 CCmdTarget 类。
引用计数的维护,修改 AddRef 和 释放
QueryInterface数据驱动的实现
此外,接口映射支持以下高级功能:
用于创建可聚集的 COM 对象支持
支持在复合对象 COM 对象的实现
实现是 hookable 且可扩展的
有关摘要的更多信息,请参见 OLE 程序员参考。
MFC 的接口映射支持根于 CCmdTarget 类。CCmdTarget “具有”引用计数以及任何成员函数与 IUnknown 实现 (如引用计数。 CCmdTarget)。若要创建支持 OLE COM 的类,则从 CCmdTarget 派生类并使用 CCmdTarget 的各种宏和成员函数实现所需接口。MFC 的实现使用嵌套类定义每个接口实现这与上面的示例。同时还可以轻松地消除某些重复代码 IUnknown 以及许多宏的标准实现。
使用 MFC 的接口映射,实现类
从 **CCmdTarget.**直接或间接派生类
使用 DECLARE_INTERFACE_MAP 功能在派生类定义。
对于希望支持的每个接口,使用 BEGIN_INTERFACE_PART 和 END_INTERFACE_PART 宏在类定义。
实现文件中,请使用 BEGIN_INTERFACE_MAP 和 END_INTERFACE_MAP 宏定义类的接口映射。
对于支持的每个 IID,请使用在 BEGIN_INTERFACE_MAP 和 END_INTERFACE_MAP 宏之间的 INTERFACE_PART 宏映射该 IID 到特定的 “section”的类。
实现表示接口所支持的每个嵌套类。
使用 METHOD_PROLOGUE 宏访问父, CCmdTarget派生的对象。
AddRef、 释放和 QueryInterface 可能委托到 CCmdTarget 这些功能 (ExternalAddRef、 ExternalRelease和 ExternalQueryInterface) 的实现。
上面的示例 CPrintEditObj 的能实现如下所示:
class CPrintEditObj : public CCmdTarget
{
public:
// member data and member functions for CPrintEditObj go here
// Interface Maps
protected:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(EditObj, IEditInterface)
STDMETHOD_(void, EditObject)();
END_INTERFACE_PART(EditObj)
BEGIN_INTERFACE_PART(PrintObj, IPrintInterface)
STDMETHOD_(void, PrintObject)();
END_INTERFACE_PART(PrintObj)
};
上述声明 CCmdTarget创建从派生的类。DECLARE_INTERFACE_MAP 宏调用框架此类将具有自定义接口映射。此外, BEGIN_INTERFACE_PART 和 END_INTERFACE_PART 宏定义嵌套类,在使用名称 CEditObj 和 CPrintObj (X 仅用于区分以 “C”的全局类和从 “i”开头的接口) 类的嵌套类。这些类的两个嵌套的成员创建的:m_CEditObj 和 m_CPrintObj,分别。宏自动声明 AddRef、 释放和 QueryInterface 功能;因此只声明函数特定于此接口:EditObject 和 PrintObject (使用 OLE 宏 STDMETHOD 这样,以便 _stdcall 和 virtual 关键字提供以适合目标平台)。
实现此类的接口映射:
BEGIN_INTERFACE_MAP(CPrintEditObj, CCmdTarget)
INTERFACE_PART(CPrintEditObj, IID_IPrintInterface, PrintObj)
INTERFACE_PART(CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()
这将 m_CPrintObj 连接 IID_IPrintInterface IID 和 IID_IEditInterface 用单个 m_CEditObj。QueryInterface (CCmdTarget::ExternalQueryInterface) 的 CCmdTarget 实现使用此映射返回指向 m_CPrintObj 和 m_CEditObj,当请求。包括 IID_IUnknown的项并不是必需的;框架在映射 (在这种情况下, m_CPrintObj) 将使用第一个接口,当 IID_IUnknown 请求。
即使 BEGIN_INTERFACE_PART 宏自动声明 AddRef、 释放 和 QueryInterface 函数您的,您仍需要实现它们:
ULONG FAR EXPORT CEditPrintObj::XEditObj::AddRef()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CEditPrintObj::XEditObj::Release()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CEditPrintObj::XEditObj::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
void FAR EXPORT CEditPrintObj::XEditObj::EditObject()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
// code to "Edit" the object, whatever that means...
}
CEditPrintObj::CPrintObj 的实现,类似于 CEditPrintObj::CEditObj 的上述定义。尽管创建可用于自动生成这些功能的宏 (不过,在之前的 MFC/OLE 开发所用例) 为,可以设置断点变得非常困难宏时生成多行代码。因此,此代码手动展开。
通过使用消息映射机制实现,它具有不需要执行的许多事情:
实现 QI
实现 AddRef 和释放
声明了两个的这些内置方法之一应用于接口
此外,框架在内部使用消息映射。这允许您从框架类派生,指出 COleServerDoc,已经支持某些接口并提供替换或向框架提供的接口。这是通过该条件启用框架完全支持 继承 的接口映射为原因的基类 —原因 BEGIN_INTERFACE_MAP 采用作为其第二个参数基类的名称。
说明 |
---|
通过 继承 该接口的嵌入式专用化重新使用 OLE 接口的 MFC 的内置实现的实现通常不可以从 MFC 版本的。这是不可能的,因为用于包含的 CCmdTarget的 METHOD_PROLOGUE 宏 get 访问派生的对象表示嵌入对象的 fixed offset 从 CCmdTarget的派生对象。,因为 XAdviseSink 取决于在特定偏移量 COleClientItem 对象的顶部,这意味着,例如,不能将 COleClientItem::XAdviseSink的 MFC 的实现派生嵌入 XMyAdviseSink。 |
说明 |
---|
可以,但是,委托给所有的 MFC 实现功能需要 MFC 的默认行为。这在 IOleInPlaceFrame (XOleInPlaceFrame) 的 MFC 实现对 COleFrameHook 类 (它委托给许多功能的 m_xOleInPlaceUIWindow)。此模型中选择减少实现多个接口对象的运行时范围;它不需要隐藏指针 (例如 m_pParent 该方式在前面的部分)。 |
汇总和接口映射
除了支持独立的 COM 对象外, MFC 还支持聚合。摘要太复杂; 此处讨论的主题请参见 OLE programmer's reference ( 有关概述的更多信息。此说明介绍摘要的支持内置结构和接口映射。
有两种使用摘要:(1) 使用支持聚合的 COM 对象和 (2) 实现可以由另的聚合的对象。这些函数可以称为 “使用复合对象”和 “使对象可聚集的”。MFC 支持两个。
使用复合对象
若要使用复合对象,需要某种方法可以附加合成为 QI 结构。换言之,复合对象必须正常运行,就象您的对象的本机部分。因此此关系是否到 MFC 的接口中如何映射结构?为 CCmdTarget 派生类的一部分,除了 INTERFACE_PART 宏外,嵌套的对象映射到 IID,还可以声明复合对象。为此, INTERFACE_AGGREGATE 宏使用。这允许您指定必须是指向 IUnknown 或派生类) 的成员变量 (,将集成接口映射结构。如果指针不为空,则 CCmdTarget::ExternalQueryInterface 调用,则该框架将自动调用复合对象的 QueryInterface 成员函数,因此,如果请求的 IID 不是一个本机 CCmdTarget 对象的支持的 IID。
使用 INTERFACE_AGGREGATE 宏
声明将包含指向复合对象的成员变量 ( IUnknown*)。
包含一 INTERFACE_AGGREGATE 宏在接口映射,按名称引用成员变量。
在某些情况下 (通常在 CCmdTarget::OnCreateAggregates句点) 除了对之外,中,初始化成员变量为其。
例如:
class CAggrExample : public CCmdTarget
{
public:
CAggrExample();
protected:
LPUNKNOWN m_lpAggrInner;
virtual BOOL OnCreateAggregates();
DECLARE_INTERFACE_MAP()
// "native" interface part macros may be used here
};
CAggrExample::CAggrExample()
{
m_lpAggrInner = NULL;
}
BOOL CAggrExample::OnCreateAggregates()
{
// wire up aggregate with correct controlling unknown
m_lpAggrInner = CoCreateInstance(CLSID_Example,
GetControllingUnknown(), CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID*)&m_lpAggrInner);
if (m_lpAggrInner == NULL)
return FALSE;
// optionally, create other aggregate objects here
return TRUE;
}
BEGIN_INTERFACE_MAP(CAggrExample, CCmdTarget)
// native "INTERFACE_PART" entries go here
INTERFACE_AGGREGATE(CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()
m_lpAggrInner 在构造函数初始化为 NULL。框架将完全忽略中 QueryInterface的默认实现的空成员变量。OnCreateAggregates 是实际创建您的复合对象的适合放置。,如果创建对象。 COleObjectFactory的 MFC 实现的外部,则必须显式调用它。创建聚合。 CCmdTarget::OnCreateAggregates 以及 CCmdTarget::GetControllingUnknown 用法的原因会变得很明显,当创建可聚集的对象时讨论。
此方法将向您提供的接口对象的聚合对象支持函数的本机接口中。如果您希望复合支持接口的子集,您可以重写 CCmdTarget::GetInterfaceHook。这使您非常低级别 hookability,与 QueryInterface。通常,您希望复合支持的所有接口。
使对象实现可聚集的
对可将对象可聚集的, AddRef的实现, 释放和 QueryInterface 必须委托为 “控件未知”。换言之,因为它可以是对象的一部分,它必须委托 AddRef、 释放和 QueryInterface 到其他对象,也从派生 IUnknown。this “未知”控件提供给对象,则在创建集合时,也就是说,提供给 COleObjectFactory的实现。实现此带有少量的开销和某些情况下不需要的,因此, MFC 使此选项。若要使对象可聚集的,请调用从对象的构造函数 CCmdTarget::EnableAggregation 。
如果对象还使用聚合,还必须确定传递正确的控件 “未知”向复合对象。通常,当聚合之后,此 IUnknown 指针传递给对象。例如, pUnkOuter 参数是控件 “未知”用 CoCreateInstance创建的对象。正确的控件 “未知”指针可通过调用 CCmdTarget::GetControllingUnknown检索。从该函数返回的值,但是,在构造函数中无效。因此,建议您在 CCmdTarget::OnCreateAggregates只重写创建自己的聚合,从 GetControllingUnknown 的返回值是可靠的,因此,即使创建从 COleObjectFactory 实现。
也是非常重要的对象操作正确引用计数,在添加或释放人工引用计数时。若要确保这种情况下,始终调用 ExternalAddRef 和 ExternalRelease 而不是 InternalRelease 和 InternalAddRef。少见的调用 InternalRelease 或 InternalAddRef 在支持聚合的类。
参考资料
OLE 高级使用,如定义自己的接口或重写 OLE 接口的结构的实现需要使用基接口映射结构。
本节讨论用于实现这些高级功能的每个宏和 API。
CCmdTarget::EnableAggregation —函数声明
void EnableAggregation();
备注
,如果希望支持此类型,对象的 OLE 汇总了对该派生类的构造函数中调用此函数。这准备对于可聚集的对象所需的某个特定 IUnknown 实现。
CCmdTarget::ExternalQueryInterface —函数声明
DWORD ExternalQueryInterface(
const void FAR* lpIID,
LPVOID FAR* ppvObj
);
备注
参数
lpIID
对 IID (对 QI 的第一个参数较指针)ppvObj
为 IUnknown* (对 QI 的第二个参数的指针)
备注
缩放在您的 IUnknown 的实现此功能每个接口的类实现。此功能提供 QI 的标准数据驱动的实现基于您的对象的接口映射。返回值强制转换为 HRESULT 是必需的。如果对象进行聚合,此功能称为 “控件” IUnknown 而不是使用本地接口映射。
CCmdTarget::ExternalAddRef —函数声明
DWORD ExternalAddRef();
备注
缩放在您的 IUnknown::AddRef 的实现此功能每个接口的类实现。返回值是新引用在 CCmdTarget 对象的计数。如果对象进行聚合,此功能称为 “控件” IUnknown 而不是操作本地引用计数。
CCmdTarget::ExternalRelease —函数声明
DWORD ExternalRelease();
备注
缩放在您的 IUnknown::Release 的实现此功能每个接口的类实现。返回值指示新引用对象中的计数。如果对象进行聚合,此功能称为 “控件” IUnknown 而不是操作本地引用计数。
DECLARE INTERFACE MAP - 宏声明
DECLARE_INTERFACE_MAP
备注
使用此宏在从将具有接口映射的 CCmdTarget 任何派生类。使用与 DECLARE_MESSAGE_MAP的方式。在类定义应将此宏调用,通常在头 (。H) 文件。与 DECLARE_INTERFACE_MAP 的类必须定义在实现文件 (.CPP) 的接口映射具有 BEGIN_INTERFACE_MAP 和 END_INTERFACE_MAP 宏的。
BEGIN_INTERFACE_PART 和 END_INTERFACE_PART —宏声明
BEGIN_INTERFACE_PART(
localClass,
iface
);
END_INTERFACE_PART(
localClass
)
备注
参数
localClass
实现接口的类的名称iface
接口的名称此类实现
备注
对您的类将实现的每个接口,需要一个位置 BEGIN_INTERFACE_PART 和 END_INTERFACE_PART 对。这些宏定义从您定义以及该类的嵌入式成员变量的 OLE 接口派生的局部类。AddRef、 释放和 QueryInterface 成员将自动声明。必须包括是实现的接口的一部分的其他成员函数的声明 (这些声明放置在 BEGIN_INTERFACE_PART 和 END_INTERFACE_PART 宏之间。
iface 参数是要实现,例如 IAdviseSink或 IPersistStorage 的 OLE 接口 (或您的自定义接口)。
localClass 参数是要定义局部类的名称。" X " 将被自动预置为名称。此命名约定用于避免同名的全局类的冲突。此外,嵌入成员,与相同 localClass 授予的名称,但它由 “m_x 前缀。
例如:
BEGIN_INTERFACE_PART(MyAdviseSink, IAdviseSink)
STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM);
STDMETHOD_(void,OnViewChange)(DWORD, LONG);
STDMETHOD_(void,OnRename)(LPMONIKER);
STDMETHOD_(void,OnSave)();
STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)
将定义局部类调用从 IAdviseSink 派生的 XMyAdviseSink 的和声明它调用的 m_xMyAdviseSink.Note 类的成员:
说明 |
---|
从 STDMETHOD_ 开头的行从 OLE2.H 基本复制和略微修改。复制它们从 OLE2.H 可以减少难以解决错误。 |
BEGIN_INTERFACE_MAP 和 END_INTERFACE_MAP —宏声明
BEGIN_INTERFACE_MAP(
theClass,
baseClass
)
END_INTERFACE_MAP
备注
参数
theClass
接口映射要定义的类baseClass
theClass 从派生的类。
备注
BEGIN_INTERFACE_MAP 和 END_INTERFACE_MAP 宏用于实现文件确实定义接口映射。对于实现的每个接口具有一个或多 INTERFACE_PART 宏调用。对于类使用的每个聚合,有一 INTERFACE_AGGREGATE 宏调用。
INTERFACE PART - 宏声明
INTERFACE_PART(
theClass,
iid,
localClass
)
备注
参数
theClass
包含接口映射类的名称。iid
将映射到嵌入类的 IID 。localClass
局部类的名称 (" X ")。
备注
此宏使用在 BEGIN_INTERFACE_MAP 宏和 END_INTERFACE_MAP 宏之间您的对象将支持的每个接口的。它使您可以映射 IID 到 theClass 和 localClass一个类的成员。“m_x 将自动添加到 localClass 。请注意多个 IID 可以与一个成员。,当您仅实现一个 “大多数派生的”接口并希望提供所有中间接口时,这非常有用。此的一个很好的示例。 IOleInPlaceFrameWindow 接口。其层次结构如下所示:
IUnknown
IOleWindow
IOleUIWindow
IOleInPlaceFrameWindow
如果对象实现 IOleInPlaceFrameWindow,客户端可以在的 QueryInterface 任何这些接口: IOleUIWindow、 IOleWindow或 IUnknown,除 “大多数派生的”接口 IOleInPlaceFrameWindow (您实际实现) 进行等。处理这可以使用多个 INTERFACE_PART 宏映射每个基接口。 IOleInPlaceFrameWindow 接口:
在类定义文件:
BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)
在类中实现文件:
BEGIN_INTERFACE_MAP(CMyWnd, CFrameWnd)
INTERFACE_PART(CMyWnd, IID_IOleWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleUIWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP
,因为始终需要,该结构负责 IUnknown。
INTERFACE PART - 宏声明
INTERFACE_AGGREGATE(
theClass,
theAggr
)
备注
参数
theClass
包含接口映射类的名称,theAggr
将聚合成员变量的名称。
备注
此宏用于调用框架类使用复合对象。它必须出现在 BEGIN_INTERFACE_PART 和 END_INTERFACE_PART 宏之间。复合对象是单独的对象,它从派生 IUnknown。使用聚合和 INTERFACE_AGGREGATE 宏,可以创建复合支持显示由对象直接支持的所有接口。theAggr 参数是您的类的成员变量的名称从 IUnknown 直接或间接派生自。所有 INTERFACE_AGGREGATE 宏在接口映射必须遵循 INTERFACE_PART 宏,在放置。