【问题标题】:Get IID from interface name in C++? (VS 2010 automation)从 C++ 中的接口名称获取 IID? (VS 2010 自动化)
【发布时间】:2014-09-23 22:03:12
【问题描述】:

给定 COM 接口的名称为字符串,我如何获取相应的 IID 以便调用 QueryInterface()?

例如:

// Attempt to cast IDispatch referenced by pDisp to an ICommandBarButton

char *interface_name = "ICommandBarButton";
IID iid;

<<< code to get the iid for interface_name goes here >>>
hr = pDisp->QueryInterface(iid, &interface);

当然,这假设接口名称在系统范围内是唯一的,如果不是,则需要更多上下文。上下文是我有一个用于自动化 VS 2010 的脚本引擎,并且需要根据从脚本中作为字符串读取的接口名称在类型之间进行转换。我已经有一个 IDispatch* 用于要转换的对象。

编辑:

用户 Alf 评论说我不应该这样做,我很乐意不这样做。使用 ITypeLib,我确定我的 IDispatch(由 CommandBarControls.Add(msoButton) 创建)是一个 CommandBarControl。我需要一个用于 CommandBarButton 的 IDispatch,以便我可以访问特定于按钮的属性,例如 Style 属性——CommandBarControl IDispatch 无法识别此属性。我的 IDispatch AFAIK 上支持的接口是:

Interface:CommandBarControl  GUID:43FD5911-7BAC-4BDC-AB6C-2DE65B5C0233
  Interface:IDispatch  GUID:00020400-0000-0000-C000-000000000046
    Interface:IUnknown  GUID:00000000-0000-0000-C000-000000000046

如下图所示。 CommandBarButton 未在此处列出,因此希望有人向我展示如何仅使用 IDispatch 的运行时机制来执行此转换。

实验代码:

void
GetTypeInfo(ITypeInfo *pTypeInfo, int indent, char *&p)
{
    BSTR        olename;
    TYPEATTR    *typeattr;
    HRESULT     hr;

    hr = pTypeInfo->GetDocumentation(MEMBERID_NIL, &olename, NULL, NULL, NULL);
    if (hr == S_OK)
    {
        for (int i = 0; i < indent; i++)
            *p++ = ' ';
        p += sprintf(p, "Interface:");
        int len = SysStringLen(olename);
        for (int i = 0; i < len; i++)
            *p++ = (char)olename[i];
        *p++ = ' ';
        SysFreeString(olename);
    }

    hr = pTypeInfo->GetTypeAttr(&typeattr);
    if (hr == S_OK)
    {
        p += sprintf(p, " GUID:");
        for (int i = 0; i < 4; i++)
            p += sprintf(p, "%02X", ((unsigned char*)&typeattr->guid.Data1)[3-i]);
        *p++ = '-';
        for (int i = 0; i < 2; i++)
            p += sprintf(p, "%02X", ((unsigned char*)&typeattr->guid.Data2)[1-i]);
        *p++ = '-';
        for (int i = 0; i < 2; i++)
            p += sprintf(p, "%02X", ((unsigned char*)&typeattr->guid.Data3)[1-i]);
        *p++ = '-';
        for (int i = 0; i < 2; i++)
            p += sprintf(p, "%02X", typeattr->guid.Data4[i]);
        *p++ = '-';
        for (int i = 2; i < 8; i++)
            p += sprintf(p, "%02X", typeattr->guid.Data4[i]);
        *p++ = '\n';
        for (int i = 0; i < typeattr->cImplTypes; i++)
        {
            HREFTYPE reftype;
            ITypeInfo   *pTypeInfo2;
            hr = pTypeInfo->GetRefTypeOfImplType(i, &reftype);
            if (hr == S_OK)
            {
                hr = pTypeInfo->GetRefTypeInfo(reftype, &pTypeInfo2);
                if (hr == S_OK)
                {
                    GetTypeInfo(pTypeInfo2, indent + 2, p);
                    pTypeInfo2->Release();
                }
            }
        }
        pTypeInfo->ReleaseTypeAttr(typeattr);
    }
}


void
GetDispatchInfo(IDispatch *pDisp)
{
    char        buffer[16384];
    char        *p = buffer;
    UINT        ticount;
    HRESULT     hr;

    hr = pDisp->GetTypeInfoCount(&ticount);
    if (hr == S_OK)
    {
        for (UINT ti = 0; ti < ticount; ti++)
        {
            ITypeInfo *pTypeInfo;
            hr = pDisp->GetTypeInfo(ti, 0, &pTypeInfo);
            if (hr == S_OK)
            {
                GetTypeInfo(pTypeInfo, 0, p);
                pTypeInfo->Release();
            }
        }
    }
    *p = 0;
    OutputDebugString(buffer);
}

【问题讨论】:

  • 通常的 interface-uuid 关联机制只是编译时的。脚本支持基于 IDispatch 和类型库。您不为此执行QueryInterface(IDispatch 本身除外),您使用IDispatch 的运行时机制。这就是它的用途。为什么不使用它。
  • 谢谢 Alf,我已经修改了问题。
  • 这是不可能的。 COM 唯一关心的是 {guid}。接口的名称是一个逃逸的细节,程序员永远不会做对。编程方便,当您必须与另一个程序互操作时,它很快就会消失。每个人都称它为 IMyInterface,或者它的一些平淡无奇的变体。那行不通,接口必须是全球唯一的。 guid 中的 GU。
  • 也不完全符合您的要求,但您可能需要考虑使用ProgID:visualbasic.freetutes.com/learn-vb6-advanced/lesson4/p35.html

标签: c++ visual-studio-2010 com queryinterface


【解决方案1】:

好的,基于上面的cmets,我认为原来的问题(将接口名称全局转换为GUID)是不可能的。

换句话说,Visual Basic 解释器,提供如下命令:

control = commandBar.Controls.Add(MsoControlType.msoControlButton)
button = DirectCast(control, CommandBarButton)

除了在某些系统范围的表中查找字符串“CommandBarButton”之外,还依赖于其他东西。这似乎是在 IDispatch 及其关联类型库的运行时机制中的某个地方。大概有一种方法可以使用某种类型库 voodoo 来复制 VB 在这里所做的事情。但这不是最初的问题所问的......

编辑:

我找到了解决问题的方法,并在我的相关问题上发布了答案:

IDispatch returns DISP_E_UNKNOWNNAME for CommandBarButton.Style

简而言之,在 IDispatch 中查询 IUnknown,然后再次在 IUnknown 中查询 IDispatch,将返回一个不同的 IDispatch,该 IDispatch 似乎适用于最派生的类(在本例中为 CommandBarButton)。不需要类型库巫术。 希望这对某人有所帮助。

【讨论】:

  • 找到后给出答案的道具。
【解决方案2】:

如果接口已注册(通常用于编组),那么您有可能在注册表中的 HKCR\Interface 下找到它。不幸的是,那里的接口是由 IID 注册的,所以如果你想从 name 中找到 IID,你必须进行线性搜索。

即使那样,也不能保证它可以工作(接口注册不是强制性的,我什至不确定接口名称是注册时的)。

【讨论】:

    猜你喜欢
    • 2016-03-21
    • 2014-08-14
    • 2011-06-15
    • 2013-01-15
    • 2019-08-31
    • 2012-08-02
    • 2019-07-13
    • 1970-01-01
    • 2013-06-21
    相关资源
    最近更新 更多