Получить IID из имени интерфейса в C ++? (VS 2010 автоматизация)

Учитывая имя интерфейса 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. Мне нужен IDispatch для CommandBarButton, чтобы я мог получить доступ к свойствам, отдельным для кнопок, например, к свойству 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);
}

1

Решение

Хорошо, основываясь на вышеупомянутых комментариях, я думаю, что оригинальный вопрос (преобразовать имя интерфейса в GUID глобально) не возможен.

Другими словами, интерпретатор Visual Basic представлен такими командами:

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

полагается на что-то другое, чем поиск строки «CommandBarButton» в какой-то общесистемной таблице. И это что-то, кажется, находится где-то внутри механизмов времени выполнения IDispatch и связанной с ним библиотеки типов. Предположительно, есть способ повторить то, что делает здесь VB, используя некоторую библиотеку типов voodoo. Но это не то, что задал оригинальный вопрос ….

РЕДАКТИРОВАТЬ:

Я нашел обходной путь к своей проблеме и разместил ответ на мой связанный вопрос:

IDispatch возвращает DISP_E_UNKNOWNNAME для CommandBarButton.Style

В двух словах, запрос IDispatch для IUnknown, а затем повторный запрос IUnknown для IDispatch возвращает другой IDispatch, который, по-видимому, предназначен для самого производного класса (в данном случае CommandBarButton). Библиотека вуду не нужна.
Надеюсь, это кому-нибудь поможет.

2

Другие решения

Если интерфейс зарегистрирован (обычно для маршаллинга), есть вероятность, что вы можете найти его в Реестре, в разделе HKCR \ Interface. К сожалению, имеющиеся там интерфейсы зарегистрированы по IID, поэтому, если вы хотите найти IID по имени, вам придется выполнить линейный поиск.

И даже тогда, это не будет гарантированно работать (регистрация интерфейса не обязательна, и я даже не уверен, что имя интерфейса при регистрации).

0

По вопросам рекламы [email protected]