TN039:MFC/OLE自动实现

备注

以下技术声明,则它在联机文档,首先包括了不更新。因此,某些过程和主题可能已过时或不正确。有关最新信息,建议您搜索议题在联机文档的索引。

OLE IDispatch 接口概述

IDispatch 接口是应用程序公开方法和属性这样的方法其他应用程序 (如 Visual Basic 中,或其他语言,可以利用应用程序的功能。 此接口的重要部分是 IDispatch::Invoke 功能。 MFC 使用 “计划映射”实现 IDispatch::Invoke。 计划映射到窗体或 “形状”提供 MFC 实现的信息。 CCmdTarget派生类,以便它能直接操作对象的属性,或调用在对象中的成员函数满足 IDispatch::Invoke 请求。

大多数情况下,访问 ClassWizard 和 MFC 协作隐藏大多数 OLE 自动化详细应用程序程序员。 程序员在应用程序集中实际功能显示,因此不必担心基础管道。

,但是,在有些情况之了解是必需的 " MFC 在后台执行。 此说明将解析框架如何分配 DISPIDs 到成员函数和属性。 算法 MFC 使用的知识分配的 DISPID的仅是必要的,因为您需要知道 ID 时,例如,当您创建应用程序的对象的某个 “类型库”。

MFC DISPID 分配

尽管自动化 (例如 Visual Basic 用户的最终用户,),查看启用自动化属性的实际在其代码的名称和方法 (例如 obj.ShowWindow), IDispatch::Invoke 的实现不接收实际名称。 对于优化原因,它接受 DISPID,是 32 位 “魔术 cookie”描述方法或属性的列。 这些 DISPID 值从 IDispatch 实现返回通过另一个方法,调用 IDispatch::GetIDsOfNames。 自动化客户端应用程序调用一次。它预期访问的 GetIDsOfNames 每个成员或属性的,并且,它们为稍后对 IDispatch::Invoke的缓存。 这样,使用大字符串中查找一次对象只用于完成,而不是一次 IDispatch::Invoke 调用。

MFC 确定具体取决于两点和属性的 DISPID中的每个方法:

  • 从计划映射 (1 个相对) 的顶部距离

  • 计划映射的距离派生类 (0 个相对)

DISPID 分为两部分。 DISPIDLOWORD 包含第一个元素,从计划映射的顶部距离。 HIWORD 包含从派生类的距离。 例如:

class CDispPoint : public CCmdTarget
{
public:
    short m_x, m_y;
    ...
    DECLARE_DISPATCH_MAP()
    ...
};

class CDisp3DPoint : public CDispPoint
{
public:
    short m_z;
    ...
    DECLARE_DISPATCH_MAP()
    ...
};

BEGIN_DISPATCH_MAP(CDispPoint, CCmdTarget)
    DISP_PROPERTY(CDispPoint, "x", m_x, VT_I2)
    DISP_PROPERTY(CDispPoint, "y", m_y, VT_I2)
END_DISPATCH_MAP()

BEGIN_DISPATCH_MAP(CDisp3DPoint, CDispPoint)
    DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
END_DISPATCH_MAP()

可以看到,有两类,这两个显示 OLE 自动化接口。 这些类之一从其他派生从而利用基类的功能,包括 OLE 自动化部分 (“x”和 “y”属性在本例中为)。

MFC 将生成类的 CDispPoint DISPIDs 如下所示:

property X    (DISPID)0x00000001
property Y    (DISPID)0x00000002

因为属性不在基类, DISPIDHIWORD 始终为零 (派生类的距离 CDispPoint 的是零开始)。

MFC 将生成类的 CDisp3DPoint DISPIDs 如下所示:

property Z    (DISPID)0x00000001
property X    (DISPID)0x00010001
property Y    (DISPID)0x00010002

为 Z 属性与零 HIWORDDISPID ,因为它在显示属性的类, CDisp3DPoint 定义。 从 X 和 Y 属性在基类中定义, DISPIDHIWORD 为 1,,因为这些定义属性的类在远处派生从派生类。

备注

LOWORD 始终依赖于映射的位置,因此,即使存在映射的项与显式 DISPID (请参见下一节有关 DISP_PROPERTYDISP_FUNCTION 宏的信息 _ID 版本)。

高级 MFC 调度映射函数

具有类向导不支持与 Visual C++ 此版本的许多其他功能。 ClassWizard 分别支持定义方法、成员变量的属性和 get/set 成员功能的属性 DISP_FUNCTIONDISP_PROPERTYDISP_PROPERTY_EX ,。 这些功能通常是需要的创建大多数自动化服务器的所有。

以下附加宏,当类向导支持的宏不充分时,可使用: DISP_PROPERTY_NOTIFYDISP_PROPERTY_PARAM

DISP PROPERTY NOTIFY - 宏声明

DISP_PROPERTY_NOTIFY( 
   theClass, 
   pszName, 
   memberName, 
   pfnAfterSet, 
   vtPropType 
)

备注

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

  • theClass
    类的名称。

  • pszName
    属性的外部名称。

  • memberName
    属性存储成员变量的名称。

  • pfnAfterSet
    成员函数名时调用的属性更改为。

  • vtPropType
    指定属性的值。

备注

此宏十分类似于 DISP_PROPERTY,不同之处在于,它接受其他参数。 附加参数, pfnAfterSet, 应为没有返回并不采用参数的成员函数, “void OnPropertyNotify ()”。 ,在 修改后,它将调用成员变量。

DISP PROPERTY PARAM - 宏声明

DISP_PROPERTY_PARAM( 
   theClass,
   pszName,
   pfnGet,
   pfnSet,
   vtPropType,
   vtsParams 
)

备注

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

  • theClass
    类的名称。

  • pszName
    属性的外部名称。

  • memberGet
    成员函数名使用了获取属性。

  • memberSet
    成员函数名使用设置属性。

  • vtPropType
    指定属性的值。

  • vtsParams
    空间字符串分隔每个参数的 VTS_。

备注

这与 DISP_PROPERTY_EX 宏,该宏定义一个属性获取与单独获取和设置成员函数。 此宏,不过,允许您指定属性的参数列表。 对于实现索引或参数化用某种其他方式的属性是很有用的。 参数将被属性的新值始终首先中,按照。 例如:

DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH,    VTS_I2 VTS_I2)

将相应获取和设置成员函数:

LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)

- 宏声明

DISP_FUNCTION_ID( 
   theClass,
   pszName,
   dispid,
   pfnMember,
   vtRetVal,
   vtsParams 
)
DISP_PROPERTY_ID( 
   theClass,
   pszName,
   dispid,
   memberName,
   vtPropType 
)
DISP_PROPERTY_NOTIFY_ID( 
   theClass,
   pszName,
   dispid,
   memberName,
   pfnAfterSet,
   vtPropType 
)
DISP_PROPERTY_EX_ID( 
   theClass,
   pszName,
   dispid,
   pfnGet,
   pfnSet,
   vtPropType 
)
DISP_PROPERTY_PARAM_ID( 
   theClass,
   pszName,
   dispid,
   pfnGet,
   pfnSet,
   vtPropType,
   vtsParams 
)

备注

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

  • theClass
    类的名称。

  • pszName
    属性的外部名称。

  • dispid
    属性或方法的内置的 DISPID。

  • pfnGet
    成员函数名使用了获取属性。

  • pfnSet
    成员函数名使用设置属性。

  • memberName
    成员变量的名称传递给映射于属性

  • vtPropType
    指定属性的值。

  • vtsParams
    空间字符串分隔每个参数的 VTS_。

备注

这些宏允许您指定 DISPID 而不是让 MFC 自动分配一个。 这些高级宏具有相同的名称,但 ID 追加到宏名 (即。 在 pszName 参数后面指定的参数取决于DISP_PROPERTY_ID) 和 ID。 请参见 AFXDISP.H 有关这些宏的更多信息。 必须将 _ID 项在计划映射的末尾。 它们将影响自动 DISPID 生成,与宏的非**_ID** 版本会类似的方式 (位置取决于 DISPID属于)。 例如:

BEGIN_DISPATCH_MAP(CDisp3DPoint, CCmdTarget)
    DISP_PROPERTY(CDisp3DPoint, "y", m_y, VT_I2)
    DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
    DISP_PROPERTY_ID(CDisp3DPoint, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()

MFC 将生成类的 CDisp3DPoint Dispid 如下所示:

property X    (DISPID)0x00020003
property Y    (DISPID)0x00000002
property Z     (DISPID)0x00000001

指定固定的 DISPID 有用维护向后兼容到以前现有的调度接口,或者为实现特定系统定义了方法或属性 (通常由负 DISPID,例如 DISPID_NEWENUM 集合)。

w7a36sdf.collapse_all(zh-cn,VS.110).gif检索 COleClientItem 的 IDispatch 接口

许多服务器支持在其中的自动化与 OLE 服务器功能的文档,对象。 为了使用此自动化接口的访问, COleClientItem::m_lpObject 成员变量访问直接是必需的。 下面的代码将检索从 COleClientItem派生的对象的 IDispatch 接口。 ,如果发现此功能需要,可以在应用程序中包含以下代码:

LPDISPATCH CMyClientItem::GetIDispatch()
{
    ASSERT_VALID(this);
    ASSERT(m_lpObject != NULL);

    LPUNKNOWN lpUnk = m_lpObject;

    Run();    // must be running

    LPOLELINK lpOleLink = NULL;
    if (m_lpObject->QueryInterface(IID_IOleLink, 
        (LPVOID FAR*)&lpOleLink) == NOERROR)
    {
        ASSERT(lpOleLink != NULL);
        lpUnk = NULL;
        if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
        {
            TRACE0("Warning: Link is not connected!\n");
            lpOleLink->Release();
            return NULL;
        }
        ASSERT(lpUnk != NULL);
    }

    LPDISPATCH lpDispatch = NULL;
    if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch) 
        != NOERROR)
    {
        TRACE0("Warning: does not support IDispatch!\n");
        return NULL;
    }

    ASSERT(lpDispatch != NULL);
    return lpDispatch;
}

可以直接地使用从该函数返回的调度接口或附加到 COleDispatchDriver 为类型安全的访问。 如果直接使用,请确保您传递具有指针时调用其 释放 成员,则默认情况下 ( COleDispatchDriver 析构函数执行)。

请参见

其他资源

由Number "技术说明

技术说明按类别