Хобрук: Ваш путь к мастерству в программировании

Получить DISPID исходящего члена dispinterface

Я застрял на этом.

Даны три переменные:

  • IDispatch* к подключаемому объекту
  • IID (DIID) исходящего дисп-интерфейса на этом объекте
  • имя члена, определяемое диспетчерским интерфейсом

Как преобразовать имя в DISPID?

  • pDispatch->GetIDsOfNames(...) возвращает DISP_E_UNKNOWNNAME, как и следовало ожидать (исходящие интерфейсы не реализуются подключаемым объектом)
  • Мне нужно поддерживать сценарии, когда 0 клиентов еще не подключились к исходящему интерфейсу, поэтому я не могу перечислить существующие точки подключения, чтобы вызвать GetIDsOfNames на одной из них (я даже не уверен, что это сработает)
  • Чтобы выполнить ручное отражение, мне понадобится ITypeInfo дисп-интерфейса. Я мог бы получить это из ITypeInfo совместного класса. Однако pDispatch->GetTypeInfo(0, ...) возвращает ITypeInfo для реализации IDispatch (согласно документации), а не ITypeInfo для сокласса. (И нет никаких других ITypeInfo, выставленных реализацией IDispatch этого объекта.)

  • Моей первой мыслью было бы использовать QueryInteface с использованием DIID, а затем вызывать GetIDsofNames() для возвращенного dispInterface... 19.11.2014
  • Исходящие интерфейсы не реализуются исходным объектом. QueryInterface для любого исходящего интерфейса IID вернет E_NOINTERFACE. 19.11.2014
  • Что ж, тогда вас ждет много работы › ;) Пробовали ли вы вызывать ITypeInfo::GetContainingTypeLib(), чтобы получить библиотеку типов, а затем итерировать библиотеку типов, пока не найдете нужную информацию о типах, а затем получить ее идентификаторы? Это кажется грубой силой, но я думаю, что это сработает... 19.11.2014
  • Проблема в том, что предполагается, что dispinterface находится в библиотеке того же типа. Если это не так, то я думаю, что я SOL. 19.11.2014
  • Что ж, в реестре вы всегда можете посмотреть в ключе HKEY_CLASSES_ROOT\Interfaces, чтобы увидеть, есть ли запись для вашего интерфейса, а также есть ли для него ключ TypeLib. Вы пытаетесь сделать это динамически, или вам удобно предполагать, что интерфейс не изменится. Вы можете использовать инструмент Visual Studio OleView для проверки интерфейса. 19.11.2014
  • Он динамический, поэтому я не знаю интерфейсов заранее. Я, вероятно, могу (и должен) использовать реестр в случае, когда интерфейс не определен в той же библиотеке типов, поскольку я считаю, что так работает большинство реализаций ITypeLib. 19.11.2014
  • Если вам повезет, объект реализует IProvideClassInfo::GetClassInfo. В противном случае существуют эвристики, которые могут работать, а могут и не работать. ITypeInfo::GetContainingTypeLib уже упоминалось. Или, если вы знаете CLSID, вы можете попробовать найти соответствующий LIBID в реестре и загрузить его с LoadRegTypeLib. Объект может реализовывать IPersist, предоставляя вам его CLSID. 20.11.2014

Ответы:


1

Если объект "вполне стандартный", то это должно быть возможно.

Из интерфейса object/IDispatch вы сможете получить доступ к TLB (библиотеке типов). В библиотеке типов вы должны иметь возможность просматривать все составные классы и получать интерфейсы, реализуемые этими составными классами. Вам нужно перейти к интерфейсу, для которого у вас есть IID, просмотреть члена и получить интересующий вас.

Есть много случаев, когда это просто не сработает. Вот созданный мной пример консоли, который работает с объектом оболочки. Я написал это на C#, потому что это проще, но нет ничего, что вы не могли бы сделать с приличным языком. Я использовал старую служебную библиотеку TLBINF32.DLL com (к сожалению, только x86), о которой я говорю в своем ответе на этот вопрос здесь, на SO: Как читать COM TypeLib с C# или C++?

    static void Main(string[] args)
    {
        // create a sample object every one has
        object o = Activator.CreateInstance(Type.GetTypeFromProgID("shell.application")); // for example
        TLIApplication app = new TLIApplication();

        // not sure, but I believe in pure COM it's calling IDispatch::GetTypeInfo & ITypeInfo::GetContainingTypeLib 
        TypeLibInfo tli = app.InterfaceInfoFromObject(o).Parent;

        // this is the guid for DShellFolderViewEvents
        int dispid = GetDispId(tli, new Guid("{62112AA2-EBE4-11CF-A5FB-0020AFE7292D}"), "SelectionChanged");
        Console.WriteLine("dispid:" + dispid); // should display 200
    }

    public static int GetDispId(TypeLibInfo tlb, Guid diid, string memberName)
    {
        // browse all coclasses
        // in pure COM this is ITypeLib::GetTypeInfo
        foreach (CoClassInfo ti in tlb.CoClasses)
        {
            // browse all interfaces in those coclasses
            // in pure COM this is ITypeInfo::GetRefTypeOfImplType 
            foreach (InterfaceInfo itf in ti.Interfaces)
            {
                // only select [source] interfaces (events)
                // this test is optional since the diid is unique
                // in pure COM this is ITypeInfo::GetImplTypeFlags
                if (((ImplTypeFlags)itf.AttributeMask & ImplTypeFlags.IMPLTYPEFLAG_FSOURCE) != ImplTypeFlags.IMPLTYPEFLAG_FSOURCE)
                    continue;

                if (new Guid(itf.GUID) == diid)
                {
                    // in pure COM this is ITypeInfo::GetTypeAttr & ITypeInfo::GetFuncDesc
                    foreach (MemberInfo mi in itf.Members)
                    {
                        if (mi.Name == memberName)
                            return mi.MemberId;
                    }
                }
            }
        }
        return -1;
    }
20.11.2014
Новые материалы

Решения DBA Metrix
DBA Metrix Solutions предоставляет удаленного администратора базы данных (DBA), который несет ответственность за внедрение, обслуживание, настройку, восстановление базы данных, а также другие..

Начало работы с Блум
Обзор и Codelab для генерации текста с помощью Bloom Оглавление Что такое Блум? Некоторые предостережения Настройка среды Скачивание предварительно обученного токенизатора и модели..

Создание кнопочного меню с использованием HTML, CSS и JavaScript
Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

Внедрите OAuth в свои веб-приложения для повышения безопасности
OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

Классы в JavaScript
class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

Как свинг-трейдеры могут использовать ИИ для больших выигрышей
По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

Как построить любой стол
Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...