4

注:背景情報については、次の関連する質問を参照してください: LINQPad を Dump() System.__ComObject 参照に取得するには?

を使用して、COM オブジェクトに対応する RCW クラスの CLSID を取得できます (別の COM オブジェクトから取得され、コードによって初期化されていませんIPersist.GetClassID()) 。

Type.GetTypeFromCLSID()厳密に型指定された RCW クラスではなくSystem.__ComObject、常に弱く型指定された を返します。

System.Typeを使用して COM オブジェクトをラップできるようにするには、厳密に型指定された RCW クラスのを取得する必要がありますMarshal.CreateWrapperOfType()

これは可能ですか、それとも COM 相互運用がどのように機能するかにより、これは開始できませんか?

4

2 に答える 2

2

これが、概念実証としてまとめたものです。実際には、ほんの一握りの拡張メソッドです。IPersistこれは、現在にロードされているPIAの1つにRCWクラスを実装して持つCOMオブジェクトに依存していますAppDomain

internal static class ExtensionMethods
{
    internal static object ConvertToRCW(this object o)
    {
        var guid = o.GetCLSID();
        if (guid != Guid.Empty)
        {
            return Marshal.CreateWrapperOfType(o, o.GetTypeFromGuid(guid));
        }
        else
        {
            return o;
        }
    }

    internal static Guid GetCLSID(this object o)
    {
        Guid guid = Guid.Empty;
        var p = o as IPersist;
        if (p != null)
            p.GetClassID(out guid);
        return guid;
    }

    internal static Type GetTypeFromGuid(this object o, Guid guid)
    {
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        foreach (var assembly in assemblies)
        {
            var types = assembly.GetLoadableTypes();
            foreach (var type in types)
            {
                if (type.GUID == guid)
                    return type;
            }
        }
        return o.GetType();
    }

    internal static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
    {
        try
        {
            return assembly.GetTypes();
        }
        catch (ReflectionTypeLoadException e)
        {
            return e.Types.Where(t => t != null);
        }
    }
}

このように使用されます:

var point = new ESRI.ArcGIS.Geometry.Point();
point.PutCoords(1, 1);
Console.WriteLine(point.GetType().FullName);
Console.WriteLine(point.Envelope.GetType().FullName);
Console.WriteLine(point.Envelope.ConvertToRCW().GetType().FullName);

次の出力が得られます。

ESRI.ArcGIS.Geometry.PointClass
System .__ ComObject
ESRI.ArcGIS.Geometry.EnvelopeClass

これは望ましい結果でした。ここで、これをLINQPad(私の元の質問)でうまく機能させるために。

于 2013-02-08T03:32:23.577 に答える
1

Type.GetTypeFromCLSID()動的な COM ラッパーを返すだけです。

厳密に型指定された RCW は、.NET 空間で定義する必要があります。ComImportAttributeで装飾されたクラスである必要があります。.NET は、これらのクラスを自動的に作成することはできません。これらは手動で (.NET コードで)、または PIA、tlbimp、またはすべての .NET 型と同様に、たとえば Reflection Emit メカニズムによって定義されます。同じ CLSID に対応する複数の .NET クラスが存在する可能性があるため、COM CLSID と .NET に対応するクラスの間に事前設定された関係はありません。

これらのタイプが利用可能である場合、たとえば、定義された名前空間のセットをスキャンして、Dictionary<Guid, Type>そこから を構築できます。

于 2013-02-07T20:44:08.783 に答える