エクスポート時のメンバの変換

このトピックでは、次のメンバがエクスポート プロセスでどのように変換されるかを説明します。

  • メソッド

  • プロパティ

  • イベント

メソッド

COM のクライアントは、パラメータなどの使い慣れた COM のデータ型を渡し、HRESULT を戻り値として受け取るメソッドを呼び出そうとします。しかし、.NET の世界では、クラスは戻り値の型に対してこのような規定はありません。実際、HRESULT は使用されません。

COM と .NET の両方のモデルを満足させるには、マネージ型のすべてのメソッドに、.NET シグネチャと暗黙の COM シグネチャを含めます。通常、この 2 つのシグネチャは大きく異なります。.NET クライアントは、.NET シグネチャを使用してサーバーとやりとりします。一方、COM クライアントは、COM シグネチャを使用してサーバーとやりとりします。これらのやりとりは、同時に起こることもあります。サーバーは、.NET シグネチャを持つメソッドを実装し、ランタイム マーシャリング サービスが、マネージ メソッドに呼び出しをデリゲートする COM シグネチャを持つスタブの提供を担当します。

HRESULT の変換

マネージ戻り値を [out, retval] パラメータに変更し、アンマネージ戻り値の型を HRESULT に変更することにより、マネージ シグネチャがアンマネージ シグネチャに変換されます。たとえば、DoSomething メソッドが、次のシグネチャを持っているとします。

マネージ シグネチャ

short DoSomething(short i);

アンマネージ シグネチャ

HRESULT DoSomething([in] short i, [out, retval] short *rv);

COM シグネチャが HRESULT を返し、戻り値として追加の out パラメータを持つことに注意してください。マネージ実装からの戻り値は、常に [out, retval] パラメータとして返され、アンマネージ シグネチャの末尾に追加されます。一方、アンマネージ シグネチャは常に HRESULT を返します。マネージ メソッドの戻り値の型が void の場合、ランタイムは、[out, retval] パラメータを省略します。次に例を示します。

マネージ シグネチャ

void DoSomething(short i);

アンマネージ シグネチャ

HRESULT DoSomething([in] short i);

一定の条件下では、マネージ シグネチャをそのまま変更しない方がいい場合もあります。マネージ シグネチャを変更しない場合は、PreserveSigAttribute を使用します。次に例を示します。

マネージ シグネチャ

[PreserveSig] short DoSomething(short i);

アンマネージ シグネチャ

short DoSomething ([in] short i);

2 つの異なるメソッド シグネチャを持つことにより、COM と .NET クライアントの両方からシームレスにクラスを使用できます。さらに、COM クライアントと .NET クライアントの両方が、同時に .NET クラスを使用できます。クラスの作成者は、マネージ シグネチャだけを実装します。Tlbexp.exe (または同等の API) を使用すると、そのクラスに対して生成されるタイプ ライブラリに、シグネチャが自動的にエクスポートされます。

オーバーロードされたメソッド

.NET はオーバーロードされたメソッドをサポートしていますが、IDispatch インターフェイスは、バインディングのために、完全メソッド シグネチャではなく、メソッド名だけを使用します。したがって、オーバーロードされたメソッドをサポートできません。ただし、ある型のオーバーロードされたメソッドへのアクセスを提供するために、Tlbexp.exe は、オーバーロードされたメソッドの名前を序数で修飾して、各メソッド名が一意になるようにします。

序数による修飾の例を次のマネージ シグネチャとアンマネージ シグネチャで示します。

マネージ シグネチャ

interface INew {
public:
    void DoSomething();
    void DoSomething(short s);
    void DoSomething(short l);
    void DoSomething(float f);
    void DoSomething(double d);
}

アンマネージ シグネチャ

interface INew {
    void DoSomething();
    void DoSomething_2(short s);
    void DoSomething_3(short l);
    void DoSomething_4(float f);
    void DoSomething_5(double d);
}

これらのメソッドの COM シグネチャは、後に一連の修飾された DoSomething_x メソッドが続く 1 つの DoSomething メソッドとして表現されています。x は、2 から始まり、メソッドのオーバーロードされた形態ごとに値が増加しています。オーバーロードされたメソッドの中には、基本型から継承できるものもあることに注意してください。オーバーロードされたメソッドが、増加していく型バージョンと同じ番号を保持する保証はありません。

.NET クライアントは、メソッドのオーバーロードされた形式を使用できますが、COM クライアントは、修飾されたメソッドにアクセスする必要があります。オブジェクト ブラウザは、正しいメソッドを選択できるようにするために、修飾されたメソッドのすべての形式とメソッド シグネチャを表示します。実行時にバインディングされるクライアントも、修飾された名前を渡して IDispatch::GetIdsOfNames を呼び出し、オーバーロードされたメソッドの DispID を取得できます。

プロパティ

マネージ クラスおよびマネージ インターフェイスは、プロパティを持つことができます。マネージ プロパティは、get メソッドおよび set メソッドを関連付けることができる特別のデータ型です。これらのメソッドは、他のメソッドと同様に、個別に定義します。Height プロパティを持つインターフェイスのコード例を次に示します。プロパティを持つインターフェイスを実装するクラスは、プロパティの get メソッドおよび set メソッドを提供する必要があります。

    interface IMammal {
 
    IMammal Mother{get;set;}
    IMammal Father{get;set;}
    int     Height{get;set;}
    int     Weight{get;set;}

    }

    class Human : IMammal
    {
        int weight;
        int height;
        IMammal father;
        IMammal mother;

        public IMammal Mother { get { return mother; } set { mother = value; } }
        public IMammal Father { get { return father; } set { father = value; } }
        public int Height { get { return height; } set { height = value; } }
        public int Weight { get { return weight; } set { weight = value; } }
    }

エクスポート時に、Tlbexp.exe はプロパティ set メソッドを [propput] に変換し、get メソッドを [propget] に変換します。COM でのプロパティ名は、マネージ プロパティ名と同じ名前を維持します。この規則には、次の例外があります。

  • プロパティ型 (値型を除く) がクラスまたはインターフェイスの場合は、プロパティ set メソッドは、[propputref] になり、パラメータに追加の間接レベルが与えられます。

  • プロパティに get メソッドまたは set メソッドが関連付けられていない場合は、Tlbexp.exe はタイプ ライブラリからのプロパティを省略します。

プロパティと同様に、マネージ フィールドも、タイプ ライブラリにエクスポートされます。ランタイム マーシャリング サービスは、すべてのパブリック フィールドに対して get メソッドと set メソッドを自動的に生成します。変換プロセス中、Tlbexp.exe が、フィールドごとに [propput] (または [propputref]) 関数と [propget] 関数を生成するタイプ ライブラリ表現を次に示します。

タイプ ライブラリ表現

interface IMammal : IDispatch {
         [propget]    HRESULT Mother([out, retval] IMammal** pRetVal);
         [propputref] HRESULT Mother([in] IMammal* pRetVal);
         [propget]    HRESULT Father([out, retval] IMammal** pRetVal);
         [propputref] HRESULT Father([in] IMammal* pRetVal);
         [propget]    HRESULT Height([out, retval] long* pRetVal);
         [propput]    HRESULT Height([in] long pRetVal);
         [propget]    HRESULT Weight([out, retval] long* pRetVal);
         [propput]    HRESULT Weight([in] long pRetVal);
         [propget]    HRESULT Age([out, retval] long* pRetVal);
         [propput]    HRESULT Age([in] long pRetVal);    
};

イベント

COM 相互運用機能のイベント モデルに詳しくない場合は、「マネージ イベントとアンマネージ イベント」を参照してください。マネージ型は、デリゲート ベースのイベント モデルを使用してイベントを実装します。たとえば、次のコード例の Class1Events インターフェイスは、Click イベントを発生させます。

    Public Delegate Sub ClickDelegate()
    <GuidAttribute("1A585C4D-3371-48dc-AF8A-AFFECC1B0967"), _
    InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)>

    Public Interface Class1Event
        Sub Click ()
    End Interface
<ComSourceInterfaces("Class1Event, EventSrc")> _
    Public Class Class1
        Public Event Click As ClickDelegate
   End Class
    public delegate void Click();

    public interface Class1Event
    {
        void Click();
    }
   [ComSourceInterfaces("Class1Event, EventSrc")]
    public class Class1
    {
        public event ClickDelegate Click;
    }

エクスポート時に、Tlbexp.exe はコクラス内でイベント インターフェイスをソースとしてマークします。エクスポートされた ComClass1Events インターフェイスがソース インターフェイスとしてマークされているタイプ ライブラリ表現を次に示します。

タイプ ライブラリ表現

    disinterface Class1Event {
        properties:
        methods:
        [id(0x60020000)]
        HRESULT Click();
    };

    coclass Class1
    {
    …
    [default, source] Class1Event;
    };

参照

概念

エクスポート時のアセンブリの変換
エクスポート時のモジュールの変換
エクスポート時の型の変換
エクスポート時のパラメータの変換

その他の技術情報

アセンブリからタイプ ライブラリへの変換の要約