このトピックは、C++/CX プロジェクトのソース コードを、C++/WinRTで同等のプロジェクトに移植する方法を説明するシリーズの最初のトピックです。
プロジェクトで Windows ランタイム C++ テンプレート ライブラリ (WRL)
移植の戦略
C++/CX から C++/WinRT への移植は一般的に簡単です。ただし、並列パターン ライブラリ (PPL) タスクからコルーチンへの移行は例外です。 モデルは異なります。 PPL タスクからコルーチンへの自然な 1 対 1 のマッピングはなく、すべてのケースで動作するコードを機械的に移植する簡単な方法はありません。 移植のこの特定の側面と、2 つのモデル間の相互運用のオプションについては、「非同期の と、C++/WinRT と C++/CX間の相互運用」を参照してください。
開発チームは、非同期コードの移植のハードルを超えると、移植作業の残りの部分は主に機械的であると日常的に報告しています。
1 つのパスでの移植
プロジェクト全体を 1 回のパスで移植できる立場にある場合は、必要な情報に対してのみこのトピックが必要になります (このトピックに続く 相互運用 トピックは必要ありません)。 まず、C++/WinRT プロジェクト テンプレートのいずれかを使用して Visual Studio で新しいプロジェクトを作成することをお勧めします (Visual Studio での C++/WinRTのサポート
または、既存の C++/CX プロジェクトで移植作業を行う場合は、C++/WinRT サポートを追加する必要があります。 これを行う手順については、「C++/CX プロジェクトの作成と C++/WinRT サポートの追加」で説明されています。 移植が完了すると、純粋な C++/CX プロジェクトだったものが純粋な C++/WinRT プロジェクトに変わります。
注
Windows ランタイム コンポーネント プロジェクトがある場合は、1 回のパスでの移植のみが唯一のオプションです。 C++ で記述された Windows ランタイム コンポーネント プロジェクトには、すべての C++/CX ソース コードまたはすべての C++/WinRT ソース コードが含まれている必要があります。 この種類のプロジェクトでは共存できません。
プロジェクトを段階的に移植する
前のセクションで説明したように、Windows ランタイム コンポーネント プロジェクトを除き、コードベースのサイズや複雑さがプロジェクトを徐々に移植する必要がある場合は、C++/CX と C++/WinRT コードが同じプロジェクトに並べて存在する移植プロセスが必要になります。 このトピックの読み方に加えて、C++/WinRT と C++/CX と
段階的な移植プロセスに備えてプロジェクトを準備するには、C++/WinRT のサポートを C++/CX プロジェクトに追加する方法があります。 これを行う手順については、「C++/CX プロジェクトの作成と C++/WinRT サポートの追加」で説明されています。 その後、そこから徐々に移植できます。
もう 1 つのオプションは、C++/WinRT プロジェクト テンプレートのいずれかを使用して Visual Studio で新しいプロジェクトを作成することです (C++/WinRTの Visual Studio のサポート
どちらの場合も、C++/WinRT コードと、まだ移植していない C++/CX コードの間で相互運用 (両方の方法) を行います。
注
C++/CX と Windows SDK の両方
XAML プロジェクトを段階的に移植する
Von Bedeutung
XAML を使用するプロジェクトの場合、すべての XAML ページ型は、常に完全に C++/CX または完全に C++/WinRT である必要があります。 C++/CX と C++/WinRT は、同じプロジェクト内 (モデルやビューモデルなど) 内の XAML ページ型の 外でも混在させることができます。
このシナリオでは、新しい C++/WinRT プロジェクトを作成し、C++/CX プロジェクトからソース コードとマークアップをコピーすることをお勧めします。 すべての XAML ページの種類が C++/WinRT である限り、Project>新しい項目の追加...>Visual C++>空白ページ (C++/WinRT)を使用して新しい XAML ページを追加できます。
または、Windows ランタイム コンポーネント (WRC) を使用して、移植時に XAML C++/CX プロジェクトからコードを要素化することもできます。
- 新しい C++/CX WRC プロジェクトを作成し、できるだけ多くの C++/CX コードをそのプロジェクトに移動してから、XAML プロジェクトを C++/WinRT に変更できます。
- または、新しい C++/WinRT WRC プロジェクトを作成し、XAML プロジェクトを C++/CX のままにして、C++/CX を C++/WinRT に移植し、結果のコードを XAML プロジェクトからコンポーネント プロジェクトに移動することもできます。
- また、C++/CX コンポーネント プロジェクトと C++/WinRT コンポーネント プロジェクトを同じソリューション内に配置し、両方をアプリケーション プロジェクトから参照し、徐々に一方から他方に移植することもできます。 ここでも、同じプロジェクトで 2 つの言語プロジェクションを使用する方法の詳細については、C++/WinRT と C++/CX 間の相互運用の
を参照してください。
C++/CX プロジェクトを C++/WinRT に移植する最初の手順
移植戦略 (1 回のパスでの移植、または段階的な移植) に関係なく、最初の手順は、移植用にプロジェクトを準備することです。 開始するプロジェクトの種類と設定方法の観点から、 を移植するための
- 一回で移植します。 C++/WinRT プロジェクト テンプレートのいずれかを使用して、Visual Studio で新しいプロジェクトを作成します。 C++/CX プロジェクトから新しいプロジェクトにファイルを移動し、C++/CX ソース コードを移植します。
-
XAML 以外のプロジェクトを段階的に移植。 C++/CX プロジェクトに C++/WinRT サポートを追加することを選択できます (C++/CX プロジェクトの作成と C++/WinRT サポートの追加に関する
を参照)、段階的に移植します。 または、新しい C++/WinRT プロジェクトを作成し、C++/CX のサポートを追加することもできます (C++/WinRT プロジェクトの作成と C++/CX サポート の追加に関するを参照)、ファイルを移動し、段階的に移植します。 -
XAML プロジェクトを段階的に移植します。 新しい C++/WinRT プロジェクトを作成し、ファイルを移動し、段階的に移植します。 XAML ページの種類は、常にすべての C++/WinRT
またはすべての C++/CX を する必要があります。
このトピックの残りの部分は、選択した移植方法に関係なく適用されます。 C++/CX から C++/WinRT へのソース コードの移植に関連する技術的な詳細のカタログが含まれています。 段階的に移植する場合は、C++/WinRT と C++/CX の相互運用 や 、および C++/WinRT と C++/CX の Asynchrony との相互運用も参考にすると良いでしょう。
ファイルの名前付け規則
XAML マークアップ ファイル
ファイルの配信元 | C++/CX | C++/WinRT |
---|---|---|
Developer XAML ファイル | MyPage.xaml MyPage.xaml.h MyPage.xaml.cpp |
MyPage.xaml MyPage.h MyPage.cpp MyPage.idl (下記参照) |
生成された XAML ファイル | MyPage.xaml.g.h MyPage.xaml.g.hpp |
MyPage.xaml.g.h MyPage.xaml.g.hpp MyPage.g.h |
C++/WinRT では、.xaml
と *.h
ファイル名から *.cpp
が削除されます。
C++/WinRT は、Midl ファイル (.idl)追加の開発者ファイルを追加します。 C++/CX は、このファイルを自動生成し、各パブリックおよび保護されたメンバーを追加します。 C++/WinRT では、ファイルを自分で追加して作成します。 IDL の作成の詳細、コード例、およびチュートリアルについては、XAML コントロール 参照してください。C++/WinRT プロパティにバインドします。
ランタイム クラスを Midl ファイル (.idl) に分解する も参照してください。
ランタイム クラス
C++/CX では、ヘッダー ファイルの名前に制限はありません。複数のランタイム クラス定義を 1 つのヘッダー ファイル (特に小規模なクラスの場合) に配置するのが一般的です。 ただし、C++/WinRT では、各ランタイム クラスに、クラス名にちなんだ独自のヘッダー ファイルが必要です。
C++/CX | C++/WinRT |
---|---|
Common.href class A { ... } ref class B { ... } |
Common.idlruntimeclass A { ... } runtimeclass B { ... } |
A.hnamespace implements { struct A { ... }; } |
|
B.hnamespace implements { struct B { ... }; } |
C++/CX では、XAML カスタム コントロールに異なる名前のヘッダー ファイルを使用することはあまり一般的ではありません (ただし、まだ有効です)。 クラス名と一致するように、これらのヘッダー ファイルの名前を変更する必要があります。
C++/CX | C++/WinRT |
---|---|
A.xaml <Page x:Class="LongNameForA" ...> |
A.xaml <Page x:Class="LongNameForA" ...> |
A.hpartial ref class LongNameForA { ... } |
LongNameForA.hnamespace implements { struct LongNameForA { ... }; } |
ヘッダー ファイルの要件
C++/CX では、.winmd
ファイルからヘッダー ファイルが内部的に自動生成されるため、特別なヘッダー ファイルを含める必要はありません。 C++/CX では、名前で使用する名前空間に using
ディレクティブを使用するのが一般的です。
using namespace Windows::Media::Playback;
String^ NameOfFirstVideoTrack(MediaPlaybackItem^ item)
{
return item->VideoTracks->GetAt(0)->Name;
}
using namespace Windows::Media::Playback
ディレクティブを使用すると、名前空間プレフィックスなしで MediaPlaybackItem
を記述できます。
ただし、C++/WinRT では、名前を付けない場合でも、使用する各名前空間に対応するヘッダー ファイルを含める必要があります。
#include <winrt/Windows.Media.Playback.h>
#include <winrt/Windows.Media.Core.h> // !!This is important!!
using namespace winrt;
using namespace Windows::Media::Playback;
winrt::hstring NameOfFirstVideoTrack(MediaPlaybackItem const& item)
{
return item.VideoTracks().GetAt(0).Name();
}
一方、MediaPlaybackItem.AudioTracksChanged イベントは、TypedEventHandler<MediaPlaybackItem、Windows.Foundation.Collections.IVectorChangedEventArgs>の種類ですが、そのイベントを使用していないため、winrt/Windows.Foundation.Collections.h
を含める必要はありません。
C++/WinRT では、XAML マークアップによって使用される名前空間のヘッダー ファイルも含める必要があります。
<!-- MainPage.xaml -->
<Rectangle Height="400"/>
Rectangle クラスを使用すると、このインクルードを追加する必要があります。
// MainPage.h
#include <winrt/Windows.UI.Xaml.Shapes.h>
ヘッダー ファイルを忘れた場合、すべてが正常にコンパイルされますが、consume_
クラスがないため、リンカー エラーが発生します。
パラメーターの受け渡し
C++/CX ソース コードを記述するときは、関数パラメーターとして C++/CX 型をハット (^) 参照として渡します。
void LogPresenceRecord(PresenceRecord^ record);
C++/WinRT では、同期関数の場合、既定で const&
パラメーターを使用する必要があります。 これによって、コピーとインターロックのオーバーヘッドが回避されます。 ただし、コルーチンでは、値渡しを使用して値によってキャプチャし、有効期間の問題を回避する必要があります (詳細については、C++/WinRTでのコンカレンシーと非同期操作、を参照してください)。
void LogPresenceRecord(PresenceRecord const& record);
IASyncAction LogPresenceRecordAsync(PresenceRecord const record);
C++/WinRT オブジェクトは、基本的には、バッキング Windows ランタイム オブジェクトへのインターフェイス ポインターを保持する値です。 C++/WinRT オブジェクトをコピーすると、コンパイラはカプセル化されたインターフェイス ポインターをコピーし、その参照カウントをインクリメントします。 コピーを最終的に破棄するには、参照カウントをデクリメントする必要があります。 そのため、必要な場合にのみコピーのオーバーヘッドが発生します。
変数とフィールドの参照
C++/CX ソース コードを記述するときは、Hat (^) 変数を使用して Windows ランタイム オブジェクトを参照し、矢印 (->) 演算子を使用してハット変数を逆参照します。
IVectorView<User^>^ userList = User::Users;
if (userList != nullptr)
{
for (UINT32 iUser = 0; iUser < userList->Size; ++iUser)
...
同等の C++/WinRT コードに移植する場合は、帽子を削除し、矢印演算子 (->) をドット演算子 (..) に変更することで、長い道のりを得ることができます。 C++/WinRT 投影型は値であり、ポインターではありません。
IVectorView<User> userList = User::Users();
if (userList != nullptr)
{
for (UINT32 iUser = 0; iUser < userList.Size(); ++iUser)
...
C++/CX Hat 参照の既定のコンストラクターは、それを null に初期化します。 正しい型の変数/フィールドを作成する C++/CX コード例を次に示しますが、初期化されていません。 つまり、最初は TextBlockを参照していません。後で参照を割り当てる予定です。
TextBlock^ textBlock;
class MyClass
{
TextBlock^ textBlock;
};
C++/WinRT での同等の機能については、「遅延初期化
特性
C++/CX 言語拡張機能には、プロパティの概念が含まれています。 C++/CX ソース コードを記述する場合は、フィールドであるかのようにプロパティにアクセスできます。 標準 C++ にはプロパティの概念がないため、C++/WinRT では get 関数と set 関数を呼び出します。
次の例では、XboxUserId、UserState、PresenceDeviceRecords、および Size はいずれもプロパティです。
プロパティからの値の取得
C++/CX でプロパティ値を取得する方法を次に示します。
void Sample::LogPresenceRecord(PresenceRecord^ record)
{
auto id = record->XboxUserId;
auto state = record->UserState;
auto size = record->PresenceDeviceRecords->Size;
}
同等の C++/WinRT ソース コードは、プロパティと同じ名前の関数を呼び出しますが、パラメーターはありません。
void Sample::LogPresenceRecord(PresenceRecord const& record)
{
auto id = record.XboxUserId();
auto state = record.UserState();
auto size = record.PresenceDeviceRecords().Size();
}
PresenceDeviceRecords 関数は、Size 関数を持つ Windows ランタイム オブジェクトを返します。 返されるオブジェクトも C++/WinRT 投影型であるため、ドット演算子を使用して Sizeを呼び出して逆参照します。
プロパティを新しい値に設定する
プロパティを新しい値に設定すると、同様のパターンに従います。 まず、C++/CX で。
record->UserState = newValue;
C++/WinRT で同等の操作を行うには、プロパティと同じ名前の関数を呼び出し、引数を渡します。
record.UserState(newValue);
クラスのインスタンスの作成
C++/CX オブジェクトは、そのハンドル (一般に帽子 (^) 参照と呼ばれます) を介して操作します。
using namespace Windows::Storage::Streams;
class Sample
{
private:
Buffer^ m_gamerPicBuffer = ref new Buffer(MAX_IMAGE_SIZE);
};
C++/WinRT オブジェクトは値です。スタックに割り当てることもできますし、オブジェクトのフィールドとして割り当てることもできます。
using namespace winrt::Windows::Storage::Streams;
struct Sample
{
private:
Buffer m_gamerPicBuffer{ MAX_IMAGE_SIZE };
};
リソースの初期化にコストがかかる場合は、実際に必要になるまで初期化を遅らせるのが一般的です。 既に説明したように、C++/CX Hat 参照の既定のコンストラクターは null に初期化します。
using namespace Windows::Storage::Streams;
class Sample
{
public:
void DelayedInit()
{
// Allocate the actual buffer.
m_gamerPicBuffer = ref new Buffer(MAX_IMAGE_SIZE);
}
private:
Buffer^ m_gamerPicBuffer;
};
C++/WinRT に移植されたのと同じコード。
std::nullptr_t コンストラクターの使用に注意してください。 そのコンストラクターの詳細については、「遅延初期化
using namespace winrt::Windows::Storage::Streams;
struct Sample
{
void DelayedInit()
{
// Allocate the actual buffer.
m_gamerPicBuffer = Buffer(MAX_IMAGE_SIZE);
}
private:
Buffer m_gamerPicBuffer{ nullptr };
};
既定のコンストラクターがコレクションに与える影響
C++ コレクション型では既定のコンストラクターが使用されるため、意図しないオブジェクトの構築が発生する可能性があります。
シナリオ | C++/CX | C++/WinRT (正しくない) | C++/WinRT (正しい) |
---|---|---|---|
ローカル変数(最初は空) | TextBox^ textBox; |
TextBox textBox; // Creates a TextBox! |
TextBox textBox{ nullptr }; |
メンバー変数 (最初は空) | class C { TextBox^ textBox; }; |
class C { TextBox textBox; // Creates a TextBox! }; |
class C { TextBox textbox{ nullptr }; }; |
グローバル変数(最初は空) | TextBox^ g_textBox; |
TextBox g_textBox; // Creates a TextBox! |
TextBox g_textBox{ nullptr }; |
空の参照のベクトル | std::vector<TextBox^> boxes(10); |
// Creates 10 TextBox objects! std::vector<TextBox> boxes(10); |
std::vector<TextBox> boxes(10, nullptr); |
マップで値を設定する | std::map<int, TextBox^> boxes; boxes[2] = value; |
std::map<int, TextBox> boxes; // Creates a TextBox at 2, // then overwrites it! boxes[2] = value; |
std::map<int, TextBox> boxes; boxes.insert_or_assign(2, value); |
空の参照の配列 | TextBox^ boxes[2]; |
// Creates 2 TextBox objects! TextBox boxes[2]; |
TextBox boxes[2] = { nullptr, nullptr }; |
ペア | std::pair<TextBox^, String^> p; |
// Creates a TextBox! std::pair<TextBox, String> p; |
std::pair<TextBox, String> p{ nullptr, nullptr }; |
空の参照コレクションについての詳細
C++/CX で Platform::Array^ (Port Platform::Array^を参照) がある場合は、それを配列として残すのではなく、C++/WinRT (実際には任意の連続したコンテナー) の std::vector に移植するかを選択できます。 std::vector
たとえば、空の参照の固定サイズのベクターを作成するための短縮形はありますが (上の表を参照)、空の参照の nullptr
を繰り返す必要があります。 不足している場合は、余分なものがデフォルトで構築されます。
ベクターの場合は、初期化時に空の参照を入力するか (上の表のように)、初期化後に空の参照を次のようなコードで埋めることができます。
std::vector<TextBox> boxes(10); // 10 default-constructed TextBoxes.
boxes.resize(10, nullptr); // 10 empty references.
std::map 例の詳細
[]
の 添字演算子は、次のように動作します。
- キーがマップ内に見つかった場合は、既存の値への参照を返します (上書きできます)。
- キーがマップに見つからない場合は、キー (移動可能な場合は移動可能) で構成される新しいエントリをマップに作成し、既定で構築された値
し、値への参照を返します (上書きできます)。
つまり、[]
演算子は常にマップにエントリを作成します。 これは、C#、Java、JavaScript とは異なります。
基本ランタイム クラスから派生クラスへの変換
ある型が派生型のオブジェクトに関していることが分かっているベース参照が存在するのは一般的によくあります。 C++/CX では、dynamic_cast
は本当に QueryInterfaceへの隠された呼び出しです。 一般的な例を次に示します。依存関係プロパティの変更イベントを処理しており、DependencyObject
void BgLabelControl::OnLabelChanged(Windows::UI::Xaml::DependencyObject^ d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ e)
{
BgLabelControl^ theControl{ dynamic_cast<BgLabelControl^>(d) };
if (theControl != nullptr)
{
// succeeded ...
}
}
同等の C++/WinRT コードは、
void BgLabelControl::OnLabelChanged(Windows::UI::Xaml::DependencyObject const& d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs const& e)
{
if (BgLabelControlApp::BgLabelControl theControl{ d.try_as<BgLabelControlApp::BgLabelControl>() })
{
// succeeded ...
}
try
{
BgLabelControlApp::BgLabelControl theControl{ d.as<BgLabelControlApp::BgLabelControl>() };
// succeeded ...
}
catch (winrt::hresult_no_interface const&)
{
// failed ...
}
}
派生クラス
ランタイム クラスから派生するには、基底クラスは 構成可能である必要があります。 C++/CX では、クラスを構成可能にするために特別な手順を踏む必要はありませんが、C++/WinRT では特別な手順が必要です。 封印解除キーワード を使用して、クラスが基底クラスとして利用可能であることを示します。
unsealed runtimeclass BasePage : Windows.UI.Xaml.Controls.Page
{
...
}
runtimeclass DerivedPage : BasePage
{
...
}
実装ヘッダー クラスでは、派生クラスの自動生成されたヘッダーを含める前に、基底クラスのヘッダー ファイルを含める必要があります。 それ以外の場合は、"式としてこの型を無効に使用しています" などのエラーが表示されます。
// DerivedPage.h
#include "BasePage.h" // This comes first.
#include "DerivedPage.g.h" // Otherwise this header file will produce an error.
namespace winrt::MyNamespace::implementation
{
struct DerivedPage : DerivedPageT<DerivedPage>
{
...
}
}
デリゲートを使用したイベント処理
この場合、ラムダ関数をデリゲートとして使用して、C++/CX でイベントを処理する一般的な例を次に示します。
auto token = myButton->Click += ref new RoutedEventHandler([=](Platform::Object^ sender, RoutedEventArgs^ args)
{
// Handle the event.
// Note: locals are captured by value, not reference, since this handler is delayed.
});
これは C++/WinRT で同等です。
auto token = myButton().Click([=](IInspectable const& sender, RoutedEventArgs const& args)
{
// Handle the event.
// Note: locals are captured by value, not reference, since this handler is delayed.
});
ラムダ関数の代わりに、デリゲートを無料の関数として実装するか、メンバー関数へのポインターとして実装するかを選択できます。 詳細については、「C++/WinRTでデリゲートを使用してイベントを処理する」を参照してください。
イベントとデリゲートが (バイナリ間ではなく) 内部的に使用される C++/CX コードベースから移植する場合は、winrt::d elegate を
デリゲートの取り消し
C++/CX では、-=
演算子を使用して、以前のイベント登録を取り消します。
myButton->Click -= token;
これは C++/WinRT で同等です。
myButton().Click(token);
詳細とオプションについては、「登録されたデリゲートを取り消す」を参照してください。
ボクシングとアンボクシング
C++/CX では、スカラーがオブジェクトに自動的にボックス化されます。 C++/WinRT では、winrt::box_value 関数を明示的に呼び出す必要があります。 どちらの言語でも、明示的にボックス化を解除する必要があります。 C++/WinRTを使用した
次の表では、これらの定義を使用します。
C++/CX | C++/WinRT |
---|---|
int i; |
int i; |
String^ s; |
winrt::hstring s; |
Object^ o; |
IInspectable o; |
オペレーション | C++/CX | C++/WinRT |
---|---|---|
ボクシング | o = 1; o = "string"; |
o = box_value(1); o = box_value(L"string"); |
開封の儀 | i = (int)o; s = (String^)o; |
i = unbox_value<int>(o); s = unbox_value<winrt::hstring>(o); |
値型への null ポインターのボックス化を解除しようとすると、C++/CX と C# で例外が発生します。 C++/WinRT では、これがプログラミング エラーと見なされ、クラッシュします。 C++/WinRT では、オブジェクトが思った型ではない場合に処理する場合は、winrt::unbox_value_or 関数を使用します。
シナリオ | C++/CX | C++/WinRT |
---|---|---|
既知の整数をアンボックスする | i = (int)o; |
i = unbox_value<int>(o); |
o が null の場合 | Platform::NullReferenceException |
クラッシュ |
o がボックス化された int でない場合 | Platform::InvalidCastException |
クラッシュ |
int をボックス化解除し、null の場合はフォールバックを使用します。それ以外の場合はクラッシュする | i = o ? (int)o : fallback; |
i = o ? unbox_value<int>(o) : fallback; |
可能な場合は int のボックスを解除します。それ以外の場合はフォールバックを使用する | auto box = dynamic_cast<IBox<int>^>(o); i = box ? box->Value : fallback; |
i = unbox_value_or<int>(o, fallback); |
文字列のボックス化と文字列のボックス化解除
文字列は、いくつかの点で値型であり、他の点では参照型です。 C++/CX と C++/WinRT は、文字列を異なる方法で処理します。
ABI 型 HSTRING は、参照カウント文字列へのポインターです。 しかし、それは IInspectableから派生していないため、技術的には オブジェクトではありません。 さらに、null HSTRING は空の文字列を表します。
C++/CX は、参照型として Windows ランタイム文字列を表します。一方、C++/WinRT は文字列を値型として投影します。 つまり、ボックス化された null 文字列は、取得方法に応じて異なる表現を持つことができます。
さらに、C++/CX を使用すると、null String^を逆参照できます。この場合、文字列 ""
のように動作します。
行動 | C++/CX | C++/WinRT |
---|---|---|
宣言 | Object^ o; String^ s; |
IInspectable o; hstring s; |
文字列型カテゴリ | 参照の種類 | 値の種類 |
HSTRING はプロジェクトとして null となる | (String^)nullptr |
hstring{} |
null と "" は同じですか? |
イエス | イエス |
null の有効性 | s = nullptr; s->Length == 0 (有効) |
s = hstring{}; s.size() == 0 (有効) |
null 文字列をオブジェクトに割り当てる場合 | o = (String^)nullptr; o == nullptr |
o = box_value(hstring{}); o != nullptr |
オブジェクトに "" を割り当てる場合 |
o = ""; o == nullptr |
o = box_value(hstring{L""}); o != nullptr |
基本的なボックス化とアンボックス化。
オペレーション | C++/CX | C++/WinRT |
---|---|---|
文字列をボックス化する | o = s; 空の文字列が nullptr になります。 |
o = box_value(s); 空の文字列は null 以外のオブジェクトになります。 |
既知の文字列のボックスを解除する | s = (String^)o; Null オブジェクトが空の文字列になります。 文字列でない場合は、InvalidCastException が発生します。 |
s = unbox_value<hstring>(o); Null オブジェクトがクラッシュします。 文字列でない場合はクラッシュします。 |
可能な文字列のボックス化を解除する | s = dynamic_cast<String^>(o); NULL オブジェクトまたは非文字列は空の文字列になります。 |
s = unbox_value_or<hstring>(o, fallback); Null または非文字列値がフォールバックに適用されます。 空の文字列は保持されます。 |
並行性と非同期処理
並列パターン ライブラリ (PPL) (concurrency::taskなど) が、C++/CX Hat 参照をサポートするように更新されました。
C++/WinRT の場合は、代わりにコルーチンと co_await
を使用する必要があります。 詳細とコード例については、「C++/WinRTを使用したコンカレンシーと非同期操作の
XAML マークアップからのオブジェクトの利用
C++/CX プロジェクトでは、XAML マークアップからプライベート メンバーと名前付き要素を使用できます。 ただし、C++/WinRT では、XAML {x:Bind} マークアップ拡張 を使用して使用されるすべてのエンティティを IDL でパブリックに公開する必要があります。
また、ブール値にバインドすると、C++/CX では
詳細とコード例については、「マークアップからオブジェクトを使用する」を参照してください。
C++/CX プラットフォームの 型を C++/WinRT 型にマッピングする
C++/CX は、Platform 名前空間に複数のデータ型を提供します。 これらの型は標準の C++ ではないため、Windows ランタイム言語拡張機能を有効にした場合にのみ使用できます (Visual Studio プロジェクト プロパティ C/C++>General>Windows ランタイム拡張機能の使用>はい (/ZW))。 次の表は、Platform 型から C++/WinRT の同等の型に移植するのに役立ちます。 これを行うと、C++/WinRT は標準の C++ であるため、/ZW
オプションをオフにすることができます。
C++/CX | C++/WinRT |
---|---|
Platform::Agile^ | winrt::agile_ref |
Platform::Array^ | ポート Platform::Array^ を参照してください |
プラットフォーム::例外^ | winrt::hresult_error |
Platform::InvalidArgumentException^ | winrt::hresult_invalid_argument |
Platform::Object^ | winrt::Windows::Foundation::IInspectable |
Platform::String^ | winrt::hstring |
Platform::Agile^ を winrt::agile_ref に移植する
C++/CX の Platform::Agile^ 型は、任意のスレッドからアクセスできる Windows ランタイム クラスを表します。 C++/WinRT と同等の値は winrt::agile_ref
C++/CX を使用して。
Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
C++/WinRT では
winrt::agile_ref<Windows::UI::Core::CoreWindow> m_window;
Port Platform::Array^
C++/CX で配列を使用する必要がある場合、C++/WinRT では連続する任意のコンテナーを使用できます。 std::vector が適切な理由
したがって、C++/CX で Platform::Array^ がある場合は常に、初期化子リスト、std::array、または std::vectorを使用する移植オプションが含まれます。 詳細とコード例については、「標準初期化子リスト および Standard 配列とベクターを参照してください。
Port Platform::Exception^ を から winrt::hresult_error へポートする
Platform::Exception^ 型は、Windows ランタイム API が非S_OK HRESULT を返すときに C++/CX で生成されます。 C++/WinRT に相当するものは winrt::hresult_error
C++/WinRT に移植するには、Platform::Exception^ を使用するすべてのコード winrt::hresult_errorを使用するように変更します。
C++/CX を使用して。
catch (Platform::Exception^ ex)
C++/WinRT では
catch (winrt::hresult_error const& ex)
C++/WinRT には、これらの例外クラスが用意されています。
例外の種類 | 基本クラス | HRESULT |
---|---|---|
winrt::hresult_error | call hresult_error::to_abi | |
winrt::hresult_access_denied | winrt::hresult_error | E_ACCESSDENIED (アクセス拒否) |
winrt::hresult_canceled | winrt::hresult_error | エラー_キャンセル |
winrt::hresult_changed_state を |
winrt::hresult_error | 状態変更_済み |
winrt::hresult_class_not_available を |
winrt::hresult_error | CLASS_E_CLASSNOTAVAILABLE(クラスが利用できません) |
winrt::hresult_illegal_delegate_assignment を |
winrt::hresult_error | E_ILLEGAL_DELEGATE_ASSIGNMENT |
winrt::hresult_illegal_method_call | winrt::hresult_error | E_ILLEGAL_METHOD_CALL(不正なメソッド呼び出し) |
winrt::hresult_illegal_state_change を |
winrt::hresult_error | E_ILLEGAL_STATE_CHANGE (不正な状態変更) |
winrt::hresult_invalid_argument | winrt::hresult_error | 無効な引数エラー (E_INVALIDARG) |
winrt::hresult_no_interface を する | winrt::hresult_error | E_NOINTERFACE |
winrt::hresult_not_implemented | winrt::hresult_error | E_NOTIMPL |
winrt::hresult_out_of_bounds | winrt::hresult_error | E_BOUNDS |
winrt::hresult_wrong_thread エラー (スレッドの間違い) | winrt::hresult_error | RPC_E_WRONG_THREAD(スレッドが正しくありません) |
各クラス (hresult_error 基底クラスを介して) には、エラーの HRESULT を返す to_abi 関数と、その HRESULT の文字列表現を返す メッセージ 関数が用意されていることに注意してください。
C++/CX で例外をスローする例を次に示します。
throw ref new Platform::InvalidArgumentException(L"A valid User is required");
C++/WinRT での同等のものも含まれます。
throw winrt::hresult_invalid_argument{ L"A valid User is required" };
の Platform::Object^ を の winrt::Windows::Foundation::IInspectable に変換する
すべての C++/WinRT 型と同様に、winrt::Windows::Foundation::IInspectable は値型です。 その型の変数を null に初期化する方法を次に示します。
winrt::Windows::Foundation::IInspectable var{ nullptr };
Port Platform::String^ を winrt::hstring にする
Platform::String^ は、Windows ランタイム HSTRING ABI 型と同じです。 C++/WinRT の場合、同等の winrt::hstringです。 ただし、C++/WinRT では、std::wstring、ワイド文字列リテラルなどの C++ 標準ライブラリのワイド文字列型を使用して Windows ランタイム API を呼び出すことができます。 詳細とコード例については、「C++/WinRTでの
C++/CX を使用すると、Platform::String::D ata プロパティにアクセスして、文字列を C スタイルの const wchar_t* 配列として取得できます (たとえば、std::wcoutに渡します)。
auto var{ titleRecord->TitleName->Data() };
C++/WinRT で同じ操作を行うには、
auto var{ titleRecord.TitleName().c_str() };
文字列を取得または返す API の実装に関しては、通常、
文字列を受け取る C++/CX API の例を次に示します。
void LogWrapLine(Platform::String^ str);
C++/WinRT の場合、MIDL 3.0 の API は次のように 宣言できます。
// LogType.idl
void LogWrapLine(String str);
その後、C++/WinRT ツールチェーンによって、次のようなソース コードが生成されます。
void LogWrapLine(winrt::hstring const& str);
ToString()
C++/CX 型は、Object::ToString メソッドを提供します。
int i{ 2 };
auto s{ i.ToString() }; // s is a Platform::String^ with value L"2".
C++/WinRT では、この機能は直接提供されませんが、代替手段に変えることができます。
int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".
C++/WinRT では、限られた数の型 winrt::to_hstringもサポートされています。 追加の型を文字列化するために、オーバーロードを追加する必要があります。
言語 | 整数を文字列に変換する | 列挙型を文字列化する |
---|---|---|
C++/CX | String^ result = "hello, " + intValue.ToString(); |
String^ result = "status: " + status.ToString(); |
C++/WinRT | hstring result = L"hello, " + to_hstring(intValue); |
// must define overload (see below) hstring result = L"status: " + to_hstring(status); |
列挙型を文字列化する場合は、winrt::to_hstringの実装を提供する必要があります。
namespace winrt
{
hstring to_hstring(StatusEnum status)
{
switch (status)
{
case StatusEnum::Success: return L"Success";
case StatusEnum::AccessDenied: return L"AccessDenied";
case StatusEnum::DisabledByPolicy: return L"DisabledByPolicy";
default: return to_hstring(static_cast<int>(status));
}
}
}
これらの文字列化は、多くの場合、データ バインディングによって暗黙的に使用されます。
<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>
これらのバインディングは、バインドされたプロパティ winrt::to_hstring を実行します。 2 番目の例 (
文字列構築
C++/CX と C++/WinRT は文字列の構築のために標準ライブラリの std::wstringstream を利用します。
オペレーション | C++/CX | C++/WinRT |
---|---|---|
文字列を追加し、null を保持する | stream.print(s->Data(), s->Length); |
stream << std::wstring_view{ s }; |
文字列を追加し、最初の null で停止する | stream << s->Data(); |
stream << s.c_str(); |
結果の抽出 | ws = stream.str(); |
ws = stream.str(); |
その他の例
次の例では、ws
オペレーション | C++/CX | C++/WinRT |
---|---|---|
リテラルから文字列を構築する | String^ s = "hello"; String^ s = L"hello"; |
// winrt::hstring s{ "hello" }; // Doesn't compile winrt::hstring s{ L"hello" }; |
std::wstring をに変換し、null を保持する | String^ s = ref new String(ws.c_str(), (uint32_t)ws.size()); |
winrt::hstring s{ ws }; s = winrt::hstring(ws); // s = ws; // Doesn't compile |
std::wstring |
String^ s = ref new String(ws.c_str()); |
winrt::hstring s{ ws.c_str() }; s = winrt::hstring(ws.c_str()); // s = ws.c_str(); // Doesn't compile |
null 値を保持しつつ std::wstringに変換する | std::wstring ws{ s->Data(), s->Length }; ws = std::wstring(s>Data(), s->Length); |
std::wstring ws{ s }; ws = s; |
std::wstring |
std::wstring ws{ s->Data() }; ws = s->Data(); |
std::wstring ws{ s.c_str() }; ws = s.c_str(); |
リテラルをメソッドに渡す | Method("hello"); Method(L"hello"); |
// Method("hello"); // Doesn't compile Method(L"hello"); |
std::wstring |
Method(ref new String(ws.c_str(), (uint32_t)ws.size()); // Stops on first null |
Method(ws); // param::winrt::hstring accepts std::wstring_view |
重要な API
関連トピック
- C++/CX
- C++/WinRT でイベントを作成する
- C++/WinRT を使用したコンカレンシーと非同期操作
- C++/WinRT で API を消費する
- C++/WinRT でデリゲートを使用してイベントを処理する
- C++/WinRT と C++/CX 間の相互運用
- 非同期 し、C++/WinRT と C++/CX 間の相互運用
- Microsoft インターフェイス定義言語 3.0 リファレンス
- WRL から C++/WinRT に移動する
- C++/WinRT での文字列処理