Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Thema wird gezeigt, wie Sie Code aus der Windows Runtime-C++-Vorlagenbibliothek (WRL) in das entsprechende C++/WinRTübertragen.
Der erste Schritt beim Portieren zu C++/WinRT besteht darin, Ihrem Projekt manuell C++/WinRT-Unterstützung hinzuzufügen (siehe Visual Studio-Unterstützung für C++/WinRT). Installieren Sie dazu das Microsoft.Windows.CppWinRT NuGet-Paket in Ihrem Projekt. Öffnen Sie das Projekt in Visual Studio, klicken Sie auf Projekt>NuGet-Pakete verwalten...>Durchsuchen Sie, geben Sie Microsoft.Windows.CppWinRT im Suchfeld ein, wählen Sie das Element in den Suchergebnissen aus, und klicken Sie dann auf Installieren, um das Paket für dieses Projekt zu installieren. Eine Auswirkung dieser Änderung ist, dass die Unterstützung für C++/CX im Projekt deaktiviert ist. Wenn Sie C++/CX im Projekt verwenden, können Sie den Support deaktiviert lassen und ihren C++/CX-Code auch auf C++/WinRT aktualisieren (siehe Wechseln zu C++/WinRT aus C++/CX). Oder Sie können die Unterstützung wieder aktivieren (in Projekteigenschaften, C/C++>Allgemein>Verwenden der Windows-Runtime-Erweiterung>Ja (/ZW)) und konzentrieren Sie sich zuerst darauf, Ihren WRL-Code zu portieren. C++/CX und C++/WinRT-Code können im selben Projekt koexistieren, mit Ausnahme der XAML-Compilerunterstützung und Windows-Runtime-Komponenten (siehe Wechseln zu C++/WinRT aus C++/CX).
Legen Sie die Projekteigenschaft Allgemeine>Zielplattformversion auf 10.0.17134.0 (Windows 10, Version 1803) oder höher fest.
Schließen Sie in der vorkompilierten Headerdatei (normalerweise pch.h) winrt/base.hein.
#include <winrt/base.h>
Wenn Sie C++/WinRT projizierte Windows-API-Header (z. B. winrt/Windows.Foundation.h) einschließen, müssen Sie nicht explizit winrt/base.h einschließen, da sie automatisch für Sie eingeschlossen wird.
Portieren intelligenter WRL COM-Zeiger (Microsoft::WRL::ComPtr)
Portieren Sie Code, der Microsoft::WRL::ComPtr<T> verwendet, um winrt::com_ptr<T>zu nutzen. Hier sehen Sie ein Codebeispiel vor und nachher. In der nach Version ruft die com_ptr::put Memberfunktion den zugrunde liegenden Rohzeiger ab, sodass er festgelegt werden kann.
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
Wenn Sie über eine winrt::com_ptr verfügen, die bereits gesetzt ist (ihr interner roher Zeiger hat bereits ein Ziel) und sie auf ein anderes Objekt umleiten möchten, müssen Sie ihm zuerst nullptr zuweisen, wie im folgenden Codebeispiel gezeigt. Wenn Sie dies nicht tun, wird ein bereits existierender com_ptr Sie auf das Problem aufmerksam machen (wenn Sie com_ptr::put oder com_ptr::put_voidaufrufen) und bestätigen, dass sein interner Zeiger nicht NULL ist.
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())
);
Im nächsten Beispiel (in der nach Version) ruft die com_ptr::put_void Memberfunktion den zugrunde liegenden rohen Zeiger als Zeiger auf einen Zeiger auf void ab.
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();
}
Ersetzen Sie ComPtr::Get durch com_ptr::get.
m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
m_d3dDevice->CreateDepthStencilView(m_depthStencil.get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
Wenn Sie den zugrunde liegenden Rohzeiger an eine Funktion übergeben möchten, die einen Zeiger auf IUnknown-erwartet, verwenden Sie die freistehende Funktion winrt::get_unknown, wie im nächsten Beispiel gezeigt.
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()
)
);
Portieren eines WRL-Moduls (Microsoft::WRL::Module)
Dieser Abschnitt bezieht sich auf das Portieren von Code, der den Typ "Microsoft::WRL::Module " verwendet.
Sie können C++/WinRT-Code schrittweise zu einem vorhandenen Projekt hinzufügen, das WRL zum Implementieren einer Komponente verwendet, und Ihre vorhandenen WRL-Klassen werden weiterhin unterstützt. In diesem Abschnitt wird gezeigt, wie das geht.
Wenn Sie eine neue Komponente für Windows-Runtime (C++/WinRT) des-Projekttyps in Visual Studio erstellen und kompilieren, wird die Datei Generated Files\module.g.cpp für Sie generiert. Diese Datei enthält die Definitionen von zwei nützlichen C++/WinRT-Funktionen (unten aufgeführt), die Sie kopieren und zu Ihrem Projekt hinzufügen können. Diese Funktionen sind WINRT_CanUnloadNow und WINRT_GetActivationFactory und rufen, wie Sie sehen können, bedingt WRL auf, um Sie unabhängig von der Phase der Portierung, in der Sie sich befinden, zu unterstützen.
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(); }
}
Sobald Sie diese Funktionen in Ihrem Projekt haben, rufen Sie anstelle von Module::GetActivationFactory direkt WINRT_GetActivationFactory auf (die die WRL-Funktion intern aufruft). Hier sehen Sie ein Codebeispiel vor und nachher.
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));
}
Anstatt Module::Terminate direkt aufzurufen, rufen Sie WINRT_CanUnloadNow auf (die die WRL-Funktion intern aufruft). Hier sehen Sie ein Codebeispiel vor und nachher.
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;
}
Portieren Microsoft::WRL::Wrappers Wrapper
Dieser Abschnitt bezieht sich auf das Portieren von Code, der die Microsoft::WRL::Wrappers Wrapper verwendet.
Wie Sie in der folgenden Tabelle sehen können, empfehlen wir, die Hilfsprogramme für die Verwaltung von Threads mit der Standard-C++--Threadunterstützungsbibliothekzu ersetzen. Eine 1:1-Zuordnung aus den WRL-Wrappern kann irreführend sein, da Ihre Wahl von Ihren Anforderungen abhängt. Auch einige Typen, die naheliegende Zuordnungen scheinen, sind neu im C++20-Standard, sodass diese unpraktisch sind, wenn Sie noch nicht aufgewertet haben.
| Typ | Portieren von Notizen |
|---|---|
| CriticalSection-Klasse | Verwenden Sie die -Thread-Unterstützungsbibliothek |
| Ereignisklasse (WRL) | Verwenden des winrt::event struct template |
| HandleT-Klasse | Verwenden Sie die winrt::handle Struktur oder die winrt::file_handle Struktur |
| HString-Klasse | Verwenden Sie die winrt::hstring-Struktur |
| HStringReference-Klasse | Kein Ersatz, da C++/WinRT dies intern so effizient wie HStringReference mit dem Vorteil verarbeitet, dass Sie nicht darüber nachdenken müssen. |
| Mutex-Klasse | Verwenden Sie die -Thread-Unterstützungsbibliothek |
| RoInitializeWrapper Klasse | Verwenden Sie winrt::init_apartment und winrt::uninit_apartment; oder schreiben Sie einen eigenen Wrapper um CoInitializeEx und CoUninitialize, der trivial ist. |
| Semaphor-Klasse | Verwenden Sie die -Thread-Unterstützungsbibliothek |
| SRWLock-Klasse | Verwenden Sie die -Thread-Unterstützungsbibliothek |