次の方法で共有


WRL から C++/WinRT に移動する

このトピックでは、 Windows ランタイム C++ テンプレート ライブラリ (WRL) コードを C++/WinRT で同等のコードに移植する方法について説明します。

C++/WinRT への移植の最初の手順は、C++/WinRT のサポートをプロジェクトに手動で追加することです ( C++/WinRT の Visual Studio のサポートを参照)。 これを行うには、 Microsoft.Windows.CppWinRT NuGet パッケージ をプロジェクトにインストールします。 Visual Studio でプロジェクト 開き、[プロジェクト][NuGet パッケージの管理]をクリックします。[参照]をし、検索ボックス Microsoft.Windows.CppWinRT を入力または貼り付け、検索結果の項目を選択して、[ のインストール] をクリックして、そのプロジェクトのパッケージをインストール します。 その変更の 1 つの効果は、 C++/CX のサポートがプロジェクトでオフになっているということです。 プロジェクトで C++/CX を使用している場合は、サポートをオフのままにして、C++/CX コードを C++/WinRT に更新することもできます (C++ /CX から C++/WinRT への移動を参照)。 または、サポートを再びオンにし (プロジェクト プロパティ、 C/C++>General>Consume Windows ランタイム拡張機能>Yes (/ZW)))、最初に WRL コードの移植に重点を置くことができます。 C++/CX と C++/WinRT コードは、XAML コンパイラのサポートと Windows ランタイム コンポーネントを除き、同じプロジェクトに共存できます (C ++/CX から C++/WinRT への移動を参照)。

プロジェクト プロパティ 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>を使用するようにします。 前後のコード例を次に示します。 バージョン後の では、com_ptr::put メンバー関数は、基になる生ポインターを取得して設定するために使用されます。

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())
);

この次の例 ( バージョン後の ) では、com_ptr::put_void メンバー関数は、基になる生ポインターを void へのポインターへのポインターとして取得します。

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 使用し、winrt::uninit_apartmentを します。または、CoInitializeEx を囲む独自の簡易ラッパーを記述し、coUninitializeを します。
Semaphore クラス スレッド サポート ライブラリを使用する
SRWLock クラス スレッド サポート ライブラリを使用する

重要な API