在给定COM接口(interface)名称为字符串的情况下,如何获取相应的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);

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

编辑:

Alf用户评论说,我不需要这样做,很高兴不这样做。使用ITypeLib,我确定我的IDispatch(由CommandBarControls.Add(msoButton)创建)是CommandBarControl。我需要一个用于CommandBarButton的IDispatch,以便可以访问按钮特有的属性,例如Style属性-CommandBarControl IDispatch无法识别该属性。我的IDispatch AFAIK支持的接口(interface)是:
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)名称全局转换为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)。不需要类型库伏都教。
希望这对某人有帮助。

07-27 19:09