C++ および Visual Basic での Windows ランタイム コンポーネントの作成
.NET Framework 4.5 の場合、マネージ コードを使用して独自の Windows ランタイム 型を作成し、Windows ランタイム コンポーネントにパッケージ化できます。C++、JavaScript、Visual Basic、または C# を使用して、Windows ストア アプリ内でコンポーネントを使用できます。この技術情報では、コンポーネントを作成するための規則を示し、Windows ランタイム の .NET Framework サポートのいくつかの面について説明します。一般に、このサポートは .NET Framework のプログラマに対して透過的に設計されています。ただし、JavaScript または C++ で使用するコンポーネントを作成する場合は、これらの言語が Windows ランタイム をサポートする方法の違いに注意する必要があります。
注意
Visual Basic または C# を使用して Windows ストア アプリでのみ使用するコンポーネントを作成する場合や、コンポーネントに Windows ストア コントロールが含まれていない場合は、[Windows ランタイム コンポーネント] テンプレートではなく、[クラス ライブラリ (Windows ストア アプリ)] テンプレートを使用することを検討してください。単純なクラス ライブラリには、より少ない制限があります。
この記事は次のセクションで構成されています。
Windows ランタイム コンポーネントの宣言型
コンポーネントのデバッグ
Windows ランタイム型のマネージ コードへの引き渡し
マネージ型の Windows ランタイムへの引き渡し
配列の引き渡し
オーバーロードされたメソッド
非同期操作
例外のスロー
イベントの宣言と発生
Windows ランタイム コンポーネントの宣言型
内部的には、コンポーネントの Windows ランタイム 型は、Windows ストア アプリケーションで許可されている .NET Framework の機能をすべて使用できます。(詳細については、「Windows ストア アプリ用 .NET の概要」を参照してください。)外部的には、型のメンバーは、パラメーターと戻り値の Windows ランタイム 型のみを公開できます。次の一覧は、Windows ランタイム コンポーネントから公開される .NET Framework 型の制限事項について説明しています。
コンポーネントのすべてのパブリック型とメンバーのフィールド、パラメーター、および戻り値は、Windows ランタイム 型である必要があります。
この制限には、作成した Windows ランタイム 型および Windows ランタイム 自体が提供した型が含まれます。また、さまざまな .NET Framework の型も含まれます。これらの型の追加は、マネージ コードでの Windows ランタイム の自然な使用を有効にするために .NET Framework が提供するサポートの一部です。コードは基になる Windows ランタイム 型の代わりに、使い慣れた .NET Framework の型を使用しているようです。たとえば、Int32 や Double などの .NET Framework のプリミティブ型、DateTimeOffset や Uri などの特定の基本型、および IEnumerable<T> (Visual Basic の IEnumerable(Of T)) や IDictionary<TKey,TValue> などのよく使用されるジェネリック インターフェイスを使用できます。(これらのジェネリック型の型引数は Windows ランタイム 型にする必要があることに注意してください。)これは、この技術情報の「Windows ランタイム型のマネージ コードへの引き渡し」と「マネージ型の Windows ランタイムへの引き渡し」で後述されます。
パブリック クラスとインターフェイスには、メソッド、プロパティ、およびイベントを含めることができます。イベントのデリゲートを宣言するか、EventHandler<T> のデリゲートを使用します。パブリック クラスまたはインターフェイスでは次ができません。
ジェネリックである。
Windows ランタイム インターフェイスではないインターフェイスを実装する (ただし、独自の Windows ランタイム インターフェイスを作成し、それを実装することはできます。)
System.Exception や System.EventArgs など、Windows ランタイム にない型から派生させる。
すべてのパブリック型にはアセンブリ名に一致するルート名前空間が必要で、アセンブリ名は「Windows」から始めることはできません。
注意
既定では、Visual Studio プロジェクトにはアセンブリ名に一致する名前空間名があります。Visual Basic では、この既定の名前空間の Namespace ステートメントはコードに表示されません。
パブリック構造体はパブリック フィールド以外のメンバーを持つことができません。また、それらのフィールドは値の型または文字列である必要があります。
パブリック クラスは sealed (Visual Basic の NotInheritable) である必要があります。プログラミング モデルがポリモーフィズムを必要とする場合は、パブリック インターフェイスを作成し、ポリモーフィックである必要があるそのインターフェイスをクラスで実装できます。
コンポーネントのデバッグ
Windows ストア アプリケーションとコンポーネントの両方がマネージ コードで作成された場合、それらを同時にデバッグできます。
C++ を使用して Windows ストア アプリケーションの一部としてコンポーネントをテストしている場合、マネージ コードとネイティブ コードを同時にデバッグできます。既定値はネイティブ コードのみです。
ネイティブ C++ コードとマネージ コードをデバッグする方法
Visual C++ プロジェクトのショートカット メニューを開き、[プロパティ] をクリックします。
プロパティ ページで、[構成プロパティ] の [デバッグ] をクリックします。
[デバッガーの種類] を選択し、ドロップダウン リスト ボックスで、[ネイティブのみ] を [混合 (マネージとネイティブ)] に変更します。[OK] をクリックします。
ネイティブ コードとマネージ コードのブレークポイントを設定します。
JavaScript を使用して Windows ストア アプリケーションの一部としてコンポーネントをテストしている場合、既定でソリューションは JavaScript デバッグ モードになります。Visual Studio 2012 と Visual Studio Express 2012 for Windows 8 では、JavaScript とマネージ コードを同時にデバッグすることはできません。
マネージ コードを JavaScript の代わりにデバッグするには
JavaScript プロジェクトのショートカット メニューを開き、[プロパティ] をクリックします。
プロパティ ページで、[構成プロパティ] の [デバッグ] をクリックします。
[デバッガーの種類] を選択し、ドロップダウン リスト ボックスで、[スクリプトのみ] を [マネージのみ)] に変更します。[OK] をクリックします。
マネージ コードのブレークポイントを設定し、通常どおりにデバッグします。
Windows ランタイム 型のマネージ コードへの引き渡し
「Windows ランタイム コンポーネントの宣言型」セクションで説明したように、特定の .NET Framework の型はパブリック クラスのメンバーのシグニチャに現れる場合があります。これはマネージ コードで Windows ランタイム の自然な使用を有効にするために .NET Framework が提供するサポートの一部です。これには、プリミティブ型と一部のクラスやインターフェイスが含まれます。コンポーネントが JavaScript または C++ コードから使用された場合、.NET Framework の型が呼び出し元にどのように表示されるかを理解することが重要です。JavaScript の例については「チュートリアル : C# または Visual Basic での単純なコンポーネントの作成および JavaScript による呼び出し」を参照してください。ここでは、よく使用される型について説明します。
.NET Framework では、Int32 構造体などのプリミティブ型には、TryParse メソッドなどの便利なプロパティとメソッドが多くあります。一方、Windows ランタイム のプリミティブ型と構造体にはフィールドしかありません。これらの型をマネージ コードに渡すと、.NET Framework の型のように表示され、通常どおりに .NET Framework のプロパティとメソッドを使用できます。次の一覧は、IDE で自動的に行われる代替の概要を示しています。
Windows ランタイム のプリミティブ Int32、Int64、Single、Double、Boolean、String (Unicode 文字の変更できないコレクション)、Enum、UInt32、UInt64、および Guid については、System 名前空間と同じ名前の型を使用します。
UInt8 では、System.Byte を使用します。
Char16 では、System.Char を使用します。
IInspectable インターフェイスでは、System.Object を使用します。
C# または Visual Basic がこれらの型のいずれかに言語のキーワードを提供する場合、代わりに言語キーワードを使用できます。
プリミティブ型に加えて、.NET Framework の同等として、よく使用される基本的な Windows ランタイム 型がマネージ コードに表示されます。たとえば、JavaScript コードが Windows.Foundation.Uri クラスを使用しており、それを C# または Visual Basic メソッドに渡したいとします。マネージ コードの等価の型は .NET Framework の System.Uri クラスで、この型をメソッド パラメーターに使用します。マネージ コードを記述すると、Visual Studio の IntelliSense が Windows ランタイム 型を非表示にし、等価の .NET Framework の型を表示するため、Windows ランタイム 型が .NET Framework の型として表示されていることがわかります。(通常、2 つの型の名前は同じです。ただし、Windows.Foundation.DateTime の構造体は、System.DateTime ではなく、System.DateTimeOffset としてマネージ コードに表示される点に注意してください。)
ある一般的に使用されるコレクション型の場合、マッピングは、Windows ランタイム 型によって実装されるインターフェイスおよび対応する .NET Framework の型によって実装されるインターフェイスとの間となります。前述した型のように、.NET Framework の型を使用してパラメーターの型を宣言する必要があります。これにより、型との一部の違いが明らかにならず .NET Framework コードの記述がより自然になります。次の表は、最も一般的なジェネリック インターフェイスの型および他の一般的なクラスとインターフェイス マップを示しています。.NET Framework がマップする Windows ランタイム 型のリストについては、「.NET Framework での Windows ランタイム型の対応付け」を参照してください。
Windows ランタイム |
.NET Framework |
---|---|
IIterable<T> |
IEnumerable<T> |
IVector<T> |
IList<T> |
IVectorView<T> |
IReadOnlyList<T> |
IMap<K, V> |
IDictionary<TKey, TValue> |
IMapView<K, V> |
IReadOnlyDictionary<TKey, TValue> |
IKeyValuePair<K, V> |
KeyValuePair<TKey, TValue> |
IBindableIterable |
IEnumerable |
IBindableVector |
IList |
Windows.UI.Xaml.Data.INotifyPropertyChanged |
System.ComponentModel.INotifyPropertyChanged |
Windows.UI.Xaml.Data.PropertyChangedEventHandler |
System.ComponentModel.PropertyChangedEventHandler |
Windows.UI.Xaml.Data.PropertyChangedEventArgs |
System.ComponentModel.PropertyChangedEventArgs |
型が複数のインターフェイスを実装すると、メンバーのパラメーターの型または戻り値の型として実装するいずれのインターフェイスも使用できます。たとえば、Dictionary<int, string> (Visual Basic の Dictionary(Of Integer, String)) を、IDictionary<int, string>、IReadOnlyDictionary<int, string>、または IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>> として渡すか返すことができます。
重要
JavaScript は、マネージ型が実装するインターフェイスのリストに最初に示されるインターフェイスを使用します。たとえば、JavaScript コードに Dictionary<int, string> を返した場合、戻り値の型としてどのインターフェイスを指定しても IDictionary<int, string> として表示されます。これは、後のインターフェイスに表示されるメンバーが最初のインターフェイスに含まれていない場合、そのメンバーは JavaScript に参照されないことを意味します。
Windows ランタイム では、IMap<K, V> と IMapView<K, V> は IKeyValuePair を使用して反復されます。それらをマネージ コードに渡すと、IDictionary<TKey, TValue> および IReadOnlyDictionary<TKey, TValue> として表示されるため、System.Collections.Generic.KeyValuePair<TKey, TValue> を使用してそれらを列挙します。
インターフェイスがマネージ コード内に表示される方法は、これらのインターフェイスを実装する型の表示方法に影響します。たとえば、PropertySet クラスは IMap<K, V> を実装しますが、これはマネージ コードでは IDictionary<TKey, TValue> として表示されます。PropertySet では、IMap<K, V> ではなく IDictionary<TKey, TValue> が実装されたように見えるため、マネージ コードでは .NET Framework ディクショナリの Add メソッドのように動作する Add メソッドがあるように表示されます。Insert メソッドがないように見えます。この例については、技術情報の「チュートリアル : C# または Visual Basic での単純なコンポーネントの作成および JavaScript による呼び出し」で確認できます。
マネージ型の Windows ランタイム への引き渡し
前のセクションで説明したように、一部の Windows ランタイム 型は、コンポーネントのメンバーのシグニチャ内、または IDE で使用する場合は Windows ランタイム メンバーのシグニチャ内で、.NET Framework 型として表示される場合があります。これらのメンバーに .NET Framework 型を渡すか、またはコンポーネントのメンバーの戻り値として使用すると、Windows ランタイム の対応する型として反対側のコードに表示されます。コンポーネントが JavaScript から呼び出されたときの影響に関する例については、「チュートリアル : C# または Visual Basic での単純なコンポーネントの作成および JavaScript による呼び出し」の「コンポーネントからマネージ型を返す」セクションを参照してください。
配列の引き渡し
Windows ランタイム では、すべてのパラメーターは入力または出力用です。ref パラメーター (Visual Basic の ByRef) はありません。Windows ランタイム コンポーネントに渡される配列の内容は、入力または出力を想定している必要があります。つまり、配列は変更可能として処理できません。配列が値 (Visual Basic の ByVal) として渡される場合、インテントを確立するために ReadOnlyArrayAttribute 属性または WriteOnlyArrayAttribute の属性を適用する必要があります。「Windows ランタイム コンポーネントへの配列の引き渡し」を参照してください。
オーバーロードされたメソッド
Windows ランタイム では、メソッドはオーバーロードできます。ただし、同じ数のパラメーターで複数のオーバーロードを宣言する場合、これらのオーバーロードの 1 だけに Windows.Foundation.Metadata.DefaultOverloadAttribute 属性を適用する必要があります。これは JavaScript から呼び出せる唯一のオーバーロードです。たとえば、次のコードでは、int (Visual Basic の Integer) を取るオーバーロードは既定のオーバーロードです。
public string OverloadExample(string s)
{
return s;
}
[Windows.Foundation.Metadata.DefaultOverload()]
public int OverloadExample(int x)
{
return x;
}
Public Function OverloadExample(ByVal s As String) As String
Return s
End Function
<Windows.Foundation.Metadata.DefaultOverload> _
Public Function OverloadExample(ByVal x As Integer) As Integer
Return x
End Function
注意
JavaScript では任意の値を OverloadExample に渡すことができ、パラメーターに必要な値を型に強制します。OverloadExample を "forty-two"、"42"、または 42.3 として呼び出せますが、それらの値はすべて既定のオーバーロードに渡されます。前の例の既定のオーバーロードは、0、42、および 42 をそれぞれ返します。
DefaultOverloadAttribute 属性をコンストラクターには適用できません。クラスのすべてのコンストラクターには、異なる数のパラメーターが必要です。
非同期操作
コンポーネントに非同期メソッドを実装するには、「Async」をメソッド名の末尾に追加し、非同期アクションまたは操作を表す Windows ランタイム インターフェイスの次のいずれかを返します。IAsyncAction、IAsyncActionWithProgress<TProgress>、IAsyncOperation<TResult>、または IAsyncOperationWithProgress<TResult, TProgress> です。
.NET Framework タスク (Task クラスとジェネリック Task<TResult> クラス) を使用して、非同期メソッドを実装できます。C# または Visual Basic で記述された非同期メソッドから返されるタスク、Task.Run メソッドから返されたタスクなど、進行中の操作を表すタスクを返す必要があります。コンストラクターを使用してタスクを作成する場合、その Task.Start メソッドを呼び出してから戻す必要があります。
await (Visual Basic の Await) を使用するメソッドは async キーワード (Visual Basic の Async) が必要です。Windows ランタイム コンポーネントからそのようなメソッドを公開する場合、Run メソッドに渡すデリゲートに async キーワードを適用します。
キャンセルまたは進行状況レポートをサポートしない非同期アクションや操作については、適切なインターフェイスにタスクをラップするために WindowsRuntimeSystemExtensions.AsAsyncAction または AsAsyncOperation<TResult> の拡張メソッドを使用できます。たとえば、次のコードはタスクを開始するために Task.Run メソッドを使用して、非同期メソッドを実装します。AsAsyncOperation<TResult> 拡張メソッドは、タスクを Windows ランタイム の非同期操作として返します。
public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
{
return Task.Run<IList<string>>(async () =>
{
var data = await DownloadDataAsync(id);
return ExtractStrings(data);
}).AsAsyncOperation();
}
Public Shared Function DownloadAsStringsAsync(ByVal id As String) _
As IAsyncOperation(Of IList(Of String))
Return Task.Run(Of IList(Of String))(
Async Function()
Dim data = Await DownloadDataAsync(id)
Return ExtractStrings(data)
End Function).AsAsyncOperation()
End Function
次の JavaScript コードは、WinJS.Promise オブジェクトを使用してメソッドを呼び出す方法を示します。then メソッドに渡される関数は、非同期呼び出しが完了したときに実行されます。stringList パラメーターには DownloadAsStringAsync メソッドによって返される文字列のリストが含まれ、関数は必要な処理を実行します。
function asyncExample(id) {
var result = SampleComponent.Example.downloadAsStringAsync(id).then(
function (stringList) {
// Place code that uses the returned list of strings here.
});
}
キャンセルまたは進行状況レポートをサポートする非同期アクションおよび操作では、開始されたタスクを生成して、適切な Windows ランタイム インターフェイスのキャンセル機能と進行状況レポート機能を持つタスクのキャンセル機能と進行状況レポート機能をフックするために AsyncInfo クラスを使用します。キャンセルと進行状況レポートの両方をサポートする例については、「チュートリアル : C# または Visual Basic での単純なコンポーネントの作成および JavaScript による呼び出し」を参照してください。
非同期メソッドがキャンセルまたは進行状況レポートをサポートしていない場合でも、AsyncInfo クラスのメソッドを使用できることに注意してください。Visual Basic のラムダ関数または C# の匿名メソッドを使用する場合、トークンと IProgress<T> インターフェイスのパラメーターを指定しないでください。C# ラムダ関数を使用する場合、トークン パラメーターを提供しますがそれを無視します。AsAsyncOperation<TResult> メソッドを使用した前の例は、AsyncInfo.Run<TResult>(Func<CancellationToken, Task<TResult>>) メソッド オーバーロードを代用すると次のようになります。
public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
{
return AsyncInfo.Run<IList<string>>(async (token) =>
{
var data = await DownloadDataAsync(id);
return ExtractStrings(data);
});
}
Public Function OverloadExample(ByVal s As String) As String
Return s
End Function
<Windows.Foundation.Metadata.DefaultOverload> _
Public Function OverloadExample(ByVal x As Integer) As Integer
Return x
End Function
オプションでキャンセルまたは進行状況レポートをサポートする非同期メソッドを作成する場合、キャンセル トークンまたは IProgress<T> インターフェイスのパラメーターがないオーバーロードを追加することを検討してください。
例外のスロー
Windows ストア アプリ用 .NET - サポートされる API に含まれる任意の例外の型をスローできます。Windows ランタイム コンポーネントで独自のパブリック例外型を宣言することはできませんが、非パブリック型を宣言し、スローすることができます。
コンポーネントが例外を処理しない場合は、コンポーネントを呼び出したコードに対応する例外が発生します。例外が呼び出し元に表示される方法は、呼び出す言語が Windows ランタイム をサポートする方法によって異なります。
JavaScript では、例外は例外メッセージがスタック トレースで置き換えられたオブジェクトとして表示されます。Visual Studio でアプリケーションをデバッグするときに、デバッガーの例外ダイアログ ボックスに、"WinRT 情報" として元のメッセージ テキストが表示されます。JavaScript コードから元のメッセージ テキストにアクセスすることはできません。
注意
現在、スタック トレースにはマネージ型の例外が含まれますが、トレースを解析して例外の型を確認することはお勧めしません。このセクションで後述するように、代わりに HRESULT 値を使用してください。
C++ では、例外はプラットフォーム例外として表示されます。マネージ例外の HResult プロパティを特定のプラットフォーム例外の HRESULT にマップできる場合は、そのプラットフォーム例外が使用されます。それ以外の場合は、Platform::COMException 例外がスローされます。マネージ例外のメッセージ テキストは、C++ コードでは使用できません。特定のプラットフォーム例外がスローされた場合、その例外の型の既定のメッセージ テキストが表示されます。それ以外の場合は、メッセージ テキストは表示されません。「例外 (C++/CX)」を参照してください。
C# または Visual Basic では、例外は通常のマネージ例外です。
コンポーネントから例外をスローする場合、HResult プロパティの値がコンポーネント固有である非パブリック型の例外をスローすることで、JavaScript または C++ の呼び出し元が例外を処理しやすくすることができます。HRESULT は、JavaScript の呼び出し元では例外オブジェクトの number プロパティから使用でき、C++ の呼び出し元では COMException::HResult プロパティから使用できます。
注意
HRESULT には負の値を使用します。正の値は成功と解釈されるので、JavaScript または C++ の呼び出し元で例外はスローされません。
イベントの宣言と発生
イベントのデータを保持する型を宣言する場合、EventArgs は Windows ランタイム 型ではないので、EventArgs の代わりに Object から派生します。EventHandler<TEventArgs> をイベントの型として使用し、ジェネリック型引数としてイベント引数の型を使用します。イベントは .NET Framework アプリケーションの場合と同様に発生させます。
Windows ランタイム コンポーネントが JavaScript または C++ から使用される場合、イベントはそれらの言語で期待される Windows ランタイム のイベント パターンに従います。C# または Visual Basic からのコンポーネントを使用すると、イベントは通常の .NET Framework のイベントとして表示されます。チュートリアル : C# または Visual Basic での単純なコンポーネントの作成および JavaScript による呼び出し で例が示されています。
カスタム イベント アクセサー (Visual Basic では Custom キーワードでイベントを宣言) を実行する場合、実装で Windows ランタイム のイベント パターンに従う必要があります。「Windows ランタイム コンポーネントのカスタム イベントおよびイベント アクセサー」を参照してください。C# または Visual Basic コードからイベントを処理する場合でも、通常の .NET Framework のイベントとして表示されます。
参照
概念
Windows ストア アプリ用 .NET - サポートされる API
チュートリアル : C# または Visual Basic での単純なコンポーネントの作成および JavaScript による呼び出し
Windows ランタイム コンポーネントのカスタム イベントおよびイベント アクセサー
Windows ランタイム コンポーネントへの配列の引き渡し