Получить 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);
}

2 ответа

Хорошо, основываясь на вышеупомянутых комментариях, я думаю, что оригинальный вопрос (преобразовать имя интерфейса в 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). Библиотека вуду не нужна. Надеюсь, это кому-нибудь поможет.

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

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

Другие вопросы по тегам