COM および .NET の C++ の属性
Microsoft では、COM プログラミングと .NET Framework 共通言語ランタイム開発を簡素化する C++ 属性のセットを定義しています。 ソース ファイルに属性を含める場合、コンパイラはプロバイダー DLL と連携して、生成されたオブジェクト ファイルにコードを挿入したり、コードを変更したりします。 これらの属性は、.idl ファイル、インターフェイス、タイプ ライブラリ、その他の COM 要素を作成する場合に便利です。 統合開発環境 (IDE) では、属性はウィザードとプロパティ ウィンドウによってサポートされています。
属性を使用すると、COM オブジェクトを記述するために必要な詳細なコーディングの一部が不要になりますが、属性を最大限に活用するには COM の基礎に関する背景知識が必要です。
Note
C++ 標準属性を探している場合は、属性に関する記事を参照 してください。
属性の目的
属性は、言語の従来の構造を壊すことなく、現在は不可能な方向に C++ を拡張します。 属性を使用すると、プロバイダー (個別の DLL) が言語機能を動的に拡張できます。 属性の主な目的は、コンポーネント開発者の生産性レベルの向上に加えて、COM コンポーネントのオーサリングを簡素化することです。 属性は、クラス、データ メンバー、またはメンバー関数など、ほぼすべての C++ コンストラクトに適用できます。 この新しいテクノロジによって提供されるメリットの主要な部分を次に示します。
使い慣れた単純な呼び出し規則を公開します。
挿入されたコードを使用します。マクロとは異なり、デバッガーによって認識されます。
詳細な実装の面倒がかかることなく、基底クラスから簡単に派生できます。
COM コンポーネントに必要な大量の IDL コードを、いくつかの簡潔な属性に置き換えます。
たとえば、汎用 ATL クラスの単純なイベント シンクを実装するには、event_receiver 属性を CMyReceiver
などの特定のクラスに適用します。 その後、event_receiver
属性は Microsoft C++ コンパイラによってコンパイルされ、オブジェクト ファイルに適切なコードが挿入されます。
[event_receiver(com)]
class CMyReceiver
{
void handler1(int i) { ... }
void handler2(int i, float j) { ... }
}
すると、event_source を使用して作成できるイベント ソースからのイベント (組み込み関数 __hook を使用) を処理するように、CMyReceiver
メソッド handler1
および handler2
を設定できます。
属性の基本的なしくみ
プロジェクトに属性を挿入するには、3 つの方法があります。 最初に、ソース コードにそれらを手動で挿入できます。 次に、プロジェクト内のオブジェクトのプロパティ グリッドを使用してそれらを挿入できます。 最後に、さまざまなウィザードを使用して挿入できます。 [プロパティ] ウィンドウとさまざまなウィザードの使用の詳細については、「Visual Studio プロジェクト - C++」を参照してください。
前と同様に、プロジェクトの作成時に、コンパイラは各 C++ ソース ファイルを解析し、オブジェクト ファイルを生成します。 ただし、コンパイラが属性を検出すると、解析され、構文的に検証されます。 その後、コンパイラは属性プロバイダーを動的に呼び出してコードを挿入するか、コンパイル時に他の変更を行います。 プロバイダーの実装は、属性の種類によって異なります。 たとえば、ATL 関連の属性は、Atlprov.dll によって実装されます。
次の図は、コンパイラと属性プロバイダーの関係を示しています。
Note
属性を使用しても、ソース ファイルの内容は変更されません。 生成された属性コードが表示されるのは、デバッグ セッション中のみです。 さらに、プロジェクト内のソース ファイルごとに、属性の置換の結果を表示するテキスト ファイルを生成できます。 この手順の詳細については、「 /Fx
(挿入されたコードのマージ) と Debug 挿入コードを参照してください。
ほとんどの C++ コンストラクトと同様に、属性には、適切な使用方法を定義する一連の特性があります。 これは 属性のコンテキストと呼ばれます。各属性参照トピックの属性コンテキスト テーブルで扱われます。 たとえば、coclass 属性は、C++ ソース ファイル内の任意の場所に挿入できる cpp_quote 属性とは対照的に、既存のクラスまたは構造体にのみ適用できます。
属性付きプログラムの作成
Visual C++ の属性をソース コードに追加した後、Microsoft C++ コンパイラでタイプ ライブラリと .idlファイルを自動的に生成できます。 次のリンカー オプションは、.tlb ファイルと .idl ファイルの作成に役立ちます。
一部のプロジェクトには、複数の独立した .idl ファイルが含まれています。 これらは、2 つ以上の .tlb ファイルを生成し、必要に応じてそれらのファイルをリソース ブロックにバインドするために使用されます。 このシナリオは現在、Visual C++ ではサポートされていません。
また、Visual C++ リンカーは、すべての IDL 関連の属性情報を 1 つの MIDL ファイルに出力します。 1 つのプロジェクトから 2 つのタイプ ライブラリを生成する方法はありません。
属性コンテキスト
C++ 属性は、以下の 4 つの基本的なフィールドを使用して記述できます。適用できるターゲット (適用対象)、反復可能かどうか (反復可能)、他の属性が必要かどうか (必須属性)、および他の属性との非互換性 (無効な属性)。 これらのフィールドは、各属性の参照トピックの付随する表に記載されています。 それぞれのフィールドの説明を以下に示します。
適用対象
このフィールドは、指定された属性の有効なターゲットであるさまざまな C++ 言語要素について説明します。 たとえば、 [適用対象] フィールドで属性に "class" が指定されている場合、この属性は有効な C++ クラスにのみ適用できることを意味します。 属性がクラスのメンバー関数に適用されると、構文エラーが発生します。
詳細については、「用途別の属性」を参照してください。
反復可能
このフィールドは、属性を同じターゲットに繰り返し適用できるかどうかを示します。 属性の大部分は反復可能ではありません。
必須の属性
このフィールドには、指定した属性が正しく機能するために存在する必要がある (つまり、同じターゲットに適用される) その他の属性が一覧表示されます。 属性にこのフィールドのエントリが含まれるのは一般的ではありません。
無効な属性
このフィールドには、指定した属性と互換性のないその他の属性が一覧表示されます。 属性にこのフィールドのエントリが含まれるのは一般的ではありません。
挿入されたコードをデバッグする
属性を使用すると、C++ でのプログラミングが簡単になります。 詳細については、概念に関するページを参照してください。 一部の属性は、コンパイラによって直接解釈されます。 プログラム ソースにコードを挿入するタイプの属性もあります。この場合、コンパイラは、コードが挿入されてからプログラム ソースをコンパイルします。 このようにコードが挿入されることにより、実際に記述するコードの量が減り、プログラミングがいっそう簡単になります。 しかし、挿入されたコードの実行中に、バグが発生してアプリケーションが正しく動作しなくなる場合があります。 このような場合は、挿入されたコードを確認する必要があります。 Visual Studio では、次の 2 つの方法で、挿入されたコードを参照できます。
挿入されたコードを [逆アセンブリ] ウィンドウに表示できます。
/Fx を使用して、元のコードと挿入されたコードをマージしたソース ファイルを作成できます。
[逆アセンブリ] ウィンドウには、ソース コードと、属性によって挿入されたコードに対応するアセンブリ言語命令が表示されます。 また、[逆アセンブリ] ウィンドウには、ソース コードの注釈を表示することもできます。
ソースの注釈を表示するには
[逆アセンブリ] ウィンドウを右クリックし、ショートカット メニューの [ソース コードの表示] を選びます。
ソース ウィンドウ内の属性の位置がわかっている場合は、ショートカット メニューを使用して、その属性が挿入したコードを [逆アセンブリ] ウィンドウに表示できます。
挿入されたコードを表示するには
デバッガーは中断モードである必要があります。
ソース コード ウィンドウで、挿入されたコードを表示する対象の属性の直前にカーソルを置きます。
右クリックし、ショートカット メニューの [逆アセンブリを表示] を選択します。
属性の位置が現在の実行ポイントに近い場合は、[デバッグ] メニューの [逆アセンブリ] ウィンドウを選択できます。
現在の実行ポイントにあるコードを表示するには
デバッガーは中断モードである必要があります。
[デバッグ] メニューの [Windows] を選び、[逆アセンブリ] をクリックします。