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:
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.