インポート時の型の変換

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

  • インターフェイス

  • クラス

  • 構造体

  • 列挙体

  • 定数

  • Typedef

通常、Tlbimp.exe は、元のタイプ ライブラリ内での名前と同じ名前を付けて型をインポートします。タイプ ライブラリ内の名前は一意である必要があります。これにより、変換プロセス中の競合を防止できます。有効なタイプ ライブラリ名はすべて、有効なアセンブリ名になります。

インポートされた型は、その型が属する名前空間によってスコープ設定されます。名前空間の名前は、元のタイプ ライブラリと同じ名前です。型は、それぞれの型の完全な名前空間と型名によって個別に識別されます。

タイプ ライブラリ内でタイプ ライブラリ属性を使用することにより、インポートする型のマネージ名を明示的に制御できます。このユーザー定義の属性の ID は、0F21F359-AB84-41e8-9A78-36D110E6D2F9 です。ユーザー定義の属性が追加されたタイプ ライブラリを次に示します。

タイプ ライブラリ表現

[  uuid(…),
    version(1.0)
]
library AcmeLib {
    interface Widget {};
    [custom(0F21F359-AB84-41e8-9A78-36D110E6D2F9, 
     "Acme.WidgetLib.Slingshot")]
    coclass Slingshot {};
};

Tlbimp.exe は、タイプ ライブラリを AcmeLib 名前空間にインポートしますが、Slingshot クラスは Acme.WidgetLib.Slingshot に変換されます。

インターフェイス

インポート プロセスがインターフェイスを変換するときは、すべての IUnknown メソッドおよび IDispatch メソッドを除去します。インターフェイスがデュアル (IDispatch から派生するインターフェイス) でない場合、変換プロセスは、インターフェイスに GuidAttribute を適用して、タイプ ライブラリ内で割り当てられているインターフェイス ID (IID: Interface Identifier) と InterfaceTypeAttribute を保持します。

タイプ ライブラリ表現

[uuid(…), ]
interface IWidget : IUnknown {
    HRESULT New()
    HRESULT Start()
};
[uuid(…), ]
interface IGadget : IWidget {
    HRESULT Baz()
};

変換中にインポート プロセスは、基本インターフェイスのメソッドを派生インターフェイスに追加します。IGadget インターフェイスに New インターフェイスおよび Start インターフェイスを追加する例を次に示します。

<Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface IWidget
    Sub [New]()
    Sub Start()
End Interface

<Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface IGadget
    Inherits IWidget
    Shadows Sub [New]()
    Shadows Sub Start()
    Sub Baz()
End Interface
[Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IWidget {
    void New();
    void Start();
};
[Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IGadget : IWidget {
    new void New();
    new void Start();
    void Baz();
};

クラス

インポート プロセスは、各 COM コクラスを表現するマネージ クラスを作成し、そのマネージ クラスに、元のコクラスの名前に Class を追加した名前を付けます。たとえば、NewNewer コクラスは NewNewerClass となります。変換プロセスは、そのクラスに GuidAttribute を追加して、コクラスのクラス ID (CLSID) をキャプチャします。

マネージ クラスだけでなく、インポート プロセスはコクラスと同じ名前を持つインターフェイスを追加し、元のコクラスの CLSID を識別するための CoClassAttribute を適用します。このインターフェイスは、コクラスの既定のインターフェイスと同じ IID を持ちます。このインターフェイスを使用すると、クライアントは常にイベント シンクとして登録できます。

COM のコクラスとは異なり、マネージ クラスには、クラス メンバを含めることができます。.NET Framework のアプローチとの関係を維持しながら、変換プロセスは、コクラスによって実装された各インターフェイスに関連付けられているメンバを各クラスに追加します。マネージ クラスのユーザーは、マネージ型のメソッドとプロパティをあらかじめ特定のインターフェイスにキャストせずに、呼び出すことができます。また、インポート プロセスは、変換された各コクラスに既定のコンストラクタを追加します。コンストラクタは、マネージ コードからクラスを作成できるようにします。コンストラクタのないクラスは、作成できません。既定のコンストラクタには引数はありません。既定のコンストラクタの実装は、基本クラスのコンストラクタを呼び出します。コクラスに noncreatable タイプ ライブラリ属性が適用されている場合は、インポート プロセスは、そのクラスに対して既定のコンストラクタを作成しません。

インターフェイス メンバ名は、必ずしも一意ではないため、メンバ間で名前や DispId の衝突が発生する場合があります。TlbImp.exe は、クラスの衝突する各メンバ名の前に、インターフェイス名とアンダースコア (_) を付けて、名前の衝突を解決します。メンバ名が衝突するときは、コクラス ステートメントで先にリストされているインターフェイスの名前が変更されずに残ります。

DispId の衝突が発生した場合、インポート プロセスは、コクラスの既定インターフェイスのメンバに DispId を割り当て、衝突しているクラス メンバには何も割り当てません。ただし、インポート プロセスは、常に、インターフェイスのメンバに DispId を割り当てます。

タイプ ライブラリ表現

[uuid(…)]
interface INew : IDispatch {
    [id(0x100)] HRESULT DoFirst();
    [id(0x101)] HRESULT DoSecond();
}
[uuid(…)]
interface INewer : IDispatch {
    [id(0x100)] HRESULT DoNow();
    [id(0x101)] HRESULT DoSecond();
}
[uuid(…)]
coclass NewNewer  {
    [default] interface INew;
    interface INewer;
}

変換後の型は次のようになります。

<Guid(…)> Public Interface INew
    …
End Interface

<Guid(…)> Public Interface INewer
    …
End Interface

<Guid(…)> Public Interface NewNewer
Inherits INew
    …
End Interface

<Guid(…)> Public Class NewNewerClass
Implements INew   
Implements INewer
Implements NewNewer
' Method implementation
     <DispId(100)> _
      …
End Class  
[Guid(…)]
public interface INew {…}

[Guid(…)]
public interface INewer {…}

[Guid(…)]
public interface NewNewer : INew {…}

[Guid(…)]
public class NewNewer : INew, INewer, NewNewer{
// Method implementation.
     [DispId(100)]…
}

構造体

タイプ ライブラリ内に定義されている構造体は、メタデータとしてインポートされます。構造体のフィールドが参照型である場合、Tlbimp.exe はその型を IntPtr としてインポートし、ComConversionLossAttribute を適用します。この属性は、インポート プロセスで情報が失われたことを示します。

列挙体

タイプ ライブラリ インポータ (Tlbimp.exe) は、アンマネージ列挙体を Enum マネージ型としてインポートします。

定数

このリリースでは、タイプ ライブラリから、定数はインポートされません。

Typedef

タイプ ライブラリ内の型定義 (typedef) は、インポートされません。代わりに、パラメータとフィールドが元になる型としてインポートされます。たとえば、BUTTON_COLOR 型のパラメータは、BUTTON_COLOR が整数のエイリアスなので、整数型としてインポートされます。

インポートされた後、パラメータやフィールドは、それらのパラメータやフィールドを元の型と関連付ける情報を ComAliasNameAttribute で保持します。変換プロセスは、ComAliasNameAttribute を適用して、フィールド、パラメータ、または戻り値をタイプ ライブラリの名前とライブラリ内でエイリアスとして使用されていた型に関連付けます。

次のタイプ ライブラリ表現は、パラメータ cl が、整数のエイリアスである BUTTON_COLOR 型であることを示しています。

タイプ ライブラリ表現

library MyLib {
    typedef [public] int BUTTON_COLOR;

    interface ISee {
        HResult SetColor([in] BUTTON_COLOR cl);
        HResult GetColor([out, retval] BUTTON_COLOR *cl);
    };
   
    coclass See {
        [default] interface ISee
    };
};

変換後の型は次のようになります。

public interface ISee {
    void SetColor([ComAliasName("MyLib.BUTTON_COLOR")]] int cl);
    [return: ComAliasName("MyLib.BUTTON_COLOR")] int GetColor();
};

public class See {
    public void SetColor([ComAliasName("MyLib.BUTTON_COLOR")]] int cl);
    [return: ComAliasName("MyLib.BUTTON_COLOR")] int GetColor();
};

実際の型 BUTTON_COLOR 型は、結果のメタデータには定義されないことに注意してください。代わりに、タイプ ライブラリ内で BUTTON_COLOR 型であったパラメータが、元になる型として int 型になり、ComAliasNameAttribute 属性を与えられます。この変換プロセスは、クラス メソッドの引数にも属性を適用します。

参照

概念

インポート時のライブラリの変換
インポート時のモジュールの変換
インポート メンバの変換
インポート パラメータの変換

その他の技術情報

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