Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Innan du läser det här avsnittet behöver du informationen i avsnittet Flytta till C++/WinRT från C++/CX. Det här avsnittet innehåller två huvudsakliga strategialternativ för att portera ditt C++/CX-projekt till C++/WinRT.
- Migrera hela projektet i ett steg. Det enklaste alternativet för ett projekt som inte är för stort. Om du har ett Windows Runtime komponentprojekt är den här strategin ditt enda alternativ.
- Portera projektet gradvis (storleken eller komplexiteten i din kodbas kan göra detta nödvändigt). Men den här strategin uppmanar dig att följa en portningsprocess där C++/CX- och C++/WinRT-kod finns sida vid sida i samma projekt. För ett XAML-projekt måste dina XAML-sidtyper vid en viss tidpunkt antingen vara C++/WinRT eller alla C++/CX.
Det här interop-ämnet är relevant för den andra strategin – för fall då du behöver portera projektet gradvis. Det här avsnittet visar olika former av hjälpfunktioner som du kan använda för att konvertera ett C++/CX-objekt (och andra typer) till ett C++/WinRT-objekt (och vice versa) i samma projekt.
Dessa hjälpfunktioner är mycket användbara när du porterar koden gradvis från C++/CX till C++/WinRT. Eller så kan du välja att använda både C++/WinRT- och C++/CX-språkprojektionerna i samma projekt, oavsett om du porterar eller inte, och använda dessa hjälpfunktioner för att samverka mellan de två.
När du har läst det här avsnittet, se det mer avancerade avsnittet Asynkronitet och interoperabilitet mellan C++/WinRT och C++/CX för information och kodexempel som visar hur du har stöd för PPL-uppgifter och koroutiner sida vid sida i samma projekt (till exempel att anropa koroutiner från uppgiftskedjor).
Funktionerna from_cx och to_cx
Här är en källkodslista över en rubrikfil med namnet interop_helpers.h, som innehåller olika konverteringshjälpfunktioner. När du gradvis porterar projektet finns det fortfarande delar i C++/CX och delar som du har portat till C++/WinRT. Du kan använda dessa hjälpfunktioner för att konvertera objekt (och andra typer) till och från C++/CX och C++/WinRT i projektet vid gränspunkterna mellan dessa två delar.
Avsnitten som följer kodlistan förklarar hjälpfunktionerna och hur du skapar och använder huvudfilen i projektet.
// interop_helpers.h
#pragma once
template <typename T>
T from_cx(Platform::Object^ from)
{
T to{ nullptr };
if (from != nullptr)
{
winrt::check_hresult(reinterpret_cast<::IUnknown*>(from)
->QueryInterface(winrt::guid_of<T>(), winrt::put_abi(to)));
}
return to;
}
template <typename T>
T^ to_cx(winrt::Windows::Foundation::IUnknown const& from)
{
return safe_cast<T^>(reinterpret_cast<Platform::Object^>(winrt::get_abi(from)));
}
inline winrt::hstring from_cx(Platform::String^ const& from)
{
return reinterpret_cast<winrt::hstring&>(const_cast<Platform::String^&>(from));
}
inline Platform::String^ to_cx(winrt::hstring const& from)
{
return reinterpret_cast<Platform::String^&>(const_cast<winrt::hstring&>(from));
}
inline winrt::guid from_cx(Platform::Guid const& from)
{
return reinterpret_cast<winrt::guid&>(const_cast<Platform::Guid&>(from));
}
inline Platform::Guid to_cx(winrt::guid const& from)
{
return reinterpret_cast<Platform::Guid&>(const_cast<winrt::guid&>(from));
}
Funktionen from_cx
Hjälpfunktionen from_cx konverterar ett C++/CX-objekt till ett motsvarande C++/WinRT-objekt. Funktionen omvandlar ett C++/CX-objekt till dess underliggande IUnknown-gränssnittspekare . Sedan anropas QueryInterface på den pekaren för att fråga efter standardgränssnittet för C++/WinRT-objektet.
QueryInterface är den Windows Runtime ABI-motsvarigheten (Application Binary Interface) för C++/CX-tilläggetsafe_cast. Och funktionen winrt::put_abi hämtar adressen till den underliggande IUnknown-gränssnittspekaren hos ett C++/WinRT-objekt så att den kan tilldelas ett annat värde.
to_cx-funktionen
Hjälpfunktionen to_cx konverterar ett C++/WinRT-objekt till ett motsvarande C++/CX-objekt. Funktionen winrt::get_abi hämtar en pekare till ett C++/WinRT-objekts underliggande IUnknown-gränssnitt . Funktionen kastar pekaren till ett C++/CX-objekt innan du använder C++/CX-tillägget safe_cast för att fråga efter den begärda C++/CX-typen.
Headerfilen interop_helpers.h
Följ dessa steg om du vill använda hjälpfunktionerna i projektet.
- Lägg till ett nytt rubrikfilobjekt (.h) i projektet och ge det
interop_helpers.hnamnet . - Ersätt innehållet i
interop_helpers.hmed kodlistan ovan. - Lägg till dessa include-satser i
pch.h.
// pch.h
...
#include <unknwn.h>
// Include C++/WinRT projected Windows API headers here.
...
#include <interop_helpers.h>
Ta ett C++/CX-projekt och lägga till C++/WinRT-stöd
I det här avsnittet beskrivs vad du ska göra om du har valt att ta ditt befintliga C++/CX-projekt, lägga till C++/WinRT-stöd till det och utföra portningsarbetet där. Se även Visual Studio stöd för C++/WinRT.
Om du vill blanda C++/CX och C++/WinRT i ett C++/CX-projekt , inklusive att använda hjälpfunktionerna from_cx och to_cx i projektet, måste du lägga till C++/WinRT-stöd i projektet manuellt.
Öppna först C++/CX-projektet i Visual Studio och bekräfta att projektegenskapen General>Target Platform Version är inställd på 10.0.17134.0 (Windows 10, version 1803) eller senare.
Installera nuget-paketet C++/WinRT
Microsoft.Windows. CppWinRT NuGet-paketet tillhandahåller C++/WinRT-byggstöd (MSBuild-egenskaper och mål). Om du vill installera det klickar du på menyalternativet Project>Hantera NuGet-paket...>Bläddra, skriv eller klistra in Microsoft.Windows. CppWinRT i sökrutan, välj objektet i sökresultaten och klicka sedan på Installera för att installera paketet för den project.
Viktigt!
Om du installerar nuget-paketet C++/WinRT inaktiveras stöd för C++/CX i projektet. Om du ska porta i ett pass är det en bra idé att lämna supporten inaktiverad så att byggmeddelanden hjälper dig att hitta (och porta) alla dina beroenden på C++/CX (så småningom omvandlar du det som var ett rent C++/CX-projekt till ett rent C++/WinRT-projekt). Men i nästa avsnitt finns information om hur du aktiverar den igen.
Aktivera C++/CX-stöd igen
Om du migrerar i ett steg behöver du inte göra detta. Men om du behöver portera gradvis måste du aktivera C++/CX-stöd igen i projektet. I projektegenskaper, under C/C++>Allmänt>Använd Windows Runtime-tillägg>Ja (/ZW)).
Alternativt (eller, för ett XAML-projekt, dessutom) kan du lägga till C++/CX-stöd med hjälp av egenskapssidan för C++/WinRT-projekt i Visual Studio. I projektegenskaper, Gemensamma egenskaper>C++/WinRT>Projektspråk>C++/CX. Om du gör det läggs följande egenskap till i .vcxproj filen.
<PropertyGroup Label="Globals">
<CppWinRTProjectLanguage>C++/CX</CppWinRTProjectLanguage>
</PropertyGroup>
Viktigt!
När du behöver bygga för att bearbeta innehållet i en Midl File (.idl) till stubbfiler måste du ändra Project Language tillbaka till C++/WinRT. När bygget har genererat dessa stubbar ändrar du Project Language tillbaka till C++/CX.
En lista över liknande anpassningsalternativ (som finjusterar verktygets cppwinrt.exe beteende) finns i Microsoft.Windows. CppWinRT NuGet-paket readme.
Inkludera C++/WinRT-huvudfiler
Det minsta du bör göra är att i din förkompilerade rubrikfil (vanligtvis pch.h), inkludera winrt/base.h som du ser nedan.
// pch.h
...
#include <winrt/base.h>
...
Men du behöver nästan säkert typerna i winrt::Windows::Foundation-namnområdet. Och du kanske redan känner till andra namnområden som du behöver. Inkludera därför de C++/WinRT-beräknade Windows API-huvuden som motsvarar dessa namnområden som detta (du behöver inte uttryckligen inkludera winrt/base.h nu eftersom det inkluderas automatiskt för dig).
// pch.h
...
#include <winrt/Windows.Foundation.h>
// Include any other C++/WinRT projected Windows API headers here.
...
Se även kodexemplet i följande avsnitt (Ta ett C++/WinRT-projekt och lägga till C++/CX-stöd) för en teknik som använder namnområdesalias namespace cx och namespace winrt. Med den här tekniken kan du hantera annars potentiella namnområdeskollisioner mellan C++/WinRT-projektionen och C++/CX-projektionen.
Lägg till interop_helpers.h i projektet
Nu kan du lägga till funktionerna from_cx och to_cx i C++/CX-projektet. Anvisningar om hur du gör det finns i avsnittet from_cx och to_cx ovan .
Ta ett C++/WinRT-projekt och lägga till C++/CX-stöd
I det här avsnittet beskrivs vad du ska göra om du har valt att skapa ett nytt C++/WinRT-projekt och utföra portningsarbetet där.
Om du vill blanda C++/WinRT och C++/CX i ett C++/WinRT-projekt, inklusive att använda hjälpfunktionerna from_cx och to_cx i projektet, måste du lägga till C++/CX-stöd i projektet manuellt.
- Skapa ett nytt C++/WinRT-projekt i Visual Studio med någon av C++/WinRT-projektmallarna (se Visual Studio stöd för C++/WinRT).
- Aktivera projektstöd för C++/CX. I projektegenskaper, C/C++>Allmänt>Använd Windows Runtime-tillägg>Ja (/ZW).
Ett exempel på ett C++/WinRT-projekt som visar de två hjälpfunktioner som används
I det här avsnittet kan du skapa ett exempel på ett C++/WinRT-projekt som visar hur du använder from_cx och to_cx. Det illustrerar också hur du kan använda namnområdesalias för de olika kodöarna för att hantera annars potentiella namnområdeskollisioner mellan C++/WinRT-projektionen och C++/CX-projektionen.
- Skapa ett projekt för Visual C++>Windows Universal>Core App (C++/WinRT).
- I projektegenskaper anger du C/C++>Allmänt>Använd Windows Runtime-tillägg>Ja (/ZW).
- Lägg till
interop_helpers.hi projektet. Anvisningar om hur du gör det finns i avsnittet from_cx och to_cx ovan . - Ersätt innehållet i
App.cppmed kodlistan nedan. - Bygg och kör.
WINRT_ASSERT är en makrodefinition och expanderas till _ASSERTE.
// App.cpp
#include "pch.h"
#include <sstream>
namespace cx
{
using namespace Windows::Foundation;
}
namespace winrt
{
using namespace Windows;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::UI::Composition;
}
struct App : winrt::implements<App, winrt::IFrameworkViewSource, winrt::IFrameworkView>
{
winrt::CompositionTarget m_target{ nullptr };
winrt::VisualCollection m_visuals{ nullptr };
winrt::Visual m_selected{ nullptr };
winrt::float2 m_offset{};
winrt::IFrameworkView CreateView()
{
return *this;
}
void Initialize(winrt::CoreApplicationView const &)
{
}
void Load(winrt::hstring const&)
{
}
void Uninitialize()
{
}
void Run()
{
winrt::CoreWindow window = winrt::CoreWindow::GetForCurrentThread();
window.Activate();
winrt::CoreDispatcher dispatcher = window.Dispatcher();
dispatcher.ProcessEvents(winrt::CoreProcessEventsOption::ProcessUntilQuit);
}
void SetWindow(winrt::CoreWindow const & window)
{
winrt::Compositor compositor;
winrt::ContainerVisual root = compositor.CreateContainerVisual();
m_target = compositor.CreateTargetForCurrentView();
m_target.Root(root);
m_visuals = root.Children();
window.PointerPressed({ this, &App::OnPointerPressed });
window.PointerMoved({ this, &App::OnPointerMoved });
window.PointerReleased([&](auto && ...)
{
m_selected = nullptr;
});
}
void OnPointerPressed(IInspectable const &, winrt::PointerEventArgs const & args)
{
winrt::float2 const point = args.CurrentPoint().Position();
for (winrt::Visual visual : m_visuals)
{
winrt::float3 const offset = visual.Offset();
winrt::float2 const size = visual.Size();
if (point.x >= offset.x &&
point.x < offset.x + size.x &&
point.y >= offset.y &&
point.y < offset.y + size.y)
{
m_selected = visual;
m_offset.x = offset.x - point.x;
m_offset.y = offset.y - point.y;
}
}
if (m_selected)
{
m_visuals.Remove(m_selected);
m_visuals.InsertAtTop(m_selected);
}
else
{
AddVisual(point);
}
}
void OnPointerMoved(IInspectable const &, winrt::PointerEventArgs const & args)
{
if (m_selected)
{
winrt::float2 const point = args.CurrentPoint().Position();
m_selected.Offset(
{
point.x + m_offset.x,
point.y + m_offset.y,
0.0f
});
}
}
void AddVisual(winrt::float2 const point)
{
winrt::Compositor compositor = m_visuals.Compositor();
winrt::SpriteVisual visual = compositor.CreateSpriteVisual();
static winrt::Color colors[] =
{
{ 0xDC, 0x5B, 0x9B, 0xD5 },
{ 0xDC, 0xED, 0x7D, 0x31 },
{ 0xDC, 0x70, 0xAD, 0x47 },
{ 0xDC, 0xFF, 0xC0, 0x00 }
};
static unsigned last = 0;
unsigned const next = ++last % _countof(colors);
visual.Brush(compositor.CreateColorBrush(colors[next]));
float const BlockSize = 100.0f;
visual.Size(
{
BlockSize,
BlockSize
});
visual.Offset(
{
point.x - BlockSize / 2.0f,
point.y - BlockSize / 2.0f,
0.0f,
});
m_visuals.InsertAtTop(visual);
m_selected = visual;
m_offset.x = -BlockSize / 2.0f;
m_offset.y = -BlockSize / 2.0f;
}
};
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
winrt::init_apartment();
winrt::Uri uri(L"http://aka.ms/cppwinrt");
std::wstringstream wstringstream;
wstringstream << L"C++/WinRT: " << uri.Domain().c_str() << std::endl;
// Convert from a C++/WinRT type to a C++/CX type.
cx::Uri^ cx = to_cx<cx::Uri>(uri);
wstringstream << L"C++/CX: " << cx->Domain->Data() << std::endl;
::OutputDebugString(wstringstream.str().c_str());
// Convert from a C++/CX type to a C++/WinRT type.
winrt::Uri uri_from_cx = from_cx<winrt::Uri>(cx);
WINRT_ASSERT(uri.Domain() == uri_from_cx.Domain());
WINRT_ASSERT(uri == uri_from_cx);
winrt::CoreApplication::Run(winrt::make<App>());
}
Viktiga API:er
Relaterade ämnen
Windows developer