run-time подписка на события набора COM - объектов
От: PeterPan Россия  
Дата: 05.08.10 04:28
Оценка:
Задача следущая.
Необходимо в .Net создать обертку для набора COM-объектов, точнее некоторых их свойств, методов, событий.
Делаю так:
Я инстанцирую объект по ProgID(конфигурируемый)
Type tp = Type.GetTypeFromProgID(progID);
object COMObject = Activator.CreateInstance(tp);


Далее я могу обернуть методы
COMObject.GetType().InvokeMember(
    methodName, BindingFlags.InvokeMethod, null, COMObject, params)


также обернуть свойства

COMObject.GetType().InvokeMember(
         propertyName, BindingFlags.SetProperty, null, COMObject, params);

COMObject.GetType().InvokeMember(
         propertyName, BindingFlags.GetProperty, null, COMObject, params);


А вот с событиями кажется проблема.
Если бы COM-Объект был один и тот-же, а не набор, то, как описывается здесь, через oleview я бы подсмотрел GUID интерфеса событий,
объявил бы в design-time свой интерфес приемника (IMySinkEvents),реализовал IMySinkEvents в классе-приемнике событий и связал бы COM-объект с моим приемником событий как то так:

IConnectionPointContainer icpc = (IConnectionPointContainer)COMObject;
IConnectionPoint connectionPoint;
int cookie = 0;
Guid g = typeof(IMySinkEvents).GUID;
icpc.FindConnectionPoint(ref g, out connectionPoint);
connectionPoint.Advise(MySinkEventsInstance, out cookie);


В моем случае GUID у COM-объектов разные и видимо приходится искать способ как в run-time "исследовать" COM-объект, чтобы найти по списку названий событий GUID интерфейса, в котором определены эти события.
Также в run-time объявить интерфейс приемника событий, реализовать его в своем классе-приемникеи как и в первом случае связать его с COM-объектом.

Как динамически объявлять типы и создавать объекты я представляю, а вот как "исследовать" COM-объект в run-time идей пока нет
и google молчит (м.б. не так спросил).

Интересуюсь, я на правильном пути? Если, да то как добраться до GUID и описания интрерфейса событий у COM -объекта
Re: run-time подписка на события набора COM - объектов
От: Jolly Roger  
Дата: 05.08.10 14:38
Оценка: 2 (1)
Здравствуйте, PeterPan, Вы писали:

PP>Как динамически объявлять типы и создавать объекты я представляю, а вот как "исследовать" COM-объект в run-time идей пока нет


Такого рода информацию получают из библиотеки типов COM-объекта — при её наличии, разумеется. Начинать от ITypeLib(2) к ITypeInfo. Чего-то готового для этого в BCL я не видел.
"Нормальные герои всегда идут в обход!"
Re[2]: run-time подписка на события набора COM - объектов
От: PeterPan Россия  
Дата: 05.08.10 15:31
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Здравствуйте, PeterPan, Вы писали:


PP>>Как динамически объявлять типы и создавать объекты я представляю, а вот как "исследовать" COM-объект в run-time идей пока нет


JR>Такого рода информацию получают из библиотеки типов COM-объекта — при её наличии, разумеется. Начинать от ITypeLib(2) к ITypeInfo. Чего-то готового для этого в BCL я не видел.


Кажется это те самые ключевые слова для гугла, которые я искал. Буду изучать, спасибо
Re: run-time подписка на события набора COM - объектов
От: TK Лес кывт.рф
Дата: 05.08.10 15:42
Оценка: +1
Здравствуйте, PeterPan, Вы писали:

PP>Также в run-time объявить интерфейс приемника событий, реализовать его в своем классе-приемникеи как и в первом случае связать его с COM-объектом.


Многие COM объекты предоставляют события через наследника IDispatch — часто можно подписать именно его.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: run-time подписка на события набора COM - объектов
От: Jolly Roger  
Дата: 05.08.10 16:52
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR> Чего-то готового для этого в BCL я не видел.


Впрочем, кое-что кажется есть. Например, класс TypeLibConverter в System.Runtime.InteropServices может оказаться полезным. Так-же в System.Windows.Forms.Design есть класс.AxImporter, посмотрите.
"Нормальные герои всегда идут в обход!"
Re: run-time подписка на события набора COM - объектов
От: Vi2 Удмуртия http://www.adem.ru
Дата: 05.08.10 19:06
Оценка:
Здравствуйте, PeterPan, Вы писали:

PP>Как динамически объявлять типы и создавать объекты я представляю, а вот как "исследовать" COM-объект в run-time идей пока нет

PP>и google молчит (м.б. не так спросил).

PP>Интересуюсь, я на правильном пути? Если, да то как добраться до GUID и описания интрерфейса событий у COM -объекта


Есть такие интерфейсы IProvideClassInfo и IProvideClassInfo2 (как и слова для поиска). Если они у объекта есть, то задача получения интересующих тебя сведений упрощается.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re: run-time подписка на события набора COM - объектов
От: PeterPan Россия  
Дата: 09.08.10 15:19
Оценка:
Продолжение...
Иду я вот таким путем:

Объявил я IProvideClassInfo2 интерфейс

    [Guid("B196B283-BAB4-101A-B69C-00AA00341D07"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IProvideClassInfo
    {

    }

    [GuidAttribute("A6BC3AC0-DBAA-11CE-9DE3-00AA004BB851"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IProvideClassInfo2 : IProvideClassInfo
    {
       Guid GetGUID();
    }


пытаюсь получить получить GUID интерфейса событий.

    (COMObject as IProvideClassInfo2).GetGUID();


Но, переодически, получаю разные GUID, не имеющие ничего общего с GUID интерфейса, подсмотренного через oleview.
Что не так? или так и должно быть?
Re[2]: run-time подписка на события набора COM - объектов
От: PeterPan Россия  
Дата: 10.08.10 13:54
Оценка:
Продвинулся я вроде бы, итак

объявляем IDispatch

    [Guid("00020400-0000-0000-c000-000000000046"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IDispatch
    {
        int GetTypeInfoCount();

        ITypeInfo GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo,
            [MarshalAs(UnmanagedType.U4)] int lcid);

        [PreserveSig]
        int GetIDsOfNames(ref Guid riid,
            [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] 
                string[] rgsNames, int cNames, int lcid,
            [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);

        [PreserveSig]
        int Invoke(int dispIdMember, ref Guid riid,
            [MarshalAs(UnmanagedType.U4)] int lcid,
            [MarshalAs(UnmanagedType.U4)] int dwFlags,
            ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams,
            [Out, MarshalAs(UnmanagedType.LPArray)] object[] pVarResult,
            ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo,
            [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr);
    }


получаем ITypeInfo и ITypeLib для COM-объекта

      Type tp = Type.GetTypeFromProgID(progID);
      object comObject = Activator.CreateInstance(tp);
      IDispatch dispatch = comObject as IDispatch;
      System.Runtime.InteropServices.ComTypes.ITypeInfo ppTINF = null;
      System.Runtime.InteropServices.ComTypes.ITypeLib ppTLB= null;
      int pIndex = 0;
      if (dispatch != null)
      {
           ppTINF = dispatch.GetTypeInfo(0, 0);
           ppTINF.GetContainingTypeLib(out ppTLB, out pIndex);
      }
      else
      {
           throw new InvalidComObjectException();
      }


исследуем типы из библиотеки объектов


     List<System.Runtime.InteropServices.ComTypes.TYPEATTR> list =
         new List<System.Runtime.InteropServices.ComTypes.TYPEATTR>();
     int i = 0;
     System.Runtime.InteropServices.ComTypes.ITypeInfo item = null;
     while (i < typeLib.GetTypeInfoCount())
     {
          typeLib.GetTypeInfo(i++, out item);
          IntPtr pTypeAttr;
          item.GetTypeAttr(out pTypeAttr);

          list.Add(
             (System.Runtime.InteropServices.ComTypes.TYPEATTR) Marshal.PtrToStructure(pTypeAttr,
              typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR)));
     }

     return list.ToArray();


структура System.Runtime.InteropServices.ComTypes.TYPEATTR содержит информацию о типе, в т.ч. guid.

Остается объявить в run-time интерфейс событий и реализовать в классе приемнике событий.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.