このトピックでは、 Windows ランタイム C++ テンプレート ライブラリ (WRL) コードを C++/WinRT で同等のコードに移植する方法について説明します。
C++/WinRT への移植の最初の手順は、C++/WinRT のサポートをプロジェクトに手動で追加することです ( C++/WinRT の Visual Studio のサポートを参照)。 これを行うには、 Microsoft.Windows.CppWinRT NuGet パッケージ をプロジェクトにインストールします。 Visual Studio でプロジェクト
プロジェクト プロパティ General>Target Platform Version を 10.0.17134.0 (Windows 10 バージョン 1803) 以上に設定します。
プリコンパイル済みヘッダー ファイル (通常は pch.h
) には、 winrt/base.h
を含めます。
#include <winrt/base.h>
C++/WinRT で投影された Windows API ヘッダー ( winrt/Windows.Foundation.h
など) を含める場合は、このような winrt/base.h
を明示的に含める必要はありません。これは自動的に含まれるためです。
WRL COM スマート ポインターの移植 (Microsoft::WRL::ComPtr)
Microsoft::WRL::ComPtr<T> を使用するコードを移植して、winrt::com_ptr<T>を使用するようにします。 前後のコード例を次に示します。 バージョン後の
ComPtr<IDXGIAdapter1> previousDefaultAdapter;
DX::ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &previousDefaultAdapter));
winrt::com_ptr<IDXGIAdapter1> previousDefaultAdapter;
winrt::check_hresult(m_dxgiFactory->EnumAdapters1(0, previousDefaultAdapter.put()));
Von Bedeutung
既に座っている winrt::com_ptr (内部の生ポインターに既にターゲットがある) があり、別のオブジェクトを指すように再座させる場合は、次のコード例に示すように、最初に nullptr
を割り当てる必要があります。 そうでない場合は、既にセットされている com_ptr は、内部ポインターが null ではないことをアサートすることで、(com_ptr::put または com_ptr::put_voidを呼び出すとき)、問題を認識させます。
winrt::com_ptr<IDXGISwapChain1> m_pDXGISwapChain1;
...
// We execute the code below each time the window size changes.
m_pDXGISwapChain1 = nullptr; // Important because we're about to re-seat
winrt::check_hresult(
m_pDxgiFactory->CreateSwapChainForHwnd(
m_pCommandQueue.get(), // For Direct3D 12, this is a pointer to a direct command queue, and not to the device.
m_hWnd,
&swapChainDesc,
nullptr,
nullptr,
m_pDXGISwapChain1.put())
);
この次の例 ( バージョン後の
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
debugController->EnableDebugLayer();
}
winrt::com_ptr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(debugController), debugController.put_void())))
{
debugController->EnableDebugLayer();
}
ComPtr::Get をcom_ptr::get に置き換えます。
m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
m_d3dDevice->CreateDepthStencilView(m_depthStencil.get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
次の例に示すように、基になる生ポインターをIUnknownへのポインターが必要な関数に渡す場合は、winrt::get_unknown フリー関数を使用します。
ComPtr<IDXGISwapChain1> swapChain;
DX::ThrowIfFailed(
m_dxgiFactory->CreateSwapChainForCoreWindow(
m_commandQueue.Get(),
reinterpret_cast<IUnknown*>(m_window.Get()),
&swapChainDesc,
nullptr,
&swapChain
)
);
winrt::agile_ref<winrt::Windows::UI::Core::CoreWindow> m_window;
winrt::com_ptr<IDXGISwapChain1> swapChain;
winrt::check_hresult(
m_dxgiFactory->CreateSwapChainForCoreWindow(
m_commandQueue.get(),
winrt::get_unknown(m_window.get()),
&swapChainDesc,
nullptr,
swapChain.put()
)
);
WRL モジュールの移植 (Microsoft::WRL::Module)
このセクションは、 Microsoft::WRL::Module 型を使用するコードの移植に関連しています。
WRL を使用してコンポーネントを実装する既存のプロジェクトに C++/WinRT コードを徐々に追加できます。既存の WRL クラスは引き続きサポートされます。 このセクションでは、その方法を示します。
Visual Studio で新しい Windows ランタイム コンポーネント (C++/WinRT) プロジェクトの種類を作成してビルドすると、 Generated Files\module.g.cpp
ファイルが自動的に生成されます。 このファイルには、2 つの便利な C++/WinRT 関数 (以下に示す) の定義が含まれています。この関数は、プロジェクトにコピーして追加できます。 これらの関数は WINRT_CanUnloadNowWINRT_GetActivationFactoryであり 、ご覧のように、WRL を条件付きで呼び出して、現在の移植段階をサポートします。
HRESULT WINRT_CALL WINRT_CanUnloadNow()
{
#ifdef _WRL_MODULE_H_
if (!::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().Terminate())
{
return S_FALSE;
}
#endif
if (winrt::get_module_lock())
{
return S_FALSE;
}
winrt::clear_factory_cache();
return S_OK;
}
HRESULT WINRT_CALL WINRT_GetActivationFactory(HSTRING classId, void** factory)
{
try
{
*factory = nullptr;
wchar_t const* const name = WINRT_WindowsGetStringRawBuffer(classId, nullptr);
if (0 == wcscmp(name, L"MoveFromWRLTest.Class"))
{
*factory = winrt::detach_abi(winrt::make<winrt::MoveFromWRLTest::factory_implementation::Class>());
return S_OK;
}
#ifdef _WRL_MODULE_H_
return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetActivationFactory(classId, reinterpret_cast<::IActivationFactory**>(factory));
#else
return winrt::hresult_class_not_available().to_abi();
#endif
}
catch (...) { return winrt::to_hresult(); }
}
プロジェクトでこれらの関数を取得したら、 Module::GetActivationFactory を直接呼び出す代わりに、 WINRT_GetActivationFactory (WRL 関数を内部的に呼び出します) を呼び出します。 前後のコード例を次に示します。
HRESULT WINAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _Out_ ::IActivationFactory **factory)
{
auto & module = Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
return module.GetActivationFactory(activatableClassId, factory);
}
HRESULT __stdcall WINRT_GetActivationFactory(HSTRING activatableClassId, void** factory);
HRESULT WINAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _Out_ ::IActivationFactory **factory)
{
return WINRT_GetActivationFactory(activatableClassId, reinterpret_cast<void**>(factory));
}
Module::Terminate を直接呼び出す代わりに、WINRT_CanUnloadNow (WRL 関数を内部的に呼び出します) を呼び出します。 前後のコード例を次に示します。
HRESULT __stdcall DllCanUnloadNow(void)
{
auto &module = Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
HRESULT hr = (module.Terminate() ? S_OK : S_FALSE);
if (hr == S_OK)
{
hr = ...
}
return hr;
}
HRESULT __stdcall WINRT_CanUnloadNow();
HRESULT __stdcall DllCanUnloadNow(void)
{
HRESULT hr = WINRT_CanUnloadNow();
if (hr == S_OK)
{
hr = ...
}
return hr;
}
Microsoft::WRL::Wrappers ラッパー 移植する
このセクションでは、Microsoft::WRL::Wrappers ラッパーを使用するコードの移植に関連します。
次の表に示すように、スレッド ヘルパーを置き換えるには、Standard C++ スレッド サポート ライブラリを使用することをお勧めします。 WRL ラッパーからの 1 対 1 のマッピングは、ニーズによって異なるため、誤解を招く可能性があります。 また、明らかなマッピングと思われる型の中には、C++20 標準の新しい型もあるため、まだアップグレードしていない場合は実用的ではありません。
タイプ | 移植に関する注意事項 |
---|---|
CriticalSection クラス | スレッド サポート ライブラリを使用する |
イベント クラス (WRL) | winrt::event 構造体テンプレートを使用する |
HandleT クラスの | winrt::handle 構造体または winrt::file_handle 構造体を使用する |
HString クラス |
winrt::hstring 構造体を使用する |
HStringReference クラス | C++/WinRT は、 HStringReference と同じくらい効率的な方法で内部的に処理するため、代わりには使用できません。その利点を考慮する必要はありません。 |
ミューテックス クラス | スレッド サポート ライブラリを使用する |
RoInitializeWrapper クラス | winrt::init_apartment |
Semaphore クラス | スレッド サポート ライブラリを使用する |
SRWLock クラス | スレッド サポート ライブラリを使用する |
重要な API
関連トピック
- C++/WinRT の概要
- C++/CX から C++/WinRT に移動する
- Windows ランタイム C++ テンプレート ライブラリ (WRL)