Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cette rubrique montre comment porter du code Windows Runtime C++ Template Library (WRL) vers son équivalent dans C++/WinRT.
La première étape du portage vers C++/WinRT consiste à ajouter manuellement la prise en charge de C++/WinRT à votre projet (consultez Visual Studio prise en charge de C++/WinRT). Pour ce faire, installez le package NuGet Microsoft.Windows.CppWinRT dans votre projet. Ouvrez le project dans Visual Studio, cliquez sur Project>Manage de packages NuGet...>Parcourez, tapez ou collez Microsoft.Windows. CppWinRT dans la zone de recherche, sélectionnez l’élément dans les résultats de recherche, puis cliquez sur Installer pour installer le package pour cette project. L’un des effets de cette modification est que la prise en charge de C++/CX est désactivée dans le projet. Si vous utilisez C++/CX dans le projet, vous pouvez laisser la prise en charge désactivée et mettre à jour votre code C++/CX vers C++/WinRT également (voir Déplacer vers C++/WinRT à partir de C++/CX). Vous pouvez également réactiver la prise en charge (dans les propriétés du projet, C/C++>Général>Consommer Windows Runtime Extension>Oui (/ZW)) et tout d’abord vous concentrer sur le portage de votre code WRL. Le code C++/CX et C++/WinRT peut coexister dans le même projet, à l’exception de la prise en charge du compilateur XAML et des composants Windows Runtime (voir Déplacer vers C++/WinRT à partir de C++/CX).
Définissez la propriété du projet Général>Version de la plateforme cible sur 10.0.17134.0 (Windows 10, version 1803) ou ultérieure.
Dans votre fichier d’en-tête précompilé (généralement pch.h), incluez winrt/base.h.
#include <winrt/base.h>
Si vous incluez des fichiers d’en-tête d’API Windows projetés pour C++/WinRT (par exemple, winrt/Windows.Foundation.h), vous n’avez pas besoin d’inclure explicitement winrt/base.h de cette manière, car il sera inclus automatiquement.
Portage de pointeurs intelligents WRL COM (Microsoft ::WRL ::ComPtr)
Portez tout code qui utilise Microsoft ::WRL ::ComPtr<T> pour utiliser winrt ::com_ptr<T>. Voici un exemple de code avant et après. Dans la version après, la fonction membre com_ptr::put récupère le pointeur brut sous-jacent afin de pouvoir le définir.
ComPtr<IDXGIAdapter1> previousDefaultAdapter;
DX::ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &previousDefaultAdapter));
winrt::com_ptr<IDXGIAdapter1> previousDefaultAdapter;
winrt::check_hresult(m_dxgiFactory->EnumAdapters1(0, previousDefaultAdapter.put()));
Important
Si vous disposez d’un winrt ::com_ptr déjà assis (son pointeur brut interne a déjà une cible) et que vous souhaitez le réinscrire pour pointer vers un autre objet, vous devez d’abord l’affecter nullptr , comme illustré dans l’exemple de code ci-dessous. Si ce n’est pas le cas, une com_ptr qui contient déjà une valeur vous le signalera (lorsque vous appelez com_ptr::put ou com_ptr::put_void) en déclenchant une assertion indiquant que son pointeur interne n’est pas 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())
);
Dans cet exemple suivant (dans la version après), la fonction membre com_ptr::put_void récupère le pointeur brut sous-jacent sous la forme d’un pointeur vers un pointeur sur 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();
}
Remplacez ComPtr ::Get par com_ptr ::get.
m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
m_d3dDevice->CreateDepthStencilView(m_depthStencil.get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
Lorsque vous souhaitez passer le pointeur brut sous-jacent à une fonction qui attend un pointeur vers IUnknown, utilisez la fonction gratuite winrt ::get_unknown , comme illustré dans cet exemple suivant.
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()
)
);
Portage d’un module WRL (Microsoft ::WRL ::Module)
Cette section concerne le portage du code qui utilise le type Microsoft ::WRL ::Module.
Vous pouvez ajouter progressivement du code C++/WinRT à un projet existant qui utilise WRL pour implémenter un composant, et vos classes WRL existantes continueront d’être prises en charge. Cette section montre comment procéder.
Si vous créez un type de projet Windows Runtime Component (C++/WinRT) dans Visual Studio, puis générez-le, le fichier Generated Files\module.g.cpp est généré pour vous. Ce fichier contient les définitions de deux fonctions C++/WinRT utiles (répertoriées ci-dessous), que vous pouvez copier et ajouter à votre projet. Ces fonctions sont WINRT_CanUnloadNow et WINRT_GetActivationFactory et, comme vous pouvez le voir, elles appellent de manière conditionnelle WRL pour vous prendre en charge quelle que soit l’étape de portage à laquelle vous vous trouvez.
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(); }
}
Une fois que vous avez ces fonctions dans votre projet, au lieu d’appeler directement Module ::GetActivationFactory , appelez WINRT_GetActivationFactory (qui appelle la fonction WRL en interne). Voici un exemple de code avant et après.
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));
}
Au lieu d’appeler directement Module ::Terminate , appelez WINRT_CanUnloadNow (qui appelle la fonction WRL en interne). Voici un exemple de code avant et après.
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;
}
Portage des wrappers Microsoft ::WRL ::Wrappers
Cette section concerne le portage du code qui utilise les wrappers Microsoft ::WRL ::Wrappers.
Comme vous pouvez le voir dans le tableau ci-dessous, pour remplacer les assistants de gestion des threads, nous vous recommandons d’utiliser la bibliothèque standard C++ de gestion des threads. Un mappage un-à-un à partir des wrappers WRL peut être trompeur, car votre choix dépend de vos besoins. En outre, certains types qui peuvent sembler être des correspondances évidentes ont été introduits par la norme C++20 ; il sera donc peu pratique de les utiliser si vous n’avez pas encore effectué la mise à niveau.
| Type | Notes de portage |
|---|---|
| classe CriticalSection | Utiliser la bibliothèque de support des threads |
| Classe d’événements (WRL) | Utiliser le modèle de struct winrt ::event |
| Classe HandleT | Utilisez le struct winrt ::handle ou le struct winrt ::file_handle |
| Classe HString | Utiliser la structure winrt::hstring |
| classe HStringReference | Aucun remplacement, car C++/WinRT gère cela en interne d’une manière aussi efficace que HStringReference avec l’avantage que vous n’avez pas à y penser. |
| classe Mutex | Utiliser la bibliothèque de gestion des threads |
| classe RoInitializeWrapper | Utilisez winrt ::init_apartment et winrt ::uninit_apartment ; ou écrivez votre propre wrapper trivial autour de CoInitializeEx et CoUninitialize. |
| classe Semaphore | Utiliser la bibliothèque de support des threads |
| classe SRWLock | Utiliser la bibliothèque de support des threads |
API importantes
Rubriques connexes
Windows developer