[C#] COM Object から TypeInfoName を取得する

2022-08-03 (水)

System.__ComObject のインスタンスから COM インターフェイスの型名を取得する方法です。

環境

  • .NET 6.0.302
  • C# 10.0
  • Visual Studio 2022 Version 17.2.6
  • Windows 10 Pro 64bit 21H1 19043.1826

使用例

var type = Type.GetTypeFromProgID("Shell.Application");
var comObject = Activator.CreateInstance(type);
var name = MarshalUtil.GetTypeInfoName(comObject);

Console.WriteLine(name); // IShellDispatch6

実装方法

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

public static class MarshalUtil
{
    public static string? GetTypeInfoName(object comObject)
    {
        if (comObject is not IDispatch dispatch)
            return null;

        var typeInfo = dispatch.GetTypeInfo(0, 0);
        return Marshal.GetTypeInfoName(typeInfo);
    }

    [ComImport]
    [Guid("00020400-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IDispatch
    {
        int GetTypeInfoCount();
        ITypeInfo GetTypeInfo(int iTInfo, int lcid);
    }
}

以下のように ITypeInfo.GetDocumentation() を使用すると、名前以外も取得できます。
Marshal.GetTypeInfoName() でも同じく ITypeInfo.GetDocumentation() を実行しています(ソース)。

var typeInfo = dispatch.GetTypeInfo(0, 0);
typeInfo.GetDocumentation(-1, out var name, out var doc, out var helpContext, out var helpFile);

Console.WriteLine(name);        // IShellDispatch6
Console.WriteLine(doc);         // Updated IShellDispatch
Console.WriteLine(helpContext); // 0
Console.WriteLine(helpFile);    // null

その他の方法

1. Microsoft.VisualBasic.Information.TypeName()

Information.TypeName(Object) メソッド (Microsoft.VisualBasic) | Microsoft Docs

var name = Microsoft.VisualBasic.Information.TypeName(comObject);

ソースとしては以下の順に実行されるようです。同じく ITypeInfo.GetDocumentation() が実行されます。

  1. Microsoft.VisualBasic.Information.TypeName()
  2. Microsoft.VisualBasic.Information.LegacyTypeNameOfCOMObject()

2. IDispatch を定義せずに Marshal で頑張って取得する (.NET Framework 限定)

IntPtr を使用すれば、IDispatch の定義なしで取得できるようです。
ただし、 Marshal.GetITypeInfoForType() が .NET Core で使用できません。

Marshal.GetITypeInfoForType(Type) メソッド (System.Runtime.InteropServices) | Microsoft Docs

var dispatchPtr = Marshal.GetIDispatchForObject(comObject);
var typeInfoPtr = Marshal.GetITypeInfoForType(dispatchPtr.GetType());
var typeInfo = (ITypeInfo)Marshal.GetTypedObjectForIUnknown(typeInfoPtr, typeof(ITypeInfo));
var name = Marshal.GetTypeInfoName(typeInfo);

感謝

2022-08-03 (水)