Microsoft インターフェイス定義言語 3.0 の概要

Microsoft Interface Definition Language (MIDL) 3.0 は、インターフェイス定義言語 (IDL) ファイル (ファイル.idl) 内でWindows ランタイム型を定義するための簡略化された最新の構文です。 この新しい構文は、C、C++、C#、Java の経験を持つすべてのユーザーにとって馴染みのあるものになります。 MIDL 3.0 は 、C++/WinRT ランタイム クラスを定義するのに特に便利な方法です。IDL の以前のバージョンよりも大幅に簡潔になります (デザインの長さを 3 分の 2 に減らし、適切な既定値を使用して属性で装飾する必要性を減らします)。

MIDL 3.0 の外観を次に示します。この例では、使用する可能性が高い言語構文要素の大部分を示します。

// Photo.idl
namespace PhotoEditor
{
    delegate void RecognitionHandler(Boolean arg); // delegate type, for an event.

    runtimeclass Photo : Windows.UI.Xaml.Data.INotifyPropertyChanged // interface.
    {
        Photo(); // constructors.
        Photo(Windows.Storage.StorageFile imageFile);

        String ImageName{ get; }; // read-only property.
        Single SepiaIntensity; // read-write property.

        Windows.Foundation.IAsyncAction StartRecognitionAsync(); // (asynchronous) method.

        event RecognitionHandler ImageRecognized; // event.
    }
}

MIDL 3.0 の構文は、型の 定義 のみを目的として特別に設計されていることに注意してください。 これらの型を 実装 するには、別のプログラミング言語を使用します。 MIDL 3.0 を使用するには、Windows SDK バージョン 10.0.17134.0 (Windows 10、バージョン 1803) (midl.exeバージョン 8.01.0622 以降、スイッチで/winrt使用) が必要です。

Note

Windows ランタイム統合リファレンス (Windows ランタイム 型システムおよび Windows メタデータ ファイル) も参照してください。

MIDL 1.0、2.0、3.0

インターフェイス定義言語 (IDL) は、分散コンピューティング環境/リモート プロシージャ コール (DCE/RPC) システムから始まりました。 元の MIDL 1.0 は DCE/RPC IDL であり、COM インターフェイスとコクラスの定義が強化されています。

その後、更新された MIDL 2.0 構文 (MIDLRT とも呼ばれます) が Microsoft 内で開発され、Windows プラットフォームWindows ランタイム API が宣言されました。 Windows SDK フォルダー %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\winrt を見ると、MIDL 2.0 構文で記述されたファイルの .idl 例が表示されます。 これらは組み込みのWindows ランタイム API であり、アプリケーション バイナリ インターフェイス (ABI) 形式で宣言されています。 これらのファイルは主にツールで使用するために存在します。これらの API は、(非常に低レベルのコードを記述している場合を除き) この形式では作成も使用もしません。

クラシック MIDLRT から MIDL 3.0 への移行も参照してください。

MIDL 3.0 は、API Windows ランタイム宣言することを目的とする、はるかにシンプルでモダンな構文です。 また、特に C++/WinRT ランタイム クラスを定義するために、プロジェクトで使用できます。 組み込みのWindows ランタイム API 用の C++/WinRT から使用するヘッダーは、フォルダー%WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt内の SDK の一部です。

MIDL 3.0 のユース ケース

一般に、すべてのWindows ランタイム API は、すべてのWindows ランタイム言語プロジェクションで使用できるように設計されています。 これは部分的に、Windows ランタイム API との間でWindows ランタイム型を排他的に渡すことによって行われます。 Windows ランタイム API との間で生の COM インターフェイスを渡すことが有効な設計上の決定ですが、これを行うと、その特定の Windows ランタイム API のコンシューマーは C++ アプリケーションに制限されます。 この手法は、相互運用シナリオ (たとえば、Direct3D と XAML の間で相互運用する場合) で確認できます。 Direct3D は図に含まれているので、シナリオは必ずしも C++ アプリケーションに絞り込まれます。 そのため、COM インターフェイスを必要とする API では、固有の制限以上の制限は課されません。 たとえば、C++ アプリケーションは IDXGISwapChain インターフェイス ポインターを取得し、それを ISwapChainPanelNative::SetSwapChain メソッドに渡すことができます。 たとえば、C# アプリケーションでは、最初に IDXGISwapChain を取得できないため、その理由でそのメソッドを使用することはできません。 これらの相互運用に関連する例外は、相互運用ヘッダー (..windows.ui.xaml.media.dxinterop.h

C++ 以外のWindows ランタイム言語プロジェクションに公開する COM コンポーネントの機能がある場合、C++ Windows ランタイム コンポーネント (たとえば DirectX など) を直接作成して使用し、その機能の一部のサブセットのレプリケーションを直接作成して使用する C++ Windows ランタイム コンポーネント (WRC) を作成できます。Windows ランタイム型のみを受け取って返す API サーフェイスWindows ランタイムします。 その後、任意のWindows ランタイム言語プロジェクションで記述されたアプリケーションからその WRC を使用できます。

定義構造、およびコマンド ラインからのmidl.exeの呼び出し

MIDL 3.0 定義の主な組織の概念は、名前空間、型、およびメンバーです。 MIDL 3.0 ソース ファイル ( .idl ファイル) には、少なくとも 1 つの名前空間が含まれており、その内部には型や下位の名前空間があります。 各型には、0 個以上のメンバーが含まれています。

  • クラス、インターフェイス、構造体、列挙型は型です。
  • メソッド、プロパティ、イベント、フィールドはメンバーの例です。

MIDL 3.0 ソース ファイルをコンパイルすると、コンパイラ (midl.exe) はWindows ランタイムメタデータ ファイル (通常は.winmdファイル) を出力します。

// Bookstore.idl
namespace Bookstore
{
    runtimeclass BookSku : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        BookSku();
        BookSku(Single price, String authorName, String coverImagePath, String title);

        Single Price;

        String AuthorName{ get; };
        Windows.UI.Xaml.Media.ImageSource CoverImage{ get; };
        String CoverImagePath{ get; };
        String Title{ get; };

        Boolean Equals(BookSku other);
        void ApplyDiscount(Single percentOff);
    }
}

Windows ランタイム型の名前空間は型名の一部になるため、上の例では Bookstore.BookSku という名前のランタイム クラスを定義しています。 名前空間も表現せずに BookSku を表現する言語に依存しない方法はありません。

このクラスは 、Windows.UI.Xaml.Data.INotifyPropertyChanged インターフェイスを実装します。 クラスには、2 つのコンストラクター、読み取り/書き込みプロパティ (Price)、読み取り専用プロパティ (AuthorName から Title)、 EqualsApplyDiscount という名前の 2 つのメソッドという複数のメンバーが含まれています。 float ではなく Single 型の使用に注意してください。 その 文字列 には大文字の "S" があります。

ヒント

Visual Studio は、C++/WinRT Visual Studio 拡張機能 (VSIX) を使用して MIDL 3.0 をコンパイルするための最適なエクスペリエンスを提供します。 「C++/WinRT の Visual Studio サポートと VSIX」を参照してください。

ただし、コマンド ラインから MIDL 3.0 をコンパイルすることもできます。 この例のソース コードが名前付きの Bookstore.idlファイルに格納されている場合は、次のコマンドを発行できます。 ケースに必要な場合は、コマンドで使用されている SDK バージョン番号 (10.0.17134.0) を更新できます。

midl /winrt /metadata_dir "%WindowsSdkDir%References\10.0.17134.0\windows.foundation.foundationcontract\3.0.0.0" /h "nul" /nomidl /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd" /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\Windows.Foundation.UniversalApiContract.winmd" /reference "%WindowsSdkDir%\References\10.0.17134.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd" Bookstore.idl

このツールは midl.exe 、この例をコンパイルし、名前付きの Bookstore.winmd メタデータ ファイルを生成します (既定では、ファイルの .idl 名前が使用されます)。

ヒント

複数の IDL ファイルを使用する場合 (詳細については、 ランタイム クラスを Midl ファイル (.idl) に組み込む方法を参照してください)、結果として生成 .winmd されるすべてのファイルを、ルート名前空間と同じ名前の 1 つのファイルにマージします。 最終的な .winmd ファイルは、API のコンシューマーが参照するファイルになります。

この場合、 BookSkuBookstore 名前空間の唯一のランタイム クラスであるため、ステップを保存し、名前空間の .idl ファイルという名前を付けただけです。

なお、このコマンドを where 使用して、インストールされている場所 midl.exe を確認できます。

where midl

1 つの .idl ファイルで定義されている型を別 .idl のファイルから使用する場合は、ディレクティブを import 使用します。 詳細とコード例については、 XAML コントロールと C++/WinRT プロパティへのバインドに関するページを参照してください。 もちろん、組み込みコンポーネントまたはサードパーティ製コンポーネントを使用している場合は、ファイルに .idl アクセスできません。 たとえば、イミディエイト モードの 2D グラフィックス レンダリングに Win2D Windows ランタイム API を使用できます。 上記のコマンドでは、スイッチを/reference使用して、Windows ランタイムメタデータ (.winmd) ファイルを参照しました。 この次の例では、このスイッチをもう一度使用し、あるシナリオを想像しますが、実際には Bookstore.winmd使用しません Bookstore.idl

// MVVMApp.idl
namespace MVVMApp
{
    runtimeclass ViewModel
    {
        ViewModel();
        Bookstore.BookSku BookSku{ get; };
    }
}

上記の例のソース コードが名前付きの MVVMApp.idlファイルに格納されている場合は、次のコマンドを発行して参照 Bookstore.winmdできます。

midl /winrt /metadata_dir "%WindowsSdkDir%References\10.0.17134.0\windows.foundation.foundationcontract\3.0.0.0" /h "nul" /nomidl /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd" /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\Windows.Foundation.UniversalApiContract.winmd" /reference "%WindowsSdkDir%\References\10.0.17134.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd" /reference Bookstore.winmd MVVMApp.idl

名前空間

名前空間が必要です。 名前空間ブロックのスコープで定義されているすべての型の名前の前に名前空間名を付けます。 名前空間には、下位の名前空間宣言を含めることもできます。 下位の名前空間スコープで定義されている型の名前には、含まれるすべての名前空間名のプレフィックスがあります。

次の例は、同じ Windows.Foundation.Uri クラスを宣言する 2 つの方法です (ご覧のとおり、ピリオドは入れ子になった名前空間のレベルを区切ります)。

namespace Windows.Foundation
{
    runtimeclass Uri : IStringable
    {
        ...
    }
}
namespace Windows
{
    namespace Foundation
    {
        runtimeclass Uri : IStringable
        {
            ...
        }
    }
}

名前空間とその型を入れ子にして宣言することは有効であることを示す別の例を次に示します。

namespace RootNs.SubNs1
{
    runtimeclass MySubNs1Class
    {
        void DoWork();
    }

    namespace SubNs2
    {
        runtimeclass MySubNs2Class
        {
            void DoWork();
        }
    }
}

ただし、以前の名前空間を閉じて、次のように新しい名前空間を開く方が一般的です。

namespace RootNs.SubNs1
{
    runtimeclass MySubNs1Class
    {
        void DoWork();
    }
}

namespace RootNs.SubNs1.SubNs2
{
    runtimeclass MySubNs2Class
    {
        void DoWork();
    }
}

種類

MIDL 3.0 には、値型と参照型の 2 種類のデータ型があります。 値型の変数には、そのデータが直接含まれます。 参照型の変数は、そのデータへの参照を格納します (このような変数は オブジェクトとも呼ばれます)。

2 つの参照型変数で同じオブジェクトを参照できます。 したがって、1 つの変数に対する操作は、もう一方の変数によって参照されるオブジェクトに影響します。 値型の場合、変数はそれぞれデータの独自のコピーを持ち、一方の操作が他方に影響を与えることはできません。

MIDL 3.0 の値型は、さらに単純型、列挙型、構造体型、および null 許容型に分割されます。

MIDL 3.0 の参照型は、さらにクラス型、インターフェイス型、デリゲート型に分割されます。

MIDL 3.0 の型システムの概要を次に示します。 以前のバージョンの MIDL とは異なり、これらの型にはエイリアスを使用できません。

カテゴリ 説明
値型 単純型 符号付き整数: Int16Int32Int64
符号なし整数: UInt8UInt16UInt32UInt64
Unicode 文字: Char (UTF-16LE、16 ビット Unicode コード単位を表します)
Unicode 文字列: 文字列
IEEE 浮動小数点: 単一倍精度浮動小数点
ブール値: ブール値
128 ビット UUID: Guid
列挙型 フォーム列挙型 E {...} のユーザー定義型
構造体の型 フォーム構造体 S {...} のユーザー定義型
null 許容型 null 値を持つ他のすべての値型の拡張
参照型 クラスの種類 他のすべての型の最終的な基底クラス: Object
ランタイムクラス C {...} フォームのユーザー定義型
インターフェイス型 フォーム インターフェイス I {...} のユーザー定義型
デリゲート型 フォーム デリゲート <returnType> D(...) のユーザー定義型

7 つの整数型は、8 ビット符号なしデータのサポートを提供します。符号付きまたは符号なし形式の 16 ビット、32 ビット、および 64 ビットの値。

2 つの浮動小数点型 SingleDouble は、それぞれ 32 ビットの単精度と 64 ビットの倍精度 IEEE 754 形式を使用してデータを表します。

MIDL 3.0 の ブール 型はブール値を表します。または truefalse.

MIDL 3.0 の文字と文字列には、Unicode 文字が含まれています。 Char 型は UTF-16LE コード単位を表します。文字列型は UTF-16LE コードユニットのシーケンスを表します。

次の表は、MIDL 3.0 の数値型をまとめたものです。

カテゴリ Bits Type Range/Precision
符号付き整数 16 Int16 –32,768...32,767
32 Int32 –2,147,483,648...2,147,483,647
64 Int64 –9,223,372,036,854,775,808...9,223,372,036,854,775,807
符号なしの整数 8 UInt8 0...255
16 UInt16 0...65,535
32 UInt32 0...4,294,967,295
64 UInt64 0...18,446,744,073,709,551,615
浮動小数点 32 Single 1.5 × 10-45 から 3.4 × 1038、7 桁の有効桁数
64 Double 5.0 × 10-324 から 1.7 × 10308、15 桁の有効桁数

MIDL 3.0 ソース ファイルでは、型定義を使用して新しい型を作成します。 型定義では、名前と新しい型のメンバーを指定します。 これらの MIDL 3.0 型カテゴリは、ユーザー定義可能です。

  • 属性の種類,
  • 構造体の型、
  • インターフェイスの種類、
  • runtimeclass 型,
  • デリゲート型、および
  • 列挙型。

属性型は、他の型定義に適用できるWindows ランタイム属性を定義します。 属性は、属性が適用される型に関するメタデータを提供します。

構造体型は、データ メンバー (フィールド) を含むWindows ランタイム構造体を定義します。 構造体は値型であり、ヒープ割り当てを必要としません。 構造体型のデータ メンバーは、値型または null 許容型である必要があります。 構造体の型は継承をサポートしていません。

インターフェイス型は、関数メンバーの名前付きセットであるWindows ランタイム インターフェイスを定義します。 インターフェイスは、インターフェイスの実装で、指定された 1 つ以上の追加 (必須) インターフェイスも実装する必要があることを指定できます。 すべてのインターフェイスの種類は、Windows ランタイム IInspectable インターフェイスから直接派生します。

runtimeclass 型は、Windows ランタイム クラス (ランタイム クラス) を定義します。 ランタイム クラスには、プロパティ、メソッド、およびイベントを指定できるメンバーが含まれています。

デリゲート型は、特定のパラメーター リストと戻り値の型を持つメソッドへの参照を表すWindows ランタイム デリゲートを定義します。 デリゲートを使用すると、メソッドをパラメーターとして渡すことができるエンティティとして扱うことができます。 デリゲートは、他のいくつかの言語で見られる関数ポインターの概念に似ています。 関数ポインターとは異なり、デリゲートはオブジェクト指向であり、型セーフです。

列挙型は、名前付き定数を持つ特殊な型です。 すべての列挙型には暗黙的な基になる型があります。 Int32 または UInt32 のいずれか。 列挙型の値のセットは、基になる型の値のセットと同じです。

MIDL 3.0 では、3 つの追加の型カテゴリがサポートされています。

  • 1 次元配列型、
  • null 許容値型、および
  • オブジェクト型。

使用する前に 1 次元配列を宣言する必要はありません。 代わりに配列型は、角かっこで囲んだ型名を後に付けることにより構成されます。 たとえば、 Int32[]Int32 の 1 次元配列です。

同様に、 null 許容 値型を使用する前に定義する必要はありません。 null 非許容値型 T ( 文字列を除く) ごとに、対応する null 許容型 Windows.Foundation.IReference<T> があり、追加の値 nullを保持できます。 たとえば、 Windows.Foundation.IReference<Int32> は、任意の 32 ビット整数または値 nullを保持できる型です。 IReference<T> も参照してください。

最後に、MIDL 3.0 では、Windows ランタイム IInspectable インターフェイスにマップされる Object 型がサポートされています。 インターフェイスランタイムクラス参照型は、概念的に Object 型から派生します。デリゲートはしません。

列挙値の式

MIDL 3.0 では、列挙型の名前付き定数の値の定義でのみ を使用できます。言い換えると、列挙初期化子です。

式は、 オペランド演算子から構築されます。 式の演算子は、オペランドに適用する操作を示します。 演算子の例には、+、-、*、/、および new. オペランドの例としては、リテラル、フィールド、ローカル変数、式などがあります。

式に複数の演算子が含まれている場合、演算子の "優先順位" によって、個々の演算子を評価する順序が制御されます。 たとえば、式 x + y * z は x + (y * z) と評価されます。これは、* 演算子が + 演算子よりも優先順位が高いためです。 論理操作は、ビットごとの操作よりも優先順位が低くなります。

次の表は、MIDL 3.0 の演算子をまとめたものです。演算子のカテゴリを優先順位の高い順に示します。 同じカテゴリ内の演算子の優先順位は同じです。

カテゴリ 説明
プライマリ x++ 後置インクリメント。
x-- 後置デクリメント。
単項演算子 +x ID
-X 否定
!x 論理否定
~x ビットごとの否定。
++x 前置インクリメント。
--x 前置デクリメント。
乗算 x * y 乗算
x / y 事業部
x % y 剰余
加法 x + y 加算、文字列連結、デリゲートの組み合わせ
x – y 減算、デリゲートの削除。
Shift キー x << y 左シフト
x >> y 右シフト。
ビット演算子 AND x & y 整数ビットごとの AND
ビットごとの XOR x ^ y 整数ビットごとの XOR
ビットごとの OR x | y ビットごとの整数 OR
論理積 x && y ブール論理 AND
論理和 x || y ブール論理 OR

クラス

クラス (またはランタイム クラス) は、MIDL 3.0 の型の最も基本的なものです。 クラスは、メソッド、プロパティ、およびイベントを 1 つの単位で集計する定義です。 クラスは 継承ポリモーフィズムをサポートします。 派生クラス基底クラスを拡張および特殊化できるメカニズムです。

クラス定義を使用して、新しいクラス型を定義します。 クラス定義は、キーワード、クラスの名前、基底クラス (指定されている場合)、およびクラスによって実装されるインターフェイスを指定 runtimeclass するヘッダーで始まります。 ヘッダーの後にクラス本体が続きます。これは、区切り記号 { と }の間に書き込まれたメンバー宣言のリストで構成されます。

Area という名前の単純なクラスの定義を次に示します。

runtimeclass Area
{
    Area(Int32 width, Int32 height);

    Int32 Height;
    Int32 Width;

    static Int32 NumberOfAreas { get; };
}

これにより、Area という名前の新しいWindows ランタイム クラスが定義されます。このクラスには、2 つの Int32 パラメーター、HeightWidth という名前の 2 つの Int32 読み取り/書き込みプロパティ、および NumberOfAreas という名前の静的読み取り専用プロパティを受け取るコンストラクターがあります。

既定では、ランタイム クラスはシールされ、そこから派生することは許可されません。 基底クラスを参照してください。

XAML をビュー モデルにバインドするには、ビュー モデル ランタイム クラスを MIDL で定義する必要があります。 詳細情報については、「XAML コントロール: C++/WinRT プロパティへのバインド」を参照してください。

ランタイム クラス定義 static の前にキーワードを付けることで、クラスがインスタンスをサポートしていない (したがって静的メンバーのみを含む必要がある) ことを宣言できます。 クラスに非静的メンバーを追加すると、コンパイル エラーが発生します。

static runtimeclass Area
{
    static Int32 NumberOfAreas { get; };
}

静的クラスは空のクラスとは異なります。 「空のクラス」も参照してください。

ランタイム クラス定義の前にキーワードを付 partial けることで、クラス定義が不完全であることを示すことができます。 コンパイラによって検出されたすべての部分クラス定義は、1 つのランタイム クラスに結合されます。 この機能は主に、部分的なクラスの一部がマシンで生成される XAML 作成シナリオに対するものです。

修飾子 説明
static クラスにはインスタンスがありません。 その結果、静的メンバーのみが許可されます。
partial クラス定義が不完全です。

高度な修飾子については、「 コンポジションとアクティブ化 」を参照してください。

メンバー アクセス修飾子

MIDL 3.0 はWindows ランタイム型のパブリック サーフェスを記述するための定義言語であるため、メンバーのパブリック アクセシビリティを宣言するための明示的な構文は必要ありません。 すべてのメンバーは暗黙的にパブリックです。 そのため、MIDL 3.0 では (実質的に冗長な) public キーワードを必要とせず、許可もしません。

基底クラス

クラス定義では、クラス名と型パラメーターにコロンと基底クラスの名前を付けて、基底クラスを指定できます。 基底クラスの指定を省略することは、 Object 型 (つまり IInspectable から) の派生と同じです。

Note

ビュー モデル クラス (実際には、アプリケーションで定義したランタイム クラス) は、基底クラスから派生する必要はありません。

基底クラス から派生する アプリケーションで定義するランタイム クラスは、 コンポーザブル クラスと呼ばれます。 また、構成可能クラスに関しては制約があります。 Visual Studio および Microsoft Store が送信を検証するために使用する Windows App Certification Kit テストにアプリケーションが合格するには (そして結果的に、アプリケーションが Microsoft Store に正常に取り込まれるには)、構成可能クラスを最終的に Windows 基底クラスから派生させる必要があります。 つまり、継承階層の最上位にあるクラスは、Windows.* 名前空間から取得された型である必要があります。

詳細情報については、「XAML コントロール: C++/WinRT プロパティへのバインド」を参照してください。

次の例では、 Volume の基本クラスは Area で、 Area の基本クラスは Windows.UI.Xaml.DependencyObject です

unsealed runtimeclass Area : Windows.UI.Xaml.DependencyObject
{
    Area(Int32 width, Int32 height);
    Int32 Height;
    Int32 Width;
}

runtimeclass Volume : Area
{
    Volume(Int32 width, Int32 height, Int32 depth);
    Int32 Depth;
}

Note

ここで、 領域ボリューム は同じソース ファイルで定義されます。 長所と短所については、 ランタイム クラスを Midl ファイル (.idl) に組み込む方法に関するページを参照してください。

クラスは、その基底クラスのメンバーを継承します。 継承とは、基底クラスのコンストラクターを除き、基底クラスのすべてのメンバーがクラスに暗黙的に含まれていることを意味します。 派生クラスは、継承するメンバーに新しいメンバーを追加できますが、継承されたメンバーの定義を削除することはできません。

前の例では、ボリュームArea から Height プロパティと Width プロパティを継承します。 そのため、すべての ボリューム インスタンスには、 HeightWidth、Depth の 3 つのプロパティ が含まれています

一般に、型解決規則では、参照時に型名を完全修飾する必要があります。 例外は、型が現在の型と同じ名前空間で定義されている場合です。 上の例は、 AreaVolume の両方が同じ名前空間にある場合に記述されているように機能します。

実装されるインターフェイス

クラス定義では、クラスが実装するインターフェイスの一覧を指定することもできます。 インターフェイスは、(省略可能) 基本クラスに続くインターフェイスのコンマ区切りの一覧として指定します。

次の例では、 Area クラスは IStringable インターフェイスを実装しています。 Volume クラスは 、IStringable インターフェイスと仮想 IEquatable インターフェイスの両方を実装します。

unsealed runtimeclass Area : Windows.Foundation.IStringable
{
    Area(Int32 width, Int32 height);
    Int32 Height;
    Int32 Width;
}

runtimeclass Volume : Area, Windows.Foundation.IStringable, IEquatable
{
    Volume(Int32 width, Int32 height, Int32 depth);
    Int32 Depth;
}

MIDL では、クラスでインターフェイスのメンバーを宣言しません。 もちろん、実際の実装で宣言して定義する必要があります。

メンバー

クラスのメンバーは、 静的メンバー または インスタンス メンバーです。 静的メンバーはクラスに属します。 インスタンス メンバーは、オブジェクト (つまり、クラスのインスタンス) に属します。

次の表は、クラスに含めることができるメンバーの種類を示しています。

メンバーの種類 説明
コンストラクター クラスのインスタンスを初期化したり、クラス自体を初期化したりするために必要なアクション
プロパティ クラスのインスタンスまたはクラス自体の名前付きプロパティの読み取りと書き込みに関連するアクション
メソッド クラスのインスタンスまたはクラス自体によって実行できる計算とアクション
イベント クラスのインスタンスによって発生できる通知

コンストラクター

MIDL 3.0 では、インスタンス コンストラクターの宣言がサポートされています。 インスタンス コンストラクターは、クラスのインスタンスを初期化するために必要なアクションを実装するメソッドです。 コンストラクターは静的ではない可能性があります。

コンストラクターはインスタンス メソッドのように宣言され (ただし、戻り値の型はありません)、含むクラスと同じ名前で宣言されます。

インスタンス コンストラクターはオーバーロードできます。 たとえば、以下の Test クラスは 3 つのインスタンス コンストラクターを宣言します。1 つはパラメーターなし ( 既定 のコンストラクター)、1 つは Int32 パラメーターを受け取り、1 つは 2 つの Double パラメーター (パラメーター化された コンストラクター) を受け取ります。

runtimeclass Test
{
    Test();
    Test(Int32 x);
    Test(Double x, Double y);
}

パラメーター リストの構文の詳細については、以下の メソッドを 参照してください。

インスタンスのプロパティ、メソッド、およびイベントは継承されます。 インスタンス コンストラクターは継承されず (例外が 1 つ除く)、クラスには、クラスで実際に宣言されているもの以外のインスタンス コンストラクターはありません。 クラスにインスタンス コンストラクターが指定されていない場合、クラスを直接インスタンス化することはできません。 このようなクラスの場合、通常は、クラスのインスタンスを返すファクトリ メソッドが他の場所にあります。

例外は封印されていないクラスです。 封印されていないクラスには、1 つ以上の保護されたコンストラクターを含めることができます。

プロパティ

プロパティ は概念的にはフィールド (C# フィールドや MIDL 3.0 構造体のフィールドなど) に似ています。 プロパティとフィールドはどちらも、名前と関連付けられた型を持つメンバーです。 ただし、フィールドとは異なり、プロパティは格納場所を表しません。 代わりに、プロパティには、プロパティの読み取りまたは書き込み時に実行する関数を指定する アクセサー があります。

プロパティは構造体のフィールドのように宣言されます。ただし、宣言は、区切り記号 { と }の間に記述されたキーワードやsetキーワードで終getわり、セミコロンで終わる点を除きます。

キーワードとキーワードの両方を持つgetプロパティは、読み取り/書き込みプロパティですset キーワードのみを get 持つプロパティは、 読み取り専用プロパティです。 Windows ランタイムでは、書き込み専用プロパティはサポートされていません。

たとえば、前に示した クラス Area には、 HeightWidth という名前の 2 つの読み取り/書き込みプロパティが含まれています。

unsealed runtimeclass Area
{
    Int32 Height { get; set; };
    Int32 Width; // get and set are implied if both are omitted.
}

Width の宣言では、中かっことキーワードはgetset省略されます。 省略は、プロパティが読み取り/書き込みであり、その順序getでキーワードを指定するget場合とset意味的に同じであることを意味します。その後setに .

さらに、プロパティが読み取り get 専用であることを示すキーワードのみを指定できます。

// Read-only instance property returning mutable collection.
Windows.Foundation.Collections.IVector<Windows.UI.Color> Colors { get; };

Windows ランタイムでは、書き込み専用プロパティはサポートされていません。 ただし、キーワードのみを指定して、既存の set 読み取り専用プロパティを読み取り/書き込みプロパティに変更できます。 このバージョンの Area を例として見てみましょう。

unsealed runtimeclass Area
{
    ...
    Color SurfaceColor { get; };
}

その後、SurfaceColor プロパティを読み取り/書き込み可能にする必要があり、Area の以前の定義とのバイナリ互換性を維持する必要がない場合 (たとえば、Area クラスは、毎回再コンパイルするアプリケーションの型です)、次のように既存の SurfaceColor 宣言にキーワードを追加setするだけです。

unsealed runtimeclass Area
{
    ...
    Color SurfaceColor { get; set; };
}

一方、バイナリの安定性 が必要な 場合 (たとえば、 Area クラスは、顧客に出荷するライブラリ内のコンポーネントです)、既存の set プロパティ宣言にキーワードを追加することはできません。 これにより、バイナリ インターフェイスがクラスに変更されます。

その場合は、次のように、クラス set の末尾にあるプロパティの追加の定義に property キーワードを追加します。

unsealed runtimeclass Area
{
    ...
    Color SurfaceColor { get; };
    ...
    Color SurfaceColor { set; };
}

コンパイラは、書き込み専用プロパティに対してエラーを生成します。 しかし、それはここで行われているものではありません。 前述のプロパティの宣言は読み取り専用であるため、set キーワードを追加しても書き込み専用プロパティは宣言されませんが、代わりに読み取り/書き込みプロパティが宣言されます。

プロパティのWindows ランタイム実装は、インターフェイス上の 1 つまたは 2 つのアクセサー メソッドです。 プロパティ宣言の get キーワードと set キーワードの順序によって、バッキング インターフェイス内の get アクセサー メソッドと set アクセサー メソッドの順序が決まります。

アクセサーは get 、プロパティ型 (プロパティ getter) の戻り値を持つパラメーターなしのメソッドに対応します。

アクセサーは set 、value という名前の単一のパラメーターを持ち、戻り の型を持たないメソッド (プロパティ セッター) に対応します。

したがって、これら 2 つの宣言では、異なるバイナリ インターフェイスが生成されます。

Color SurfaceColor { get; set; };
Color SurfaceColor { set; get; };
静的プロパティとインスタンス プロパティ

メソッドと同様に、MIDL 3.0 ではインスタンス プロパティと静的プロパティの両方がサポートされています。 静的プロパティは修飾子の前に static 付いて宣言され、インスタンス プロパティはそれなしで宣言されます。

メソッド

メソッドは、クラスのインスタンスまたはクラス自体によって実行できる計算またはアクションを実装するメンバーです。 静的メソッドは、クラスを介してアクセスされます。 インスタンス メソッドは、クラスのインスタンスを介してアクセスされます。

メソッドには、メソッドに渡される値または変数参照を表す パラメーターの (空の可能性がある) リストがあります。 メソッドには 戻り値の型もあります。戻り値の型は、メソッドによって計算されて返される値の型を指定します。 メソッドによって値が返されない場合、メソッドの戻り値の型は void です。

// Instance method with no return value.
void AddData(String data);

// Instance method *with* a return value.
Int32 GetDataSize();

// Instance method accepting/returning a runtime class.
// Notice that you don't say "&" nor "*" for reference types.
BasicClass MergeWith(BasicClass other);

// Asynchronous instance methods.
Windows.Foundation.IAsyncAction UpdateAsync();
Windows.Foundation.IAsyncOperation<Boolean> TrySaveAsync();

// Instance method that returns a value through a parameter.
Boolean TryParseInt16(String input, out Int16 value);

// Instance method that receives a reference to a value type.
Double CalculateArea(ref const Windows.Foundation.Rect value);

// Instance method accepting or returning a conformant array.
void SetBytes(UInt8[] bytes);
UInt8[] GetBytes();

// instance method that writes to a caller-provided conformant array
void ReadBytes(ref UInt8[] bytes);

メソッドの "シグネチャ" は、メソッドが宣言されているクラス内で一意である必要があります。 メソッドのシグネチャは、メソッドの名前、そのパラメーターの型、およびそのパラメーターの数で構成されます。 メソッドのシグネチャに戻り値の型は含まれません。

メソッドの可視性修飾子

メソッドが派生クラスに存在する場合、 メソッド には 2 つのオプションの可視性修飾子のいずれかを指定できます。

オーバーライド可能な修飾子は、サブクラスに属するメソッド (同じ名前とシグネチャを持つ) によってこのメソッドがオーバーライドされる可能性があることを示します。

保護された修飾子は、このメソッドは後続の派生クラスのメンバーのみがアクセス可能であると述べています。

メソッドのオーバーロード

メソッド のオーバーロード では、パラメーターの数が異なる限り、同じクラス内の複数のメソッドが同じ名前を持つことができます (つまり、メソッドの アリティが異なります)。

runtimeclass Test
{
    static void F();
    static void F(Double x);
    static void F(Double x, Double y);
}

Note

同じ名前のメソッドはすべて、異なる アリティを持つ必要があります。 これは、弱く型指定されたプログラミング言語では、型によるオーバーロードがサポートされていないためです。

パラメーター

パラメーター は、メソッドに値または変数参照を渡すために使用されます。 パラメーターは、型と名前を持つスロットと、必要に応じて修飾子キーワードを記述します。 引数は、メソッドの呼び出し元から呼び出し先にそのスロットに渡される実際の値です。

メソッドのパラメーターは、メソッドの呼び出し時に指定された特定の 引数 から値を取得します。 呼び出し元と呼び出し先の間で引数を渡す方法は、パラメーターの型によって異なります。 既定では、すべてのパラメーターは 入力パラメーターです。つまり、呼び出し元から呼び出し先にのみマーシャリングされます。 修飾子キーワード refref constおよび呼び出し元と out 呼び出し先の間のマーシャリングの既定の方向を変更し、 出力パラメーターを作成するために追加できます。 ただし、すべてのキーワードがすべてのパラメーター型で有効なわけではありません。有効な組み合わせを以下に詳しく示します。

重要

共通言語ランタイム (CLR) には、このセクションで説明したものと似ているように見える概念と修飾子キーワードがあります。 しかし、実際にはそれらは無関係であり、これらの修飾子の効果は、Windows ランタイムの設計と機能に固有です。

値型は暗黙的に 入力パラメーターであり、既定では、引数のコピーが呼び出し元から呼び出し先に渡されます。 値パラメーターは、キーワードを使用outして出力パラメーターに変換できます。その場合、引数は呼び出し先から呼び出し元のみにマーシャリングされます。

runtimeclass Test
{
    static void Divide(Int32 x, Int32 y, out Int32 result, out Int32 remainder);
}

特別なパフォーマンスの最適化として、通常は値によって完全コピーとして渡される構造体型 (およびその他の型) は、不変構造体へのポインターによって渡すことができます。 これは、構造体パラメーターを ref const 入力パラメーターとしてマークする (notconst ref) キーワードで実現されますが、構造体の完全なコピーを渡す代わりに、構造体のストレージへのポインターを渡すようにマーシャラーに指示します。 ただし、構造体は不変であることに注意してください。ポインターは概念的には const ポインターです。 ボクシングは関係ありません。 これは、 たとえば Matrix4x4 のような大きな値を受け入れる場合に実用的な選択肢です。

runtimeclass Test
{
    static Boolean IsIdentity(ref const Windows.Foundation.Numerics.Matrix4x4 m);
}

参照型も暗黙的に入力パラメーターです。つまり、呼び出し元はオブジェクトを割り当て、そのオブジェクトへの参照を引数として渡します。ただし、引数はオブジェクトへの参照であるため、呼び出し先によるそのオブジェクトへの変更は、呼び出し後に呼び出し元によって観察されます。 または、参照型をキーワードを使用して出力パラメーターを out 作成することもできます。 その場合、ロールは元に戻されます。呼び出し先は、オブジェクトを割り当て、呼び出し元に返します。 ここでも、参照型でキーワードを ref 一般に使用することはできません (以下の例外を参照してください)。

runtimeclass Test
{
    static void CreateObjectWithConfig(Config config, out MyClass newObject);
}

次の表は、値パラメーターと参照パラメーターのマーシャリング キーワードの動作をまとめたものです。

動作 割り当て方法 Keyword 種類 解説
入力パラメーター Caller (なし) すべての種類 既定の動作
ref const 構造体のみ パフォーマンスの最適化
出力パラメーター Callee out すべての種類

Windows ランタイムでは、パラメーターとしての動作が多少異なる配列型がサポートされています。 配列は、連続して格納され、インデックスを介してアクセスされる多数の変数を含むデータ構造です。 配列に含まれる変数 (配列の 要素 とも呼ばれます) はすべて同じ型であり、この型は配列の 要素型 と呼ばれます。

MIDL 3.0 では、 1 次元配列の宣言がサポートされています。

配列パラメーターは参照型であり、すべての参照型と同様に、既定では入力パラメーターです。 その場合、呼び出し元は配列を呼び出し先に割り当てます。この配列は要素を読み取ることができますが、変更することはできません (読み取り専用)。 これを パス配列 パターンと呼ばれます。 または、 フィル配列 パターンを使用するには、パラメーターにキーワードを ref 追加します。そのセットアップでは、配列は呼び出し元によって引き続き割り当てられますが、概念的には、呼び出し先が配列要素の値を埋めるという意味での出力パラメーターです。 最後に、最後のパターンは、呼び出し先が呼び出し元に返される前に引数を割り当てて初期化している 受信配列 です (すべての出力参照パラメーターと同様)。

runtimeclass Test
{
    // Pass array pattern: read-only array from caller to callee
    void PassArray(Int32[] values);

    // Fill array pattern: caller allocates array for callee to fill
    void FillArray(ref Int32[] values);

    // Receive array pattern: callee allocates and fill an array returned to caller
    void ReceiveArray(out Int32[] values);
}

次の表は、配列とその要素の動作をまとめたものです。

配列パターン Keyword 割り当て方法 呼び出し先による要素のアクセス
"配列の渡し" (なし) Caller 読み取り専用
"Fill 配列" ref Caller 書き込み専用
"Receive array" out Callee 読み取り/書き込み

C++/WinRT で C スタイルの配列パラメーター (準拠配列とも呼ばれます) を使用する方法の詳細については、「 配列パラメーター」を参照してください。

静的メソッドとインスタンス メソッド

プレフィックスが付いた修飾子で static 宣言されたメソッドは静的 メソッドです。 静的メソッドは特定のインスタンスにアクセスできないため、クラスの他の静的メンバーにのみ直接アクセスできます。

static 修飾子なしで宣言されているメソッドは "インスタンス メソッド" です。 インスタンス メソッドは、特定のインスタンスにアクセスでき、クラスの静的メンバーとインスタンス メンバーの両方にアクセスできます。

次の Entity クラスには、静的メンバーとインスタンス メンバーの両方があります。

runtimeclass Entity
{
    Int32 SerialNo { get; };
    static Int32 GetNextSerialNo();
    static void SetNextSerialNo(Int32 value);
}

Entity インスタンスには、独自のシリアル番号 (およびおそらく、ここには示されていないその他の情報) が含まれています。 内部的には、 Entity コンストラクター (インスタンス メソッドに似ています) は、次に使用可能なシリアル番号を使用して新しいインスタンスを初期化します。

SerialNo プロパティは、プロパティ get メソッドを呼び出すインスタンスのシリアル番号へのアクセスを提供します。

GetNextSerialNo および SetNextSerialNo 静的メソッドは、Entity クラスの内部次に使用可能なシリアル番号静的メンバーにアクセスできます。

オーバーライド可能なメソッドと保護されたメソッド

Windows ランタイム型のすべてのメソッドは実質的に仮想です。 仮想メソッドが呼び出されると、その呼び出しが行われるインスタンスの "実行時の型" によって、呼び出す実際のメソッドの実装が決定します。

メソッドは、派生クラスで オーバーライド できます。 インスタンス メソッド宣言に修飾子が overridable 含まれている場合、メソッドは派生クラスによってオーバーライドできます。 派生クラスがオーバーライド可能な基底クラス メソッドを実際にオーバーライドするかどうかは、実装によって決定されます。メタデータには存在しません。 派生クラスが基底クラス内のメソッドを再宣言した場合は、オーバーライドするのではなく、派生クラス メソッドと共に配置される新しいメソッドを宣言します。

インスタンス メソッド宣言に修飾子が protected 含まれている場合、メソッドは派生クラスにのみ表示されます。

イベント

イベント宣言は、クラスがイベント ソースであることを指定するメンバーです。 このようなイベント ソースは、デリゲート (特定のシグネチャを持つメソッド) を実装するすべての受信者に通知を提供します。

キーワードを使用してイベントを event 宣言し、その後にデリゲート型名 (必要なメソッド シグネチャを記述) を続けて、イベントの名前を宣言します。 プラットフォームの既存のデリゲート型を使用するイベントの例を次に示します。

runtimeclass Area
{
    ...
    event Windows.UI.Xaml.WindowSizeChangedEventHandler SizeChanged;
    ...
}

イベント宣言は、ソースにイベント ハンドラーを追加するためにクライアントが呼び出す add メソッドと、クライアントが以前に追加したイベント ハンドラーを削除するために呼び出す remove メソッドという 2 つのメソッドを暗黙的にクラスに追加します。 その他の例を次に示します。

// Instance event with no meaningful payload.
event Windows.Foundation.TypedEventHandler<BasicClass, Object> Changed;

// Instance event with event parameters.
event Windows.Foundation.TypedEventHandler<BasicClass, BasicClassSaveCompletedEventArgs> SaveCompleted;

// Static event with no meaningful payload.
static event Windows.Foundation.EventHandler<Object> ResetOccurred;

// Static event with event parameters.
static event Windows.Foundation.EventHandler<BasicClassDeviceAddedEventArgs> DeviceAdded;

規則により、常に 2 つのパラメーターが Windows ランタイム イベント ハンドラーに渡されます。送信者の ID とイベント引数オブジェクトです。 送信側は、イベントを発生させたオブジェクトです。静的イベントの場合は null です。 イベントに意味のあるペイロードがない場合、イベント引数は値が null の Object です。

代理人

デリゲート型は、特定のパラメーター リストと戻り値の型を持つメソッドを指定します。 イベントの 1 つのインスタンスには、デリゲート型のインスタンスへの任意の数の参照を含めることができます。 宣言は、ランタイム クラスの外部に存在し、キーワードのプレフィックスが付 delegate いている点を除き、通常のメンバー メソッドの宣言と似ています。

デリゲートを使用すると、メソッドを、変数に割り当ててパラメーターとして渡すことができるエンティティとして扱うことができます。 デリゲートは、他の言語で検出された関数ポインターの概念に似ています。 ただし、関数ポインターとは異なり、デリゲートはオブジェクト指向で型セーフです。

プラットフォームから WindowSizeChangedEventHandler デリゲート型を使用しない場合は、独自のデリゲート型を定義できます。

delegate void SizeChangedHandler(Object sender, Windows.UI.Core.WindowSizeChangedEventArgs args);

SizeChangedHandler デリゲート型のインスタンスは、2 つの引数 (ObjectWindowSizeChangedEventArgs) を受け取り、void を返す任意のメソッドを参照できます。 構造体について説明したら、WindowSizeChangedEventArgs パラメーターを独自のイベント引数型に置き換えることもできます。

デリゲートの興味深く便利なプロパティは、参照するメソッドのクラスを知らないか、気にしないという点です。重要なのは、参照先のメソッドにデリゲートと同じパラメーターと戻り値の型があるということです。

必要に応じて、デリゲート宣言 [uuid(...)]に .

HRESULT を返すデリゲートも参照してください。

構造体

構造体は、データ メンバー (フィールド) を含めることができるデータ構造です。 ただし、クラスとは異なり、構造体は値型です。

構造体は、値セマンティクスを持つ小規模なデータ構造に特に便利です。 複素数(座標系内の点)は、構造体の良い例です。 小さなデータ構造に対してクラスではなく構造体を使用すると、アプリケーションが実行するメモリ割り当ての数に大きな違いが生じます。

例を使用して、クラスと構造体を対比してみましょう。 クラスとして最初に Point のバージョンを次に示します。

runtimeclass Point
{
    Point(Int32 x, Int32 y);
    Int32 x;
    Int32 y;
}

この C# プログラムは、 Point の 100 個のインスタンスの配列を作成して初期化します。 Point をクラスとして実装すると、101 個の個別のオブジェクトがインスタンス化されます。1 つは配列オブジェクト自体用です。100 Point 要素ごとに 1 つ。

class Test
{
    static Test()
    {
        Point[] points = new Point[100];
        for (Int32 i = 0; i < 100; ++i) points[i] = new Point(i, i);
    }
}

よりパフォーマンスの高い方法は、 クラス の代わりに Point を構造体にすることです。

struct Point
{
    Int32 x;
    Int32 y;
};

これで、1 つのオブジェクト (配列オブジェクト自体) のみがインスタンス化されます。 Point 要素は配列内の行に格納されます。プロセッサ キャッシュが強力な効果を発揮するために使用できるメモリの配置。

構造体を変更することは、バイナリ破壊的変更です。 そのため、Windows 自体の一部として実装された構造体は、導入後は変更されません。

インターフェイス

インターフェイスは、クラスによって実装できるコントラクトを定義 します 。 インターフェイスには、クラスと同様に、メソッド、プロパティ、イベントを含めることができます。

クラスとは異なり、インターフェイスは定義するメンバーの実装を提供しません。 インターフェイスを実装する任意のクラスによって提供される必要があるメンバーを指定するだけです。

インターフェイスには、他のインターフェイスも実装するためにインターフェイスを実装するクラスが 必要 な場合があります。 次の例では、 IComboBox インターフェイスでは、 IComboBox を実装するすべてのクラスが、 ITextBoxIListBox の両方も実装する必要があります。 さらに、 IComboBox を実装するクラスは 、IControl も実装する必要があります。 これは、 ITextBoxIListBox の両方で必要 になるためです

interface IControl
{
    void Paint();
}

interface ITextBox requires IControl
{
    void SetText(String text);
}

interface IListBox requires IControl
{
    void SetItems(String[] items);
}

interface IComboBox requires ITextBox, IListBox
{
    ...
}

クラスは、0 個以上のインターフェイスを実装できます。 次の例では、 EditBox クラスは IControl と IDataBound の両方 実装しています。

interface IDataBound
{
    void Bind(Binder b);
}

runtimeclass EditBox : IControl, IDataBound
{
}

Windows プラットフォームのWindows ランタイム型の場合、これらの型を使用する開発者がインターフェイスを実装することが期待される場合は、インターフェイスが定義されます。 インターフェイスを定義するためのもう 1 つのユース ケースは、複数のランタイム クラスがインターフェイスを実装し、それらのランタイム クラスを使用する開発者が、その共通インターフェイスを介してさまざまな種類のオブジェクトに一般的に (したがって多形的に) アクセスする場合です。

Note

MIDL 3.0 でキーワードを requires 使用する方法を 2 回考えてください。 これは、特にバージョン管理が考慮されている場合に、乱雑な設計につながる可能性があります。

列挙型

列挙型 (または列挙型) は、名前付き定数のセットを持つ個別の値型です。 次の例では、 Color という名前の列挙型を定義して使用し、3 つの定数値 ( ) を使用します。

enum Color
{
    Red,
    Green,
    Blue, // Trailing comma is optional, but recommended to make future changes easier.
};

各列挙型には、列挙型の 基になる 型と呼ばれる対応する整数型があります。 列挙型の基になる型は 、Int32 または UInt32 のいずれかです

Windows ランタイムでは、標準列挙型とフラグ列挙型の 2 種類の列挙型がサポートされています。 通常の種類の列挙型は、排他値のセットを表します。フラグの種類の 1 つはブール値のセットを表します。 フラグ列挙型に対してビットごとの演算子を有効にするために、MIDL 3.0 コンパイラは C++ 演算子のオーバーロードを生成します。

フラグ列挙型には属性が [flags] 適用されています。 その場合、列挙型の基になる型は UInt32 です。 属性が [flags] 存在しない場合 (通常の列挙型)、列挙型の基になる型は Int32 です。 列挙型を他の型として宣言することはできません。

[flags]
enum SetOfBooleanValues
{
    None   = 0x00000000,
    Value1 = 0x00000001,
    Value2 = 0x00000002,
    Value3 = 0x00000004,
};

列挙型のストレージ形式と使用可能な値の範囲は、基になる型によって決まります。 列挙型が受け取ることができる値のセットは、宣言された列挙型メンバーによって制限されません。

次の例では、基になる型が Int32 である Alignment という名前の列挙型を定義します。

enum Alignment
{
    Left = -1,
    Center = 0,
    Right = 1
};

C および C++ でも同様に、MIDL 3.0 列挙型には、メンバーの値を指定する定数式を含めることができます (上で説明したように)。 各列挙型メンバーの定数値は、列挙型の基になる型の範囲内にある必要があります。 列挙型メンバー宣言で値が明示的に指定されていない場合、メンバーには値 0 が与えられます (列挙型の最初のメンバーの場合)、またはテキストで先行する列挙型メンバーの値に 1 を加算します。

次の例では、基になる型が UInt32 である Permissions という名前の列挙型を定義します。

[flags]
enum Permissions
{
    None = 0x0000,
    Camera = 0x0001,
    Microphone = 0x0002
};

属性

MIDL 3.0 ソース コードの型、メンバー、およびその他のエンティティは、動作の特定の側面を制御する修飾子をサポートします。 たとえば、メソッドのアクセシビリティは、アクセス修飾子を protected 使用して制御されます。 MIDL 3.0 では、ユーザー定義型の宣言情報をプログラム エンティティにアタッチし、メタデータから実行時に取得できるように、この機能を一般化します。

プログラムでは、属性を定義して使用することにより、この追加の宣言情報を指定します。

次の例では 、HelpAttribute 属性を定義します。この属性は、関連するドキュメントへのリンクを提供するためにプログラム エンティティに配置できます。 ご覧のように、属性は基本的に構造体型であるため、コンストラクターを持たず、データ メンバーのみを含みます。

[attributeusage(target_runtimeclass, target_event, target_method, target_property)]
attribute HelpAttribute
{
    String ClassUri;
    String MemberTopic;
}

属性を適用するには、関連付けられた宣言の直前の角かっこ内に、名前と任意の引数を指定します。 属性の名前が属性で終わる場合は、属性が参照されるときに、名前のその部分を省略できます。 たとえば、 HelpAttribute 属性は次のように使用できます。

[Help("https://docs.contoso.com/.../BookSku", "BookSku class")]
runtimeclass BookSku : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
    [Help("https://docs.contoso.com/.../BookSku_Title", "Title method")]
    String Title;
}

同じ属性を複数の宣言に適用するには、属性の後に続くスコープ ブロックを使用します。 つまり、属性の直後に、属性が適用される宣言を囲む中かっこが続きます。

runtimeclass Widget
{
    [Help("https://docs.contoso.com/.../Widget", "Widget members")]
    {
        void Display(String text);
        void Print();
        Single Rate;
    }
}

Windows 自体の一部として実装される属性は、通常、 Windows.Foundation 名前空間にあります。

最初の例に示すように、属性定義で [attributeusage(<target>)] 属性を使用します。 有効なターゲット値はtarget_all、、、target_delegatetarget_enum、、target_eventtarget_fieldtarget_runtimeclasstarget_parametertarget_propertytarget_interfacetarget_methodおよびtarget_structです。 かっこ内に複数のターゲットをコンマで区切って含めることができます。

属性に適用できるその他の属性は[allowmultiple][attributename("<name>")]

パラメーター化された型

次の例では 、エラー MIDL2025: [msg]構文エラー [context]: expecting > or, near ">>".

Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String>> RetrieveCollectionAsync();

代わりに、2 つの > 文字の間にスペースを挿入して、テンプレート終了文字のペアが右シフト演算子として誤って解釈されないようにします。

Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String> > RetrieveCollectionAsync();

次の例では、 エラー MIDL2025: [msg]構文エラー [context]: expecting > or near "[". これは、パラメーター化されたインターフェイスのパラメーター型引数として配列を使用することは無効であるためです。

Windows.Foundation.IAsyncOperation<Int32[]> RetrieveArrayAsync();

ソリューションについては、「 配列を非同期に返す」を参照してください。