Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
In dit onderwerp wordt beschreven hoe u code van Windows Runtime C++-sjabloonbibliotheek (WRL) kunt overzetten naar het equivalent ervan in C++/WinRT.
De eerste stap bij het overzetten naar C++/WinRT is het handmatig toevoegen van C++/WinRT-ondersteuning aan uw project (zie Visual Studio ondersteuning voor C++/WinRT). Installeer hiervoor de Microsoft.Windows. CppWinRT NuGet-pakket in uw project. Open het project in Visual Studio en klik op Project>Manage NuGet Packages...>Bladeren, typ of plak Microsoft.Windows.CppWinRT in het zoekvak, selecteer het item in de zoekresultaten en klik vervolgens op Installeren om het pakket voor dat project te installeren. Een van de gevolgen van deze wijziging is dat ondersteuning voor C++/CX is uitgeschakeld in het project. Als u C++/CX in het project gebruikt, kunt u de ondersteuning uitgeschakeld laten en uw C++/CX-code ook bijwerken naar C++/WinRT (zie Verplaatsen naar C++/WinRT van C++/CX). U kunt ook ondersteuning weer inschakelen (in projecteigenschappen, C/C++>Algemeen>verbruiken Windows Runtime Extensie>Ja (/ZW)) en u moet zich eerst richten op het overzetten van uw WRL-code. C++/CX en C++/WinRT-code kunnen naast hetzelfde project bestaan, met uitzondering van XAML-compilerondersteuning en Windows Runtime onderdelen (zie Verplaatsen naar C++/WinRT van C++/CX).
Stel projecteigenschap Algemeen>doelplatformversie in op 10.0.17134.0 (Windows 10, versie 1803) of hoger.
Neem in het vooraf gecompileerde headerbestand (meestal pch.h) op winrt/base.h.
#include <winrt/base.h>
Als u C++/WinRT-geprojecteerde Windows API-headers opneemt (bijvoorbeeld winrt/Windows.Foundation.h), hoeft u winrt/base.h niet expliciet op deze manier op te nemen, omdat dit automatisch voor u wordt opgenomen.
WRL COM-smart pointers overzetten (Microsoft::WRL::ComPtr)
Migreer alle code die Microsoft::WRL::ComPtr<T> gebruikt naar winrt::com_ptr<T>. Hier volgt een voorbeeld van code vóór en na. In de na-versie haalt de com_ptr::put-lidfunctie de onderliggende ruwe pointer op, zodat die kan worden ingesteld.
ComPtr<IDXGIAdapter1> previousDefaultAdapter;
DX::ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &previousDefaultAdapter));
winrt::com_ptr<IDXGIAdapter1> previousDefaultAdapter;
winrt::check_hresult(m_dxgiFactory->EnumAdapters1(0, previousDefaultAdapter.put()));
Belangrijk
Als u een winrt::com_ptr hebt die al is ingesteld (de interne raw pointer verwijst al naar een doel) en u deze opnieuw wilt laten verwijzen naar een ander object, moet u er eerst nullptr aan toewijzen, zoals wordt weergegeven in het onderstaande codevoorbeeld. Als u dat niet doet, trekt een reeds geplaatste com_ptr het probleem naar uw aandacht (wanneer u com_ptr::p ut of com_ptr::p ut_void) aanroept door te bevestigen dat de interne aanwijzer niet null is.
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())
);
In dit volgende voorbeeld (in de versie na) haalt de lidfunctie com_ptr::put_void de onderliggende ruwe pointer op als een pointer naar een pointer naar 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();
}
Vervang ComPtr::Get door com_ptr::get.
m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
m_d3dDevice->CreateDepthStencilView(m_depthStencil.get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
Als u de onderliggende onbewerkte aanwijzer wilt doorgeven aan een functie die een aanwijzer naar IUnknown verwacht, gebruikt u de gratis functie winrt::get_unknown , zoals wordt weergegeven in dit volgende voorbeeld.
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()
)
);
Een WRL-module overzetten (Microsoft::WRL::Module)
Deze sectie heeft betrekking op poortcode die gebruikmaakt van het type Microsoft::WRL::Module.
U kunt geleidelijk C++/WinRT-code toevoegen aan een bestaand project dat gebruikmaakt van WRL om een onderdeel te implementeren en uw bestaande WRL-klassen blijven ondersteund. In deze sectie ziet u hoe u dit doet.
Als u een nieuw Windows Runtime Component-projecttype (C++/WinRT) maakt in Visual Studio en bouwt, wordt het bestand Generated Files\module.g.cpp voor u gegenereerd. Dat bestand bevat de definities van twee nuttige C++/WinRT-functies (hieronder vermeld), die u kunt kopiëren en toevoegen aan uw project. Deze functie zijn WINRT_CanUnloadNow en WINRT_GetActivationFactory en, zoals u kunt zien, roepen ze WRL voorwaardelijk aan om u te ondersteunen in welke fase van het overzetten u zich bevindt.
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(); }
}
Zodra u deze functies in uw project hebt, roept u, in plaats van Module::GetActivationFactory rechtstreeks aan te roepen, WINRT_GetActivationFactory aan (dat intern de WRL-functie aanroept). Hier volgt een voorbeeld van code vóór en na.
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));
}
Roep niet rechtstreeks Module::Terminate aan, maar WINRT_CanUnloadNow (die intern de WRL-functie aanroept). Hier volgt een voorbeeld van code vóór en na.
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;
}
Overzetten van Microsoft::WRL::Wrappers-omhulsels
Deze sectie heeft betrekking op poortcode die gebruikmaakt van de Microsoft::WRL::Wrappers-wrappers.
Zoals u in de onderstaande tabel kunt zien, wordt u aangeraden de threading-helpers te vervangen door de standaard-C++- threadondersteuningsbibliotheek te gebruiken. Een een-op-een-koppeling van de WRL-wrappers kan misleidend zijn, omdat de keuze afhangt van uw behoeften. Sommige typen die duidelijk lijken te zijn, zijn ook nieuw voor de C++20-standaard, dus deze zijn niet praktisch als u nog geen upgrade hebt uitgevoerd.
| Type | Opmerkingen bij het porteren |
|---|---|
| CriticalSection-klasse | Gebruik de bibliotheek voor threadondersteuning |
| Gebeurtenisklasse (WRL) | De winrt::event struct-sjabloon gebruiken |
| HandleT-klasse | Gebruik de winrt::handle struct of de winrt::file_handle struct |
| HString-klasse | De winrt::hstring-struct gebruiken |
| HStringReference-klasse | Geen vervanging, omdat C++/WinRT dit intern verwerkt op een manier die net zo efficiënt is als HStringReference met het voordeel dat u er niet over hoeft na te denken. |
| Mutex-klasse | Gebruik de bibliotheek voor threadondersteuning |
| Klasse RoInitializeWrapper | Gebruik winrt::init_apartment en winrt::uninit_apartment; ofwel schrijf uw eigen triviale wrapper om CoInitializeEx en CoUninitialize. |
| Semaphore-klasse | Gebruik de bibliotheek voor threadondersteuning |
| SRWLock-klasse | Gebruik de bibliotheek voor threadondersteuning |
Belangrijke API's
Verwante onderwerpen
Windows developer