Обучение
Схема обучения
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Этот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
Перед прочтением этого раздела нужно ознакомиться со сведениями в статье Переход на C++/WinRT из C++/CX. В этом разделе представлены два основных варианта стратегии переноса проекта C++/CX в C++/WinRT.
Этот раздел взаимодействия относится ко второй стратегии, в случаях, когда проект необходимо переносить постепенно. В нем представлены различные формы пар вспомогательных функций, которые можно использовать для преобразования объекта C++/CX в объект C++/WinRT (и наоборот).
Эти вспомогательные функции будут очень полезны при постепенном переносе кода с C++/CX на C++/WinRT. Или вы можете просто использовать в одном проекте проекции на языке C++/WinRT и C++/CX, независимо от того, выполняете вы перенос или нет, и пользоваться этими вспомогательными функциями для взаимодействия между ними.
Прочитав этот раздел, ознакомьтесь с информацией и примерами кода, показывающими, как поддерживать выполнение задач PPL и сопрограмм параллельно в одном проекте (например, вызов сопрограмм из цепочек задач). См. дополнительные сведения в статье Асинхронное выполнение задач и взаимодействие между C++/WinRT и C++/CX.
Ниже приведен исходный код файла заголовка с именем interop_helpers.h
, содержащий различные вспомогательные функции преобразования. По мере постепенного переноса проекта вы окажетесь в ситуации, когда одни его части остаются в C++, а другие уже перенесены в C++/WinRT. Приведенные далее вспомогательные функции можно использовать, чтобы преобразовывать объекты (и другие типы) C++/CX в объекты C++/WinRT и наоборот в проекте на граничных точках между этими двумя средами.
В следующих разделах приведен листинг кода и описываются эти вспомогательные функции, а также описывается создание и использование файла заголовка в проекте.
// 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));
}
Вспомогательная функция from_cx преобразовывает объект C++/CX в эквивалентный объект C++/WinRT. Она автоматически приводит объект C++/CX к его базовому указателю интерфейса IUnknown. Затем она вызывает QueryInterface для этого указателя, чтобы запросить интерфейс по умолчанию для объекта C++/WinRT. QueryInterface — это эквивалент расширения safe_cast
C++/CX в двоичном интерфейсе приложения (ABI) среды выполнения Windows. Функция winrt::put_abi возвращает адрес базового указателя интерфейса IUnknown объекта C++/WinRT, чтобы для него можно было задать другое значение.
Вспомогательная функция to_cx преобразовывает объект C++/WinRT в эквивалентный объект C++/CX. Функция Winrt::get_abi получает указатель на базовый интерфейс IUnknown объекта C++/WinRT. Функция приводит этот указатель к объекту C++/CX перед тем, как использовать расширение C++/CX safe_cast
для запроса необходимого типа C++/CX.
Чтобы использовать вспомогательные функции в проекте, выполните следующие действия.
interop_helpers.h
.interop_helpers.h
кодом из списка выше.pch.h
.// pch.h
...
#include <unknwn.h>
// Include C++/WinRT projected Windows API headers here.
...
#include <interop_helpers.h>
В этом разделе описывается, что делать, если вы решили добавить к существующему проекту C++/CX поддержку C++/WinRT и выполнить перенос. Также см. сведения в разделе Поддержка Visual Studio для C++/WinRT, XAML, расширения VSIX и пакета NuGet.
Для объединения C++/CX и C++/WinRT в проекте C++/CX, в том числе использования в проекте вспомогательных функций from_cx и to_cx, необходимо вручную добавить в проект поддержку C++/WinRT.
Сначала откройте свой проект C++/CX в Visual Studio и подтвердите, что для свойства проекта Общие>Версия целевой платформы установлено значение 10.0.17134.0 (Windows 10, версия 1803) или выше.
Пакет NuGet Microsoft.Windows.CppWinRT обеспечивает поддержку сборки C++/WinRT (свойства и цели MSBuild). Для его установки, выберите пункт меню Проект>Управление пакетами NuGet ...>Обзор, введите или вставьте Microsoft.Windows.CppWinRT в поле поиска, выберите элемент в результатах поиска, а затем нажмите кнопку Установить, чтобы установить пакет для этого проекта.
Важно!
Установка пакета NuGet для C++/WinRT приводит к отключению поддержки C++/CX в проекте. Если вы собираетесь переносить данные за один проход, эту поддержку лучше оставить выключенной, чтобы сообщения о сборке помогли вам найти (и перенести) все ваши зависимости с C++/CX (в конечном итоге превратив то, что было обычным проектом C++/CX, в обычный проект C++/WinRT). Однако просмотрите следующий раздел со сведениями о включении поддержки.
Если вы выполняете перенос за один проход,поддержку C++/CX можно не включать. Однако вам необходимо будет включить поддержку C++/CX в проекте при постепенном переносе. В свойствах проекта выберите C/C++>Общие>Использовать расширение среды выполнения Windows> Да (/ZW)).
Кроме того (или в дополнение к проекту XAML), поддержку C++/CX можно добавить, используя страницу свойств C++/WinRT проекта в Visual Studio. В свойствах проекта поочередно выберите Общие свойства>C++/WinRT>Язык проекта>C++/CX. При этом в файл .vcxproj
будет добавлено следующее свойство.
<PropertyGroup Label="Globals">
<CppWinRTProjectLanguage>C++/CX</CppWinRTProjectLanguage>
</PropertyGroup>
Важно!
Каждый раз, когда необходимо выполнить сборку для обработки содержимого файла Midl File (.idl) в файлы заглушек, язык проекта необходимо будет снова сменить на C++/WinRT. После того, как сборка создала эти заглушки, измените язык проекта обратно на C++/CX.
Список похожих параметров настройки (которые управляют поведением средства cppwinrt.exe
) см. в файле сведений пакета NuGet Microsoft.Windows.CppWinRT.
Меньшее, что вы должны сделать, это включить в ваш прекомпилированный файл заголовка (обычно pch.h
) winrt/base.h
, как показано ниже.
// pch.h
...
#include <winrt/base.h>
...
Но вам почти наверняка понадобятся типы в пространстве имен winrt::Windows::Foundation. И, возможно, вы уже знаете о других пространствах имен, которые могут пригодиться. Поэтому включите проектируемые заголовки C++/WinRT Windows API, которые соответствуют таким пространствам имен, как это (теперь winrt/base.h
не нужно добавлять намеренно, потому он добавляется автоматически).
// pch.h
...
#include <winrt/Windows.Foundation.h>
// Include any other C++/WinRT projected Windows API headers here.
...
Также просмотрите пример кода в следующем разделе (Создание проекта C++/WinRT и добавление поддержки C++/CX), чтобы узнать сведения о технике, использующей псевдонимы пространства имен namespace cx
и namespace winrt
. Эта техника позволяет справиться с потенциальными расхождениями пространств имен между проекцией C++/WinRT и C++/CX.
Теперь вы можете добавить функции from_cx и to_cx в проект C++/CX. Инструкции к выполнению этой команды см. выше в разделе Функции from_cx и to_cx .
В этом разделе описывается, что делать, если вы решили создать новый проект C++/WinRT и выполнить перенос.
Для объединения C++/WinRT и C++/CX в проекте C++/WinRT, в том числе использования в проекте вспомогательных функций from_cx и to_cx, необходимо вручную добавить в проект поддержку C++/CX.
В этом разделе можно создать пример проекта C++/WinRT, в котором продемонстрировано использование from_cx и to_cx. В нем также показано, как использовать псевдонимы пространства имен для различных участков кода, чтобы справиться с потенциальными противоречиями пространства имен между проекциями C++/WinRT и C++/CX.
interop_helpers.h
в проект. Инструкции к выполнению этой команды см. выше в разделе Функции from_cx и to_cx .App.cpp
кодом из листинга ниже.WINRT_ASSERT
— это макроопределение, которое передается в _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>());
}
Обучение
Схема обучения
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization