简体   繁体   中英

Get IID from interface name in C++? (VS 2010 automation)

Given the name of a COM interface as a string, how do I get the corresponding IID so that I can call QueryInterface()?

For example:

// 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);

Of course this assumes interface names are unique system-wide, if they aren't then more context is needed. The context is that I have a scripting engine for automating VS 2010, and need to cast between types based on interface names that are read from the script as strings. I already have an IDispatch* for the object to be cast.

EDIT:

User Alf commented that I shouldn't need to do this, and I'd be happy not to. Using ITypeLib, I've determined that my IDispatch (created by CommandBarControls.Add(msoButton)) is a CommandBarControl. I need an IDispatch for CommandBarButton so that I can access properties sepcific to buttons, such as the Style property -- the CommandBarControl IDispatch does not recognise to this property. The supported interfaces on my IDispatch, AFAIK, are:

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

Generated as shown below. CommandBarButton is not listed here, so would love someone to show me how to do this cast using only runtime mechanisms of IDispatch.

Experimental code:

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);
}

OK, based on the above comments, I think the original question (convert an interface name to a GUID globally) is not possible.

In other words, the Visual Basic interpreter, presented with commands such as this:

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

relies on something other than looking up the string "CommandBarButton" in some system-wide table. And that something appears to be somewhere inside the runtime mechanisms of IDispatch and its associated type library. Presumably there is a way to replicate what VB is doing here, using some type library voodoo. But that's not what the original question asked....

EDIT:

I found a workaround to my problem, and posted the answer on my related question:

IDispatch returns DISP_E_UNKNOWNNAME for CommandBarButton.Style

In a nutshell, querying the IDispatch for IUnknown, then querying the IUnknown for IDispatch again, returns a different IDispatch which appears to be for the most derived class (CommandBarButton in this case). No type library voodoo needed. Hope this helps someone.

If the interface is registered (usually for marshalling), then there's a chance you may find it in the Registry, under HKCR\\Interface. Unfortunately the interfaces that are there are registered by IID, so if you wanted to find the IID from name you'd have to do a linear search.

And even then, it wouldn't be guaranteed to work (interface registration isn't mandatory, and I'm not even sure the interface name is when registering one).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM