C++/WinRT のアジャイル オブジェクト

ほとんどの場合、Windows ランタイム クラスのインスタンスは任意のスレッドからアクセスできます (ほとんどの標準的な C++ オブジェクトと同様)。 このようなWindows ランタイムクラスはアジャイルです。 Windowsに付属する少数のWindows ランタイム クラスのみがアジャイルではありませんが、それらを使用する場合は、スレッド モデルとマーシャリング動作を考慮する必要があります (マーシャリングはアパートメント境界を越えてデータを渡します)。 すべてのWindows ランタイム オブジェクトがアジャイルになるのは適切な既定値であるため、独自の C++/WinRT 型は既定でアジャイルです。

ただし、オプトアウトすることもできます。たとえば、特定のシングル スレッド アパートメント内に、型のオブジェクトを存在させる必要がある魅力的な理由があります。 これは通常、再入要件と関係があります。 しかし、ますます、ユーザー インターフェイス (UI) API でもアジャイル オブジェクトが提供されます。 一般に、機敏性は最も単純で最もパフォーマンスの高いオプションです。 また、アクティブ化ファクトリを実装する場合は、対応するランタイム クラスが存在しない場合でも、アジャイルである必要があります。

Note

Windows ランタイムは COM に基づいています。 COM の用語では、アジャイル クラスは ThreadingModel = Both に登録されます。 COM スレッド モデルとアパートメントの詳細については、「 COM スレッド モデルの概要と使用」を参照してください。

コード例

ランタイム クラスの実装例を使用して、C++/WinRT で機敏性がどのようにサポートされるかを示しましょう。

#include <winrt/Windows.Foundation.h>

using namespace winrt;
using namespace Windows::Foundation;

struct MyType : winrt::implements<MyType, IStringable>
{
    winrt::hstring ToString(){ ... }
};

オプトアウトしていないため、この実装はアジャイルです。 winrt::implements 基本構造体は IAgileObjectIMarshal を実装します。 IMarshal 実装では、CoCreateFreeThreadedMarshaler を使用して、IAgileObject について知らないレガシ コードに適した処理を行います。

このコードは、オブジェクトの機敏性をチェックします。 IUnknown::as の呼び出しでは、myimpl がアジャイルでない場合、例外がスローされます。

winrt::com_ptr<MyType> myimpl{ winrt::make_self<MyType>() };
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.as<IAgileObject>() };

例外を処理するのではなく、 代わりに IUnknown::try_as を呼び出すことができます。

winrt::com_ptr<IAgileObject> iagileobject{ myimpl.try_as<IAgileObject>() };
if (iagileobject) { /* myimpl is agile. */ }

IAgileObject には独自のメソッドがないため、あまり操作できません。 この次のバリアントは、より一般的です。

if (myimpl.try_as<IAgileObject>()) { /* myimpl is agile. */ }

IAgileObjectマーカー インターフェイスです。 IAgileObject に対するクエリの単なる成功または失敗は、そこから取得する情報とユーティリティの範囲です。

アジャイル オブジェクトのサポートをオプトアウトする

winrt::non_agile マーカー構造体をテンプレート引数として基底クラスに渡すことで、アジャイル オブジェクトのサポートをオプトアウトするように明示的に選択できます。

winrt::implements を直接継承する場合。

struct MyImplementation: implements<MyImplementation, IStringable, winrt::non_agile>
{
    ...
}

ランタイム クラスを作成している場合。

struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, winrt::non_agile>
{
    ...
}

可変数パラメーター パック内のどこにマーカー構造体が表示されるかは関係ありません。

機敏性をオプトアウトするかどうかにかかわらず、 IMarshal を自分で実装できます。 たとえば、 winrt::non_agile マーカーを使用して、既定の機敏性の実装を回避し、 IMarshal を自分で実装して、値によるマーシャリング セマンティクスをサポートすることができます。

アジャイル参照 (winrt::agile_ref)

アジャイルではないオブジェクトを使用しているが、アジャイルの可能性があるコンテキストで渡す必要がある場合は、 winrt::agile_ref 構造体テンプレートを使用して、非アジャイル型のインスタンスまたは非アジャイル オブジェクトのインターフェイスへのアジャイル参照を取得する方法があります。

NonAgileType nonagile_obj;
winrt::agile_ref<NonAgileType> agile{ nonagile_obj };

または、 winrt::make_agile ヘルパー関数を使用することもできます。

NonAgileType nonagile_obj;
auto agile{ winrt::make_agile(nonagile_obj) };

どちらの場合も、 agile は別のアパートのスレッドに自由に渡され、そこで使用される可能性があります。

co_await resume_background();
NonAgileType nonagile_obj_again{ agile.get() };
winrt::hstring message{ nonagile_obj_again.Message() };

agile_ref::get 呼び出しは、get が呼び出されるスレッド コンテキスト内で安全に使用できるプロキシを返します。

重要な API