Дамп объекта для ComObject с использованием динамического? - PullRequest
2 голосов
/ 15 января 2012

Я пытаюсь (без удачи) реализовать «Дампер объектов» для объектов, к которым я обращаюсь в библиотеке типов Office.

Возможно, это так, потому что окно отладки VS имеет «динамическое представление»."для системы .__ ComObject объекты, которые эффективно делают то, что я хочу.

Есть идеи?

1 Ответ

3 голосов
/ 04 июня 2012

Я также создал метод для получения интерфейса, который можно использовать для доступа к объекту. Использование:

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

В вашем коде должен быть интерфейс IDispatch:

[Guid("00020400-0000-0000-C000-000000000046"), ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IDispatch 
{ 
    [PreserveSig] 
    int GetTypeInfoCount(out int pctinfo); 

    [PreserveSig] 
    int GetTypeInfo( 
        [MarshalAs(UnmanagedType.U4)] int iTInfo, 
        [MarshalAs(UnmanagedType.U4)] int lcid, 
        out System.Runtime.InteropServices.ComTypes.ITypeInfo ppTInfo); 

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

    [PreserveSig] 
    int Invoke( 
        int dispIdMember, 
        ref Guid riid, 
        uint lcid, 
        ushort wFlags, 
        ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, 
        out object pVarResult, 
        ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, 
        IntPtr[] puArgErr); 
}

Мой метод преобразует COM-объект в IDispatch, получает информацию о неуправляемом типе, получает GUID типа объекта из закрытого метода Marshal GetTypeInfoGuid и затем ищет его в текущих сборках AppDomain.

internal static Func<ITypeInfo,Guid> GetTypeInfoGuid = (Func<ITypeInfo,Guid>)Delegate.CreateDelegate(typeof(Func<ITypeInfo,Guid>), typeof(Marshal).GetMethod("GetTypeInfoGuid", BindingFlags.NonPublic | BindingFlags.Static, null, new[]{typeof(ITypeInfo)}, null), true);
public static Type GetCOMObjectType(object comobject)
{
    if(!Marshal.IsComObject(comobject))
    {
        throw new ArgumentException("This is not COM object.", "comobject");
    }
    IDispatch dispatch = (IDispatch)comobject;
    ITypeInfo info;
    dispatch.GetTypeInfo(0,0, out info);
    Guid guid = GetTypeInfoGuid(info);
    foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies())
    {
        foreach(Type t in a.GetTypes())
        {
            if(t.IsInterface && t.IsImport && t.GUID == guid)
            {
                return t;
            }
        }
    }
    return Type.GetTypeFromCLSID(guid);
}

Если соответствующий тип не найден, метод вернет тип System .__ ComObject. Однако вы можете получить значение свойства GUID из него, так что, по крайней мере, вы получите GUID. Использование:

object controls = axWindowsMediaPlayer1.cdromCollection;
Type t = GetCOMObjectType(controls);
Console.WriteLine(t);
Console.WriteLine(t.GUID);
/*Output:
  WMPLib.IWMPCdromCollection
  ee4c8fe2-34b2-11d3-a3bf-006097c9b344 */

Надеюсь, это поможет. Удачи. ☺

Edit: Найден более простой, но более медленный метод:

object controls = axWindowsMediaPlayer1.cdromCollection;
IDispatch dispatch = (IDispatch)controls;
ITypeInfo info;
dispatch.GetTypeInfo(0,0, out info);
Type t = Marshal.GetTypeForITypeInfo(Marshal.GetIUnknownForObject(info));
Console.WriteLine(t);
...