Help us understand the problem. What is going on with this article?

C#で実行時に得たCOMオブジェクトのインタフェース名を取得する

More than 1 year has passed since last update.

やれること

インスタンス化したComObject(※)が特定のインタフェース(IDispatch)を実装している場合に

  • インタフェース名 と そのGUID
  • TypeLibrary名

を取得します。

※簡単な判別方法: .GetType().ToString()"System.__ComObject"になるやつ

ソースコード

ソースコード
using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices;

// ↓これを消すと、System.Runtime.InteropServicesにある同名の古い定義をうっかり引き当ててしまうおそれがあるので残す
using System.Runtime.InteropServices.ComTypes;

using ComTypes = System.Runtime.InteropServices.ComTypes;


public static class ShowComInfo
{
    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-c000-000000000046")]
    private interface IDispatch
    {
        [PreserveSig]
        int GetTypeInfoCount(out int count);
        [PreserveSig]
        int GetTypeInfo([In] int itinfo, [In] int lcid, out IntPtr typeinfo);
        [PreserveSig]
        int GetIDsOfNames();//dummy. don't call this method
        [PreserveSig]
        int Invoke();//dummy. don't call this method
    }

    static Guid? GetGuidFromIType(ITypeInfo typ)
    {
        Guid? guid = null;
        IntPtr ptr;
        try {
            typ.GetTypeAttr(out ptr);
        }
        catch ( COMException ) { return null; }

        try {
            var attr = Marshal.PtrToStructure<ComTypes.TYPEATTR>(ptr);
            guid = attr.guid;
        }
        finally {
            typ.ReleaseTypeAttr(ptr);
        }

        return guid;
    }

    static void ShowNamesOfTypeInfo(ITypeInfo typ)
    {
        string strName;
        string strDocString;
        int dwHelpContext;
        string strHelpFile;

        typ.GetDocumentation(-1, out strName, out strDocString, out dwHelpContext, out strHelpFile);
        Console.Write("InterfaceName: ");
        Console.WriteLine(strName??"<<NULL>>");
        Console.Write("InterfaceDocString: ");
        Console.WriteLine(strDocString??"<<NULL>>");
        Console.Write("InterfaceHelpFile: ");
        Console.WriteLine(strHelpFile??"<<NULL>>");
    }

    static void ShowNamesOfTypeLib(ITypeLib typ)
    {
        string strName;
        string strDocString;
        int dwHelpContext;
        string strHelpFile;

        typ.GetDocumentation(-1, out strName, out strDocString, out dwHelpContext, out strHelpFile);
        Console.Write("TypeLibName: ");
        Console.WriteLine(strName??"<<NULL>>");
        Console.Write("TypeLibDocString: ");
        Console.WriteLine(strDocString??"<<NULL>>");
        Console.Write("TypeLibHelpFile: ");
        Console.WriteLine(strHelpFile??"<<NULL>>");
    }

    public static void ShowInterfaceIdFromComObject(object obj)
    {
        Guid? guid = null;
        ComTypes.ITypeInfo typeInfo = null;
        IntPtr ptr = IntPtr.Zero;

        try {
            if ( obj is IDispatch ) {
                var idisp = (IDispatch)obj;
                int count;
                int hResult = idisp.GetTypeInfoCount(out count);
                if ( hResult >= 0 ) { // Succeeded
                    if ( count < 1 ) { // no type info
                        return;
                    }

                    idisp.GetTypeInfo(0, 0, out ptr);
                    if ( ptr == IntPtr.Zero ) {
                        return;
                    }

                    typeInfo = (ComTypes.ITypeInfo)
                       (Marshal.GetTypedObjectForIUnknown(ptr, typeof(ComTypes.ITypeInfo)));

                    if ( typeInfo == null ) {
                        return;
                    }
                    ShowNamesOfTypeInfo(typeInfo);
                    guid = GetGuidFromIType(typeInfo);
                    Console.Write("InterfaceGUID: ");
                    Console.WriteLine(guid);

                    ITypeLib typLib;
                    int indexOfLib;
                    typeInfo.GetContainingTypeLib(out typLib, out indexOfLib);
                    ShowNamesOfTypeLib(typLib);
                }
            }
            else { // unknown type
                return;
            }
        }
        finally {
            if ( ptr != IntPtr.Zero ) {
                Marshal.Release(ptr);
                ptr = IntPtr.Zero;
            }
        }
    }
}

class Test
{
    [STAThread]
    static void Main(string[] args)
    {
        Type comType = Type.GetTypeFromProgID("Shell.Application");
        dynamic o = Activator.CreateInstance(comType);

        try {
            ShowComInfo.ShowInterfaceIdFromComObject(o);
        }
        finally {
            Marshal.ReleaseComObject(o);
        }
    }
}

実行結果

InterfaceName: IShellDispatch6
InterfaceDocString: Updated IShellDispatch
InterfaceHelpFile: <<NULL>>
InterfaceGUID: 34936ba1-67ad-4c41-99b8-8c12dff1e974
TypeLibName: Shell32
TypeLibDocString: Microsoft Shell Controls And Automation
TypeLibHelpFile: <<NULL>>

ちなみにCOMオブジェクトのインタフェースは、レジストリの HKEY_CLASSES_ROOT\Interface にいます。
OleView.exeでTypeLibraryを探すと情報がみれる。

参考サイト

OleView.exeの使い方

OleView.exeでインタフェースのメソッド、プロパティを調べる方法。
※そのPCにインストールされているものしか出ません。例:ExcelがインストールされていないPCでExcelのCOM Objectは多分でてこない。

■Step0. 入手する ・・・ oleview.exe microsoft あたりのキーワードでググるべし。
■Step1. 起動する ・・・ C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin らへんにいるはず。。環境依存。
image.png
■Step2. タイプライブラリ名を探す
「Type Libraries」から、TypeLib名を探す(例:Microsoft Shell Controls And Automation)
■Step3. タイプライブラリ名をダブルクリックする
・・・別ウィンドウが立ち上がります。
■Step4. インタフェース名を探す。
・・・dispinterface インタフェース名

その後

C#でITypeInfoクラスを使い倒してCOMオブジェクトの関数名とパラメータを表示させる

kob58im
趣味でC#で色々試してます。 置いてるほとんどのC#サンプルコードは、Windows7以降デフォで入ってる環境でコンパイルできます。 最近はCodePen使ってJavaScriptも書いてます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away