Начало работы с C++/WinRT

Это важно

Сведения о настройке Visual Studio для разработки C++/WinRT, включая установку и использование расширения C++/WinRT Visual Studio (VSIX) и пакета NuGet (которые вместе предоставляют поддержку шаблона проекта и сборки),см. Visual Studio поддержку C++/WinRT.

Чтобы ускорить работу с помощью C++/WinRT, в этом разделе описывается простой пример кода на основе нового проекта консольного приложения Windows (C++/WinRT). В этом разделе также показано, как добавить поддержку C++/WinRT в проект приложения Windows Desktop.

Note

Хотя мы рекомендуем разрабатывать с использованием последних версий Visual Studio и Windows SDK, если вы используете Visual Studio 2017 (версии 15.8.0 или более поздней) и ориентируетесь на Windows SDK версии 10.0.17134.0 (Windows 10, версия 1803), то вновь созданный проект C++/WinRT может не скомпилироваться с ошибкой "error C3861: 'from_abi': identifier not found", а также с другими ошибками, возникающими в base.h. Решение состоит в том, чтобы либо использовать более позднюю (лучше соответствующую стандарту) версию Windows SDK, либо задать для свойства проекта C/C++>Language>Conformance mode: No (также, если /permissive- отображается в свойстве проекта C/C++>Language>Command Line в разделе Additional Options, удалите его).

Краткое введение в 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>

При использовании параметров проекта по умолчанию включенные заголовки приходят из пакета SDK Windows в папке%WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt. Visual Studio включает этот путь в макрос IncludePath. Но строгой зависимости от Windows SDK нет, поскольку ваш проект (с помощью средства cppwinrt.exe) генерирует эти же заголовочные файлы в папке $(GeneratedFilesDir) вашего проекта. Они будут загружены из этой папки, если их не удается найти в другом месте или если вы измените параметры проекта.

Заголовки содержат Windows API, проецируемые в C++/WinRT. Другими словами, для каждого типа Windows C++/WinRT определяет эквивалент, удобный для C++ (называемый проецируемым типом). Проецируемый тип имеет то же полное имя, что и тип Windows, но он помещается в пространство имен winrt C++. Добавление этих элементов в предварительно скомпилированные заголовки сокращает время добавочной сборки.

Это важно

Если вы хотите использовать тип из пространств имен Windows, необходимо #include использовать соответствующий файл заголовка пространства имен C++/WinRT Windows, как показано выше. Соответствующий заголовок имеет то же имя, что и пространство имен типа. Например, чтобы использовать проекцию C++/WinRT для класса среды выполнения Windows::Foundation::Collections::P ropertySet, включите 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 и/или кодом ABI (двоичного интерфейса приложения) SDK (то есть переносите код из одной или обеих этих моделей либо обеспечиваете взаимодействие с ними), см. разделы Взаимодействие между 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 — это диапазон, определенный итераторами, возвращаемыми из начальных и конечных функций (или их констант, обратных и константных обратных вариантов). Из-за этого можно перечислить элементы с помощью инструкции на основе 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, а также работать с указателями COM.

Кроме того, вам не нужно обрабатывать коды возврата HRESULT. C++/WinRT преобразует ошибки HRESULTs в исключения, такие как winrt::hresult-error для естественного и современного стиля программирования. Дополнительные сведения об обработке ошибок и примерах кода см. в статье об обработке ошибок с помощью C++/WinRT.

Изменение проекта классического приложения Windows для добавления поддержки C++/WinRT

Некоторые проекты классических приложений (например, шаблоны WinUI 3 в Visual Studio) имеют встроенную поддержку C++/WinRT.

Но в этом разделе показывается, как можно добавить поддержку C++/WinRT в любой проект классического приложения Windows, который у вас может быть. Если у вас нет существующего проекта классического приложения Windows, вы можете выполнить эти действия, сначала создав его. Например, откройте Visual Studio и создайте проект Visual C++>Windows Desktop>Windows Desktop Application.

При необходимости можно установить расширение C++/WinRT Visual Studio (VSIX) и пакет NuGet. Дополнительные сведения см. в статье «Поддержка C++/WinRT в Visual Studio».

Настройка свойств проекта

Перейдите к свойству проекта Общие>Версия Windows SDK и выберите Все конфигурации и Все платформы. Убедитесь, что версия пакета SDK для Windows имеет значение 10.0.17134.0 (Windows 10 версии 1803) или более поздней.

Убедитесь, что вас не касается проблема, описанная в Почему мой новый проект не компилируется?.

Так как C++/WinRT использует возможности стандарта C++17, установите для свойства проекта C/C++>Language>C++ Language Standard значение ISO C++17 Standard (/std:c++17).

Предварительно скомпилированные заголовки

Шаблон проекта по умолчанию создает предварительно скомпилируемый заголовок для вас с именем framework.hили stdafx.h. Переименуйте это в pch.h. Если у вас есть stdafx.cpp файл, переименуйте его pch.cppв . Задайте для свойства проекта C/C++>Предварительно скомпилированные заголовки>Предварительно скомпилированный заголовок значение Create (/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 всех свойств и целевых объектов MSBuild C++/WinRT. Для этого установите в проект пакет NuGet Microsoft.Windows.CppWinRT. Откройте проект в Visual Studio, щелкните Project>Manage NuGet Packages...>Browse, введите или вставьте Microsoft.Windows.CppWinRT в поле поиска, выберите элемент в результатах поиска, а затем нажмите Install, чтобы установить пакет для этого проекта.

Вы также можете использовать параметры ссылки проекта для явной ссылки WindowsApp.lib. Или вы можете сделать это в исходном коде (например, в pch.h) вот так.

#pragma comment(lib, "windowsapp")

Теперь вы можете компилировать и связать код C++/WinRT в проект (например, код, аналогичный приведенному в разделе быстрого запуска C++/WinRT , приведенном выше).

Три основных сценария для C++/WinRT

При использовании и ознакомлении с C++/WinRT и работе с остальной документацией вы, скорее всего, заметите, что существует три основных сценария, как описано в следующих разделах.

Использование API и типов Windows

Другими словами, использовать API или вызывать API. Например, вызовы API для обмена данными с помощью Bluetooth; для потоковой передачи и представления видео; для интеграции с оболочкой Windows и т. д. C++/WinRT полностью и бескомпромиссно поддерживает эту категорию сценария. Дополнительные сведения см. в разделе "Использование API с помощью C++/WinRT".

Разработка Windows API и типов

Другими словами, создание 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