Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Toto téma popisuje, jak přenést kód prostředí Windows Runtime C++ Template Library (WRL) do jeho ekvivalentu v C++/WinRT.
Prvním krokem při přenosu do C++/WinRT je ruční přidání podpory C++/WinRT do projektu (viz Visual Studio podpora C++/WinRT). To provedete tak, že do svého projektu nainstalujete balíček NuGet Microsoft.Windows.CppWinRT. Otevřete project v Visual Studio, klikněte na Project>Spravování balíčků NuGet...>Procházet, psát nebo vkládat Microsoft.Windows. CppWinRT ve vyhledávacím poli, vyberte položku ve výsledcích hledání a potom klepněte na tlačítko Nainstalovat, chcete-li nainstalovat balíček pro tento project. Jedním z účinků této změny je, že podpora C++/CX je v projektu vypnutá. Pokud v projektu používáte C++/CX, můžete ponechat podporu vypnutou a aktualizovat kód C++/CX na C++/WinRT (viz Přechod na C++/WinRT z C++/CX). Nebo můžete podporu zapnout (ve vlastnostech projektu, C/C++>General>Consume prostředí Windows Runtime Extension>Yes (/ZW) a nejprve se zaměřit na přenos kódu WRL. Kód C++/CX a C++/WinRT může existovat ve stejném projektu, s výjimkou podpory kompilátoru XAML a komponent prostředí Windows Runtime (viz přechod na C++/WinRT z C++/CX).
Nastavte vlastnost projektu Obecná>cílová platforma verze na 10.0.17134.0 (Windows 10, verze 1803) nebo vyšší.
Do souboru předkompilované hlavičky (obvykle pch.h) zahrňte winrt/base.h.
#include <winrt/base.h>
Pokud zahrnete jakékoli projektované hlavičky rozhraní Windows API pro C++/WinRT (například winrt/Windows.Foundation.h), nemusíte pak explicitně zahrnovat winrt/base.h, protože se zahrne automaticky.
Portování inteligentních ukazatelů COM z knihovny WRL (Microsoft::WRL::ComPtr)
Portuje libovolný kód, který používá Microsoft::WRL::ComPtr<T>, aby používal winrt::com_ptr<T>. Tady je příklad kódu před a po. Ve verzi after načítá členská funkce com_ptr::put podkladový surový ukazatel, aby jej bylo možné nastavit.
ComPtr<IDXGIAdapter1> previousDefaultAdapter;
DX::ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &previousDefaultAdapter));
winrt::com_ptr<IDXGIAdapter1> previousDefaultAdapter;
winrt::check_hresult(m_dxgiFactory->EnumAdapters1(0, previousDefaultAdapter.put()));
Důležité
Pokud máte winrt::com_ptr , který už sedí (jeho interní nezpracovaný ukazatel už má cíl) a chcete ho znovu sesadit tak, aby odkazoval na jiný objekt, musíte ho nejdřív přiřadit nullptr – jak je znázorněno v příkladu kódu níže. Pokud ne, pak již sedící com_ptr vás upozorní na váš problém (když zavoláte com_ptr::p ut nebo com_ptr::p ut_void) tím, že zjistíte, že jeho interní ukazatel není null.
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())
);
V tomto dalším příkladu (ve verzi po) členská funkce com_ptr::put_void načítá podkladový nezpracovaný ukazatel jako ukazatel na ukazatel na 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();
}
Nahraďte ComPtr::Getcom_ptr::get.
m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
m_d3dDevice->CreateDepthStencilView(m_depthStencil.get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
Pokud chcete předat základní nezpracovaný ukazatel na funkci, která očekává ukazatel na IUnknown, použijte winrt::get_unknown funkci free, jak je znázorněno v tomto dalším příkladu.
ComPtr<IDXGISwapChain1> swapChain;
DX::ThrowIfFailed(
m_dxgiFactory->CreateSwapChainForCoreWindow(
m_commandQueue.Get(),
reinterpret_cast<IUnknown*>(m_window.Get()),
&swapChainDesc,
nullptr,
&swapChain
)
);
// Note: In a WinUI 3 desktop app, use CreateSwapChainForHwnd instead of
// CreateSwapChainForCoreWindow, since WinUI 3 doesn't use CoreWindow.
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()
)
);
Přenos modulu WRL (Microsoft::WRL::Module)
Tato část se vztahuje k přenosu kódu, který používá typ Microsoft::WRL::Module.
Kód C++/WinRT můžete postupně přidat do existujícího projektu, který k implementaci komponenty používá knihovnu WRL, a vaše stávající třídy knihovny WRL budou nadále podporovány. V této části se dozvíte, jak na to.
Pokud v Visual Studio vytvoříte nový typ projektu komponenty prostředí Windows Runtime (C++/WinRT) a sestavíte ho, soubor Generated Files\module.g.cpp se vygeneruje za vás. Tento soubor obsahuje definice dvou užitečných funkcí C++/WinRT (uvedených níže), které můžete zkopírovat a přidat do projektu. Těmito funkcemi jsou WINRT_CanUnloadNow a WINRT_GetActivationFactory a, jak vidíte, podmíněně volají WRL, aby vás podpořily v jakékoli fázi portace, ve které se právě nacházíte.
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(); }
}
Jakmile budete mít tyto funkce v projektu, místo volání Module::GetActivationFactory přímo volejte WINRT_GetActivationFactory (která volá funkci WRL interně). Tady je příklad kódu před a po.
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));
}
Místo volání Modulu::Terminate přímo volejte WINRT_CanUnloadNow (který volá funkci WRL interně). Tady je příklad kódu před a po.
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;
}
Portování obalových tříd Microsoft::WRL::Wrappers
Tato část se týká kódu přenosu, který používá obálky Microsoft::WRL::Wrappers.
Jak můžete vidět v tabulce níže, pro nahrazení pomocných rutin pro práci s vlákny doporučujeme, abyste použili knihovnu podpory vláken standardu C++. Mapování 1:1 z obálky WRL může být zavádějící, protože vaše volba závisí na vašich potřebách. Některé typy, které můžou vypadat jako běžné mapování, jsou pro standard C++20 nové, takže pokud jste ještě neupgradovali, budou nepraktické.
| Typ | Poznámky k portování |
|---|---|
| třída CriticalSection | Použijte knihovnu podpory vláken |
| Třída událostí (WRL) | Použití šablony struktury winrt::event |
| třída HandleT | Použijte strukturu winrt::handle nebo winrt::file_handle |
| třída HString | Použijte strukturu winrt::hstring |
| třída HStringReference | Žádné nahrazení, protože C++/WinRT to interně zpracovává způsobem, který je stejně efektivní jako HStringReference s výhodou, kterou o tom nemusíte přemýšlet. |
| Třída Mutex | Použijte knihovnu podpory vláken |
| Třída RoInitializeWrapper | Použijte winrt::init_apartment a winrt::uninit_apartment; nebo si napište vlastní jednoduchý obal kolem CoInitializeEx a CoUninitialize. |
| třída Semaphore | Použijte knihovnu podpory vláken |
| třída SRWLock | Použijte knihovnu podpory vláken |
Důležitá rozhraní API
Příbuzná témata
Windows developer