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使用 IPrintInterfaceIID ,,调用 IUnknown::QueryInterfaceIID 是唯一地标识接口的 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。,因为 IPrintInterfaceIUnknown 接口,直接派生了这是简单的。但是,如果希望支持两个不同接口,两个从 IUnknown派生的,考虑以下几点:

class IEditInterface : public IUnkown
{
public:
    virtual void EditObject() = 0;
};

尽管有多种不同的方法来支持 IEditInterfaceIPrintInterface的类,包括使用 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 的接口映射,实现类

  1. 从 **CCmdTarget.**直接或间接派生类

  2. 使用 DECLARE_INTERFACE_MAP 功能在派生类定义。

  3. 对于希望支持的每个接口,使用 BEGIN_INTERFACE_PARTEND_INTERFACE_PART 宏在类定义。

  4. 实现文件中,请使用 BEGIN_INTERFACE_MAPEND_INTERFACE_MAP 宏定义类的接口映射。

  5. 对于支持的每个 IID,请使用在 BEGIN_INTERFACE_MAPEND_INTERFACE_MAP 宏之间的 INTERFACE_PART 宏映射该 IID 到特定的 “section”的类。

  6. 实现表示接口所支持的每个嵌套类。

  7. 使用 METHOD_PROLOGUE 宏访问父, CCmdTarget派生的对象。

  8. AddRef释放QueryInterface 可能委托到 CCmdTarget 这些功能 (ExternalAddRefExternalReleaseExternalQueryInterface) 的实现。

上面的示例 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_PARTEND_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 版本的。这是不可能的,因为用于包含的 CCmdTargetMETHOD_PROLOGUE 宏 get 访问派生的对象表示嵌入对象的 fixed offsetCCmdTarget的派生对象。,因为 XAdviseSink 取决于在特定偏移量 COleClientItem 对象的顶部,这意味着,例如,不能将 COleClientItem::XAdviseSink的 MFC 的实现派生嵌入 XMyAdviseSink。

说明说明

可以,但是,委托给所有的 MFC 实现功能需要 MFC 的默认行为。这在 IOleInPlaceFrame (XOleInPlaceFrame) 的 MFC 实现对 COleFrameHook 类 (它委托给许多功能的 m_xOleInPlaceUIWindow)。此模型中选择减少实现多个接口对象的运行时范围;它不需要隐藏指针 (例如 m_pParent 该方式在前面的部分)。

5hhehwba.collapse_all(zh-cn,VS.110).gif汇总和接口映射

除了支持独立的 COM 对象外, MFC 还支持聚合。摘要太复杂; 此处讨论的主题请参见 OLE programmer's reference ( 有关概述的更多信息。此说明介绍摘要的支持内置结构和接口映射。

有两种使用摘要:(1) 使用支持聚合的 COM 对象和 (2) 实现可以由另的聚合的对象。这些函数可以称为 “使用复合对象”和 “使对象可聚集的”。MFC 支持两个。

5hhehwba.collapse_all(zh-cn,VS.110).gif使用复合对象

若要使用复合对象,需要某种方法可以附加合成为 QI 结构。换言之,复合对象必须正常运行,就象您的对象的本机部分。因此此关系是否到 MFC 的接口中如何映射结构?为 CCmdTarget 派生类的一部分,除了 INTERFACE_PART 宏外,嵌套的对象映射到 IID,还可以声明复合对象。为此, INTERFACE_AGGREGATE 宏使用。这允许您指定必须是指向 IUnknown 或派生类) 的成员变量 (,将集成接口映射结构。如果指针不为空,则 CCmdTarget::ExternalQueryInterface 调用,则该框架将自动调用复合对象的 QueryInterface 成员函数,因此,如果请求的 IID 不是一个本机 CCmdTarget 对象的支持的 IID

使用 INTERFACE_AGGREGATE 宏

  1. 声明将包含指向复合对象的成员变量 ( IUnknown*)。

  2. 包含一 INTERFACE_AGGREGATE 宏在接口映射,按名称引用成员变量。

  3. 在某些情况下 (通常在 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。通常,您希望复合支持的所有接口。

5hhehwba.collapse_all(zh-cn,VS.110).gif使对象实现可聚集的

对可将对象可聚集的, AddRef的实现, 释放QueryInterface 必须委托为 “控件未知”。换言之,因为它可以是对象的一部分,它必须委托 AddRef释放QueryInterface 到其他对象,也从派生 IUnknown。this “未知”控件提供给对象,则在创建集合时,也就是说,提供给 COleObjectFactory的实现。实现此带有少量的开销和某些情况下不需要的,因此, MFC 使此选项。若要使对象可聚集的,请调用从对象的构造函数 CCmdTarget::EnableAggregation

如果对象还使用聚合,还必须确定传递正确的控件 “未知”向复合对象。通常,当聚合之后,此 IUnknown 指针传递给对象。例如, pUnkOuter 参数是控件 “未知”用 CoCreateInstance创建的对象。正确的控件 “未知”指针可通过调用 CCmdTarget::GetControllingUnknown检索。从该函数返回的值,但是,在构造函数中无效。因此,建议您在 CCmdTarget::OnCreateAggregates只重写创建自己的聚合,从 GetControllingUnknown 的返回值是可靠的,因此,即使创建从 COleObjectFactory 实现。

也是非常重要的对象操作正确引用计数,在添加或释放人工引用计数时。若要确保这种情况下,始终调用 ExternalAddRefExternalRelease 而不是 InternalReleaseInternalAddRef。少见的调用 InternalReleaseInternalAddRef 在支持聚合的类。

5hhehwba.collapse_all(zh-cn,VS.110).gif参考资料

OLE 高级使用,如定义自己的接口或重写 OLE 接口的结构的实现需要使用基接口映射结构。

本节讨论用于实现这些高级功能的每个宏和 API。

5hhehwba.collapse_all(zh-cn,VS.110).gifCCmdTarget::EnableAggregation —函数声明

void EnableAggregation();

备注

,如果希望支持此类型,对象的 OLE 汇总了对该派生类的构造函数中调用此函数。这准备对于可聚集的对象所需的某个特定 IUnknown 实现。

5hhehwba.collapse_all(zh-cn,VS.110).gifCCmdTarget::ExternalQueryInterface —函数声明

DWORD ExternalQueryInterface( 
   const void FAR* lpIID, 
   LPVOID FAR* ppvObj 
);

备注

5hhehwba.collapse_all(zh-cn,VS.110).gif参数

  • lpIID
    对 IID (对 QI 的第一个参数较指针)

  • ppvObj
    为 IUnknown* (对 QI 的第二个参数的指针)

备注

缩放在您的 IUnknown 的实现此功能每个接口的类实现。此功能提供 QI 的标准数据驱动的实现基于您的对象的接口映射。返回值强制转换为 HRESULT 是必需的。如果对象进行聚合,此功能称为 “控件” IUnknown 而不是使用本地接口映射。

5hhehwba.collapse_all(zh-cn,VS.110).gifCCmdTarget::ExternalAddRef —函数声明

DWORD ExternalAddRef();

备注

缩放在您的 IUnknown::AddRef 的实现此功能每个接口的类实现。返回值是新引用在 CCmdTarget 对象的计数。如果对象进行聚合,此功能称为 “控件” IUnknown 而不是操作本地引用计数。

5hhehwba.collapse_all(zh-cn,VS.110).gifCCmdTarget::ExternalRelease —函数声明

DWORD ExternalRelease();

备注

缩放在您的 IUnknown::Release 的实现此功能每个接口的类实现。返回值指示新引用对象中的计数。如果对象进行聚合,此功能称为 “控件” IUnknown 而不是操作本地引用计数。

5hhehwba.collapse_all(zh-cn,VS.110).gifDECLARE INTERFACE MAP - 宏声明

DECLARE_INTERFACE_MAP

备注

使用此宏在从将具有接口映射的 CCmdTarget 任何派生类。使用与 DECLARE_MESSAGE_MAP的方式。在类定义应将此宏调用,通常在头 (。H) 文件。与 DECLARE_INTERFACE_MAP 的类必须定义在实现文件 (.CPP) 的接口映射具有 BEGIN_INTERFACE_MAPEND_INTERFACE_MAP 宏的。

5hhehwba.collapse_all(zh-cn,VS.110).gifBEGIN_INTERFACE_PART 和 END_INTERFACE_PART —宏声明

BEGIN_INTERFACE_PART( 
   localClass,
   iface 
);
END_INTERFACE_PART( 
   localClass 
)

备注

5hhehwba.collapse_all(zh-cn,VS.110).gif参数

  • localClass
    实现接口的类的名称

  • iface
    接口的名称此类实现

备注

对您的类将实现的每个接口,需要一个位置 BEGIN_INTERFACE_PARTEND_INTERFACE_PART 对。这些宏定义从您定义以及该类的嵌入式成员变量的 OLE 接口派生的局部类。AddRef释放QueryInterface 成员将自动声明。必须包括是实现的接口的一部分的其他成员函数的声明 (这些声明放置在 BEGIN_INTERFACE_PARTEND_INTERFACE_PART 宏之间。

iface 参数是要实现,例如 IAdviseSinkIPersistStorage 的 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 可以减少难以解决错误。

5hhehwba.collapse_all(zh-cn,VS.110).gifBEGIN_INTERFACE_MAP 和 END_INTERFACE_MAP —宏声明

BEGIN_INTERFACE_MAP( 
   theClass,
   baseClass 
)
END_INTERFACE_MAP

备注

5hhehwba.collapse_all(zh-cn,VS.110).gif参数

  • theClass
    接口映射要定义的类

  • baseClass
    theClass 从派生的类。

备注

BEGIN_INTERFACE_MAPEND_INTERFACE_MAP 宏用于实现文件确实定义接口映射。对于实现的每个接口具有一个或多 INTERFACE_PART 宏调用。对于类使用的每个聚合,有一 INTERFACE_AGGREGATE 宏调用。

5hhehwba.collapse_all(zh-cn,VS.110).gifINTERFACE PART - 宏声明

INTERFACE_PART( 
   theClass,
   iid, 
   localClass 
)

备注

5hhehwba.collapse_all(zh-cn,VS.110).gif参数

  • 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 任何这些接口: IOleUIWindowIOleWindowIUnknown,除 “大多数派生的”接口 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。

5hhehwba.collapse_all(zh-cn,VS.110).gifINTERFACE PART - 宏声明

INTERFACE_AGGREGATE( 
   theClass,
   theAggr 
)

备注

5hhehwba.collapse_all(zh-cn,VS.110).gif参数

  • theClass
    包含接口映射类的名称,

  • theAggr
    将聚合成员变量的名称。

备注

此宏用于调用框架类使用复合对象。它必须出现在 BEGIN_INTERFACE_PARTEND_INTERFACE_PART 宏之间。复合对象是单独的对象,它从派生 IUnknown。使用聚合和 INTERFACE_AGGREGATE 宏,可以创建复合支持显示由对象直接支持的所有接口。theAggr 参数是您的类的成员变量的名称从 IUnknown 直接或间接派生自。所有 INTERFACE_AGGREGATE 宏在接口映射必须遵循 INTERFACE_PART 宏,在放置。

请参见

其他资源

由Number "技术说明

技术说明按类别