Начало работы с C++/WinRT
Внимание
Сведения об установке Visual Studio для разработки с использованием C++/WinRT, включая установку и использование расширения C++/WinRT для Visual Studio (VSIX) и пакета NuGet (которые вместе обеспечивают поддержку шаблона проекта и сборки), приведены в разделе Поддержка Visual Studio для C++/WinRT.
В этой статье рассматривается простой пример кода на основе нового проекта консольного приложения для Windows (C++/WinRT), который поможет вам начать работу с C++/WinRT. Здесь также показано, как добавить поддержку C++/WinRT в проект классического приложения для Windows.
Примечание.
Хотя рекомендуется разрабатывать с помощью последних версий Visual Studio и пакета SDK для Windows, Если вы используете Visual Studio 2017 (версия 15.8.0 или более поздней версии) и предназначение для пакета SDK для Windows версии 10.0.17134.0 (Windows 10 версии 1803), то созданный проект C++/WinRT может не скомпилироваться с ошибкой "error C3861: "from_abi": идентификатор не найден" и с другими ошибками, возникающими в base.h. Следует разрабатывать проект с более поздней (лучше соответствующей) версией Windows SDK или задать свойство проекта C/C++>Язык>Режим совместимости: Нет (кроме того, если параметр /permissive- отображается в свойстве проекта C/C++>Язык>Командная строка в разделе Дополнительные параметры, удалите его).
Краткое руководство по C++/WinRT
Создайте проект консольного приложения для Windows (C++/WinRT).
Отредактируйте файлы pch.h
и main.cpp
следующим образом.
// pch.h
#pragma once
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
// main.cpp
#include "pch.h"
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;
int main()
{
winrt::init_apartment();
Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
SyndicationClient syndicationClient;
syndicationClient.SetRequestHeader(L"User-Agent", L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
for (const SyndicationItem syndicationItem : syndicationFeed.Items())
{
winrt::hstring titleAsHstring = syndicationItem.Title().Text();
// A workaround to remove the trademark symbol from the title string, because it causes issues in this case.
std::wstring titleAsStdWstring{ titleAsHstring.c_str() };
titleAsStdWstring.erase(remove(titleAsStdWstring.begin(), titleAsStdWstring.end(), L'™'), titleAsStdWstring.end());
titleAsHstring = titleAsStdWstring;
std::wcout << titleAsHstring.c_str() << std::endl;
}
}
Подробно рассмотрим небольшой пример кода выше с объяснением того, что происходит в каждой части.
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
В соответствии с параметрами проекта по умолчанию включенные заголовки берутся из пакета Windows SDK внутри папки %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt
. Visual Studio включает этот путь в своем макросе IncludePath. Строгой зависимости от пакета Windows SDK нет, потому что проект (с помощью средства cppwinrt.exe
) создает те же самые заголовки в своей папке $(GeneratedFilesDir). Они будут загружены из этой папки, если их невозможно найти в другом расположении или если вы измените параметры проекта.
Заголовки содержат API-интерфейсы Windows, проецируемые в C++/WinRT. Другими словами, для каждого типа Windows проекция C++/WinRT определяет эквивалентный тип для C++ (проецируемый тип). Проецируемый тип имеет то же полное доменное имя, что и тип в Windows, но он размещается в пространстве имен C++ winrt. Добавление этих инструкций include в предварительно скомпилированный заголовок сокращает время сборки.
Внимание
Каждый раз, когда вы хотите использовать тип из пространств имен Windows, необходимо включить (#include
) соответствующий файл заголовков пространства имен C++/WinRT для Windows, как показано выше. Соответствующий заголовок — это заголовок с таким же именем, как у пространства имен типа. Например, чтобы использовать проекцию C++/WinRT для класса среды выполнения Windows::Foundation::Collections::PropertySet, добавьте заголовок winrt/Windows.Foundation.Collections.h
.
Обычно заголовок проекции C++/WinRT автоматически включает связанные файлы заголовков пространства имен. Например, winrt/Windows.Foundation.Collections.h
включает winrt/Windows.Foundation.h
. Но не следует полагаться на такое поведение, так как это сведения о реализации, которые меняются со временем. Необходимо явно включить все требуемые заголовки.
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;
Директивы using namespace
являются необязательными, но удобными. Приведенный выше шаблон для таких директив (позволяющий выполнять поиск любых элементов в пространстве имен winrt по неполному имени) подходит при начале работы с новым проектом, при этом C++/WinRT — единственная проекция языка, которую вы используете внутри этого проекта. Если, с другой стороны, вы объединяете код C++/WinRT с кодом C++/CX или двоичным интерфейсом приложения SDK (ABI) (вы осуществляете перенос или взаимодействуете с этим кодом либо используете обе этих модели), изучите статьи Взаимодействие между C++/WinRT и C++/CX, Переход на C++/WinRT из C++/CX и Взаимодействие между C++/WinRT и интерфейсом ABI.
winrt::init_apartment();
Вызов winrt::init_apartment инициализирует поток в среде выполнения Windows (по умолчанию — в многопотоковом подразделении). Вызов также инициализирует COM.
Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
SyndicationClient syndicationClient;
Разместите в стеке два объекта: они представляют URI блога о Windows и клиент синдикации. Мы создаем URI с помощью простого литерала широкой строки (дополнительные способы работы со строками см. в статье Обработка строк в C++/WinRT).
SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
SyndicationClient::RetrieveFeedAsync является примером асинхронной функции среды выполнения Windows. Этот пример кода получает объект асинхронной операции от RetrieveFeedAsync и вызывает get для этого объекта, чтобы заблокировать вызывающий поток и дождаться результата (в данном случае это веб-канал синдикации). Дополнительные сведения о параллелизме и неблокирующих методах см. в статье Параллельная обработка и асинхронные операции с помощью C++/WinRT.
for (const SyndicationItem syndicationItem : syndicationFeed.Items()) { ... }
SyndicationFeed.Items является диапазоном, определяемым итераторами, возвращенными функциями begin и end (или их постоянными, обратными, либо постоянно-обратными вариантами). По этой причине вы можете перечислять Items с помощью основанного на диапазоне оператора for
или функции шаблона std::for_each. Всякий раз, когда вы проходите подобную коллекцию среды выполнения Windows, вам требуется #include <winrt/Windows.Foundation.Collections.h>
.
winrt::hstring titleAsHstring = syndicationItem.Title().Text();
// Omitted: there's a little bit of extra work here to remove the trademark symbol from the title text.
std::wcout << titleAsHstring.c_str() << std::endl;
Этот код получает текст заголовка канала в виде объекта winrt::hstring (см. сведения в статье Обработка строк в C++/WinRT). Затем hstring выводится с помощью функции c_str, которая отражает шаблон, используемый в строках стандартной библиотеки C++.
Как видно, C++/WinRT поощряет использование современных аналогичных классам выражений C++, таких как syndicationItem.Title().Text()
. Это более ясный стиль программирования, отличающийся от традиционного COM-программирования. Вам не нужно напрямую инициализировать COM или работать с указателями СОМ.
Вам также не нужно обрабатывать коды возврата HRESULT. C++/ WinRT преобразует ошибки HRESULT в исключения, такие как winrt::hresult-error, для использования естественного и современного стиля программирования. Дополнительные сведения об обработке ошибок и примеры кода см. в статье Обработка ошибок в C++/WinRT.
Добавление поддержки C++/WinRT в проекте классического приложения для Windows
Некоторые проекты для настольных систем (например, шаблоны WinUI 3 в Visual Studio) имеют встроенную поддержку C++/WinRT.
Но в этом разделе вы узнаете, как добавить поддержку C++/WinRT в любой проект классического приложения для Windows. Если у вас нет проекта классического приложения для Windows, вы можете выполнить эти шаги, чтобы создать его. Например, откройте Visual Studio и создайте проект Visual C++>Рабочий стол Windows>Классическое приложение для Windows.
При желании можно установить расширение C++/WinRT для Visual Studio (VSIX) и пакет NuGet. Дополнительные сведения см. в разделе о поддержке C++/WinRT в Visual Studio.
Настройка свойств проекта
Перейдите к свойству проекта Общие>Версия пакета SDK для Windows и выберите Все конфигурации и Все платформы. Убедитесь, что для версии пакета Windows SDK установлено значение 10.0.17134.0 (Windows 10 версии 1803) или выше.
Убедитесь, что у вас не возникает ситуация, описанная в разделе Почему мой новый проект не компилируется?.
Так как C++/WinRT использует компоненты стандарта C++17, необходимо установить для свойства проекта C/C++>Язык>Стандарт языка C++ значение Стандарт ISO C++17 (/std:c++17).
Предварительно скомпилированный заголовок
Шаблон проекта по умолчанию создает для вас предварительно скомпилированный заголовок с именем framework.h
или stdafx.h
. Переименуйте его на pch.h
. Если у вас есть файл stdafx.cpp
, переименуйте его на pch.cpp
. Установите для свойства проекта C/C++>Предварительно скомпилированные заголовки>Предварительно скомпилированный заголовок значение Create (/Yc) (Создать (/Yc)), а для свойства Предварительно скомпилированный заголовочный файл значение pch.h.
Найдите и замените все элементы #include "framework.h"
(или #include "stdafx.h"
) на #include "pch.h"
.
В pch.h
добавьте winrt/base.h
.
// pch.h
...
#include <winrt/base.h>
Связывание
Языковая проекция C++/WinRT зависит от определенных свободных функций среды выполнения Windows (не являющихся членами) и точек входа, для которых требуется связывание с библиотекой WindowsApp.lib. В этом разделе описываются три варианта соответствия компоновщику.
Первый вариант — добавить в ваш проект Visual Studio все свойства и цели C++/WinRT MSBuild. Для этого установите пакет NuGet Microsoft.Windows.CppWinRT в проект. В Visual Studio откройте проект, выберите Проект>Управление пакетами NuGet...>Обзор, введите или вставьте Microsoft.Windows.CppWinRT в поле поиска, выберите элемент в результатах поиска, а затем нажмите кнопку Установить чтобы установить пакет для этого проекта.
Вы также можете использовать параметры компоновки проекта для явного включения WindowsApp.lib
. Кроме того, это можно сделать в исходном коде (например, в pch.h
) следующим образом.
#pragma comment(lib, "windowsapp")
Теперь вы можете выполнить компиляцию, связать и добавить код C++/WinRT в ваш проект (например, код, подобный тому, который показан в разделе Краткое руководство по C++/WinRT выше).
Три основных сценария для C++/WinRT
По мере работы с C++/WinRT и ознакомления с остальной частью документации вы, скорее всего, заметите, что есть три основных сценария. Они описаны в следующих разделах.
Использование типов и интерфейсов API Windows
Иными словами, это использование и вызовы API. Например, вы можете выполнять вызовы API для обмена данными по Bluetooth, потоковую передачу и воспроизведение видео, интеграцию с оболочкой Windows и т. д. В C++/WinRT реализована полная поддержка этого сценария. Дополнительные сведения см. в статье Использование API-интерфейсов с помощью C++/WinRT.
Создание типов и интерфейсов API Windows
Иными словами, это создание API и типов. Например, вы можете создавать описанные в разделе выше типы API, графические API, API хранилища и файловой системы, сетевые API и т. д. Дополнительные сведения см. в статье Создание API-интерфейсов в C++/WinRT.
Разработка API с помощью C++/WinRT — это более сложный процесс, чем их использование, так как вам нужно работать с IDL для определения API перед его реализацией. Описание процесса см. в статье Элементы управления XAML; привязка к свойству C++/WinRT.
Приложения XAML
Этот сценарий предполагает создания приложений и элементов управления в пользовательском интерфейсе на основе XAML. Работа с приложением, созданным с использованием XAML, включает процессы использования и разработки. Но так как сегодня XAML является основным средством описания пользовательского интерфейса в Windows, которое оказывает огромное влияние на среду выполнения Windows пропорционально этому, для него предусмотрен отдельный сценарий.
Помните, что XAML лучше всего сочетается с языками программирования, в которых используется рефлексия. В C++/WinRT, чтобы взаимодействовать с XAML, иногда необходимо выполнить некоторую дополнительную работу. Все эти случаи описаны в документации. Лучше всего начать со статей Элементы управления XAML; привязка к свойству C++/WinRT и Создание пользовательских (на основе шаблона) элементов управления XAML с помощью C++/WinRT.
Примеры приложений, написанные на C++/WinRT
См. раздел Где можно найти примеры приложений C++/WinRT?.
Важные API
- Метод SyndicationClient::RetrieveFeedAsync
- Свойство SyndicationFeed.Items
- Структура winrt::hstring
- Структура winrt::hresult_error