Реализация поставщика веб-каналов в приложении win32 (C++/WinRT)
Примечание.
Некоторые сведения относятся к предварительной версии продукта, в которую перед коммерческим выпуском могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В этой статье описывается создание простого поставщика веб-каналов, который регистрирует URI содержимого веб-канала и реализует интерфейс IFeedProvider . Методы этого интерфейса вызываются доска мини-приложений для запроса пользовательских параметров строки запроса, как правило, для поддержки сценариев проверки подлинности. Поставщики веб-каналов могут поддерживать один веб-канал или несколько веб-каналов.
Сведения о реализации поставщика веб-каналов с помощью C++/WinRT см. в разделе "Реализация поставщика веб-каналов" в приложении Windows C# (C++/WinRT).
Необходимые компоненты
- Устройство должно быть включено в режиме разработчика. Дополнительные сведения см. в разделе "Включение устройства для разработки".
- Visual Studio 2022 или более поздней версии с рабочей нагрузкой разработки универсальная платформа Windows. Обязательно добавьте компонент для C++ (версии 143) из дополнительного раскрывающегося списка.
Создание консольного приложения C++/WinRT win32
В Visual Studio создайте проект . В диалоговом окне "Создание проекта" установите для фильтра языка значение "C++" и фильтр платформы в Windows, а затем выберите шаблон проекта консольного приложения Windows (C++/WinRT). Назовите новый проект ExampleFeedProvider. В этом пошаговом руководстве убедитесь, что решение и проект place в том же каталоге сняты. При появлении запроса задайте целевую версию Windows для приложения 10.022631.2787 или более поздней версии.
Добавление ссылок на пакеты NuGet пакета SDK для приложений Windows и библиотеки реализации Windows
В этом примере используется последний стабильный пакет Пакета NuGet для приложений Windows. В Обозреватель решений щелкните правой кнопкой мыши ссылки и выберите пункт "Управление пакетами NuGet...". В диспетчере пакетов NuGet перейдите на вкладку "Обзор" и найдите "Microsoft.WindowsAppSDK". Выберите последнюю стабильную версию в раскрывающемся списке "Версия" , а затем нажмите кнопку "Установить".
В этом примере также используется пакет NuGet библиотеки реализации Windows. В Обозреватель решений щелкните правой кнопкой мыши ссылки и выберите пункт "Управление пакетами NuGet...". В диспетчере пакетов NuGet перейдите на вкладку "Обзор" и найдите "Microsoft.Windows.ImplementationLibrary". Выберите последнюю версию в раскрывающемся списке "Версия" и нажмите кнопку "Установить".
В предварительно скомпилированного файла заголовка pch.h добавьте следующие директивы include.
//pch.h
#pragma once
#include <wil/cppwinrt.h>
#include <wil/resource.h>
...
#include <winrt/Microsoft.Windows.Widgets.Providers.h>
Примечание.
Перед любыми заголовками WinRT необходимо сначала включить заголовок wil/cppwinrt.h.
Чтобы правильно завершить работу приложения поставщика веб-каналов, необходимо настроить пользовательскую реализацию winrt::get_module_lock. Мы предварительно объявляем метод SignalLocalServerShutdown , который будет определен в нашем main.cpp файле и установим событие, которое сигнализирует приложению о выходе. Добавьте следующий код в файл pch.h, непосредственно под директивой #pragma once
, прежде чем другие включают.
//pch.h
#include <stdint.h>
#include <combaseapi.h>
// In .exe local servers the class object must not contribute to the module ref count, and use
// winrt::no_module_lock, the other objects must and this is the hook into the C++ WinRT ref counting system
// that enables this.
void SignalLocalServerShutdown();
namespace winrt
{
inline auto get_module_lock() noexcept
{
struct service_lock
{
uint32_t operator++() noexcept
{
return ::CoAddRefServerProcess();
}
uint32_t operator--() noexcept
{
const auto ref = ::CoReleaseServerProcess();
if (ref == 0)
{
SignalLocalServerShutdown();
}
return ref;
}
};
return service_lock{};
}
}
#define WINRT_CUSTOM_MODULE_LOCK
Добавление класса FeedProvider для обработки операций веб-канала
В Visual Studio щелкните проект правой ExampleFeedProvider
кнопкой мыши в Обозреватель решений и выберите "Класс надстройки>". В диалоговом окне "Добавление класса" назовите класс "FeedProvider" и нажмите кнопку "Добавить".
Объявление класса, реализующего интерфейс IFeedProvider
Интерфейс IFeedProvider определяет методы, которые совет мини-приложений вызывает для запуска операций с поставщиком веб-канала. Замените пустое определение класса в файле FeedProvider.h следующим кодом. Этот код объявляет структуру, которая реализует интерфейс IFeedProvider и объявляет прототипы для методов интерфейса.
// FeedProvider.h
#pragma once
struct FeedProvider : winrt::implements<FeedProvider, winrt::Microsoft::Windows::Widgets::Feeds::Providers::IFeedProvider>
{
FeedProvider() {}
/* IFeedrovider required functions that need to be implemented */
void OnFeedProviderEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderEnabledArgs args);
void OnFeedProviderDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderDisabledArgs args);
void OnFeedEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedEnabledArgs args);
void OnFeedDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedDisabledArgs args);
void OnCustomQueryParametersRequested(winrt::Microsoft::Windows::Widgets::Feeds::Providers::CustomQueryParametersRequestedArgs args);
/* IFeedProvider required functions that need to be implemented */
};
Реализация методов IFeedProvider
В следующих нескольких разделах мы реализуем методы интерфейса IFeedProvider . Перед погружением в методы интерфейса добавьте следующие строки FeedProvider.cpp
в после директив включения, чтобы извлечь API поставщика веб-каналов в пространство имен winrt и разрешить доступ к карте, объявленной на предыдущем шаге.
Примечание.
Объекты, передаваемые в методы обратного вызова интерфейса IFeedProvider , гарантированно допустимы только в обратном вызове. Не следует хранить ссылки на эти объекты, так как их поведение вне контекста обратного вызова не определено.
// WidgetProvider.cpp
namespace winrt
{
using namespace Microsoft::Windows::Widgets::Feeds::Providers;
}
OnFeedProviderEnabled
Метод OnFeedProviderEnabled вызывается, когда веб-канал, связанный с поставщиком, создается узлом Мини-приложения Board. В реализации этого метода создайте строку запроса с параметрами, которые будут переданы URL-адресу, который предоставляет содержимое веб-канала, включая все необходимые маркеры проверки подлинности. Создайте экземпляр CustomQueryParametersUpdateOptions, передавая в feedProviderDefinitionId из аргов событий, определяющих веб-канал, включенный и строку запроса. Получите по умолчанию FeedManager и вызовите SetCustomQueryParameters , чтобы зарегистрировать параметры строки запроса в Board мини-приложений.
// FeedProvider.cs
void FeedProvider::OnFeedProviderEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderEnabledArgs args)
{
std::wstringstream wstringstream;
wstringstream << args.FeedProviderDefinitionId().c_str() << L" feed provider was enabled." << std::endl;
_putws(wstringstream.str().c_str());
auto updateOptions = winrt::CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId(), L"param1¶m2");
winrt::FeedManager::GetDefault().SetCustomQueryParameters(updateOptions);
}
OnFeedProviderDisabled
OnFeedProviderDisabled вызывается при отключении всех веб-каналов для этого поставщика. Поставщики веб-каналов не требуются для выполнения каких-либо действий в ответ на этот вызов метода. Вызов метода можно использовать для целей телеметрии или обновления параметров строки запроса или отзыва маркеров проверки подлинности при необходимости. Если приложение поддерживает только одного поставщика веб-каналов или если все поставщики веб-каналов, поддерживаемые приложением, были отключены, приложение может выйти в ответ на этот обратный вызов.
// FeedProvider.cs
void FeedProvider::OnFeedProviderDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderDisabledArgs args)
{
std::wstringstream wstringstream;
wstringstream << args.FeedProviderDefinitionId().c_str() << L" feed provider was disabled." << std::endl;
_putws(wstringstream.str().c_str());
}
OnFeedEnabled, OnFeedDisabled
OnFeedEnabled и OnFeedDisabled вызываются советом мини-приложений при включении или отключении веб-канала. Поставщики веб-каналов не требуются для выполнения каких-либо действий в ответ на эти вызовы метода. Вызов метода можно использовать для целей телеметрии или обновления параметров строки запроса или отзыва маркеров проверки подлинности при необходимости.
// FeedProvider.cs
void FeedProvider::OnFeedEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedEnabledArgs args)
{
std::wstringstream wstringstream;
wstringstream << args.FeedDefinitionId().c_str() << L" feed was enabled." << std::endl;
_putws(wstringstream.str().c_str());
}
// FeedProvider.cs
void FeedProvider::OnFeedDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedDisabledArgs args)
{
std::wstringstream wstringstream;
wstringstream << args.FeedDefinitionId().c_str() << L" feed was disabled." << std::endl;
_putws(wstringstream.str().c_str());
}
OnCustomQueryParametersRequested
OnCustomQueryParametersRequested возникает, когда доска мини-приложений определяет, что пользовательские параметры запроса, связанные с поставщиком веб-канала, необходимо обновить. Например, этот метод может возникать, если операция получения содержимого веб-канала из удаленной веб-службы завершается ошибкой. Свойство FeedProviderDefinitionId объекта CustomQueryParametersRequestedArgs , переданное в этот метод, указывает канал, для которого запрашиваются параметры строки запроса. Поставщик должен повторно создать строку запроса и передать ее обратно в доску мини-приложений, вызвав SetCustomQueryParameters.
// FeedProvider.cs
void FeedProvider::OnCustomQueryParametersRequested(winrt::Microsoft::Windows::Widgets::Feeds::Providers::CustomQueryParametersRequestedArgs args)
{
std::wstringstream wstringstream;
wstringstream << L"CustomQueryParameters were requested for " << args.FeedProviderDefinitionId().c_str() << std::endl;
_putws(wstringstream.str().c_str());
auto updateOptions = winrt::CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId(), L"param1¶m2");
winrt::FeedManager::GetDefault().SetCustomQueryParameters(updateOptions);
}
Регистрация фабрики классов, которая создаст экземпляр FeedProvider по запросу
Добавьте заголовок, определяющий класс FeedProvider , в список в верхней части файла приложения main.cpp
. Мы также будем включать мьютекс здесь.
// main.cpp
...
#include "FeedProvider.h"
#include <mutex>
Объявите событие, которое активирует наше приложение для выхода и функцию SignalLocalServerShutdown , которая установит событие. Вставьте следующий код в main.cpp.
// main.cpp
wil::unique_event g_shudownEvent(wil::EventOptions::None);
void SignalLocalServerShutdown()
{
g_shudownEvent.SetEvent();
}
Затем необходимо создать CLSID , который будет использоваться для идентификации поставщика веб-канала для активации COM. Создайте GUID в Visual Studio, перейдя в раздел "Сервис-создание> GUID". Выберите параметр "статический guid констант =" и нажмите кнопку "Копировать ", а затем вставьте его main.cpp
. Обновите определение GUID следующим синтаксисом C++/WinRT, задав имя переменной GUID feed_provider_clsid. Оставьте закомментированную версию GUID, так как вам потребуется этот формат позже при упаковке приложения.
// main.cpp
...
// {80F4CB41-5758-4493-9180-4FB8D480E3F5}
static constexpr GUID feed_provider_clsid
{
0x80f4cb41, 0x5758, 0x4493, { 0x91, 0x80, 0x4f, 0xb8, 0xd4, 0x80, 0xe3, 0xf5 }
};
Добавьте следующее определение main.cpp
фабрики классов. В основном это стандартный код, который не предназначен для реализации поставщика веб-каналов. Обратите внимание, что CoWaitForMultipleObjects ожидает активации события завершения работы до выхода приложения.
// main.cpp
template <typename T>
struct SingletonClassFactory : winrt::implements<SingletonClassFactory<T>, IClassFactory>
{
STDMETHODIMP CreateInstance(
::IUnknown* outer,
GUID const& iid,
void** result) noexcept final
{
*result = nullptr;
std::unique_lock lock(mutex);
if (outer)
{
return CLASS_E_NOAGGREGATION;
}
if (!instance)
{
instance = winrt::make<FeedProvider>();
}
return instance.as(iid, result);
}
STDMETHODIMP LockServer(BOOL) noexcept final
{
return S_OK;
}
private:
T instance{ nullptr };
std::mutex mutex;
};
int main()
{
winrt::init_apartment();
wil::unique_com_class_object_cookie feedProviderFactory;
auto factory = winrt::make<SingletonClassFactory<winrt::Microsoft::Windows::Widgets::Feeds::Providers::IFeedProvider>>();
winrt::check_hresult(CoRegisterClassObject(
feed_provider_clsid,
factory.get(),
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
feedProviderFactory.put()));
DWORD index{};
HANDLE events[] = { g_shudownEvent.get() };
winrt::check_hresult(CoWaitForMultipleObjects(CWMO_DISPATCH_CALLS | CWMO_DISPATCH_WINDOW_MESSAGES,
INFINITE,
static_cast<ULONG>(std::size(events)), events, &index));
return 0;
}
Упаковка приложения поставщика веб-каналов
В текущем выпуске только упакованные приложения можно зарегистрировать в качестве поставщиков веб-каналов. Ниже описано, как упаковать приложение и обновить манифест приложения, чтобы зарегистрировать приложение в качестве поставщика веб-канала.
Создание проекта упаковки MSIX
В Обозреватель решений щелкните решение правой кнопкой мыши и выберите "Добавить> новый проект...". В диалоговом окне "Добавление нового проекта" выберите шаблон "Проект упаковки приложений Windows" и нажмите кнопку "Далее". Задайте для имени проекта значение ExampleFeedProviderPackage и нажмите кнопку "Создать". При появлении запроса задайте целевую версию версии 1809 или более поздней и нажмите кнопку "ОК". Затем щелкните правой кнопкой мыши проект ExampleFeedProviderPackage и выберите ссылку add-Project>. Выберите проект ExampleFeedProvider и нажмите кнопку "ОК".
Добавление ссылки на пакет sdk для приложений Windows в проект упаковки
Необходимо добавить ссылку на пакет nuget пакета sdk для приложений Windows в проект упаковки MSIX. В Обозреватель решений дважды щелкните проект ExampleFeedProviderPackage, чтобы открыть файл ExampleFeedProviderPackage.wapproj. Добавьте следующий xml-код в элемент Project .
<!--ExampleFeedProviderPackage.wapproj-->
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231116003-experimentalpr">
<IncludeAssets>build</IncludeAssets>
</PackageReference>
</ItemGroup>
Примечание.
Убедитесь, что версия , указанная в элементе PackageReference , соответствует последней стабильной версии, на которая ссылается на предыдущий шаг.
Если на компьютере уже установлена правильная версия пакета SDK для приложений Windows, и вы не хотите упаковывать среду выполнения пакета в пакет, можно указать зависимость пакета в файле Package.appxmanifest для проекта ExampleFeedProviderPackage.
<!--Package.appxmanifest-->
...
<Dependencies>
...
<PackageDependency Name="Microsoft.WindowsAppRuntime.1.5.233430000-experimental1" MinVersion="2000.638.7.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
...
</Dependencies>
...
Обновление манифеста пакета
В Обозреватель решений щелкните файл правой кнопкой мыши Package.appxmanifest
и выберите команду Просмотреть код, чтобы открыть XML-файл манифеста. Затем необходимо добавить некоторые объявления пространства имен для расширений пакета приложения, которые мы будем использовать. Добавьте следующие определения пространства имен в элемент package верхнего уровня.
<!-- Package.appmanifest -->
<Package
...
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
В элементе Application создайте пустой элемент с именем Extensions. Убедитесь, что это происходит после закрывающего тега uap :VisualElements.
<!-- Package.appxmanifest -->
<Application>
...
<Extensions>
</Extensions>
</Application>
Первым расширением , который необходимо добавить, является расширение ComServer . Это регистрирует точку входа исполняемого файла в ОС. Это расширение является эквивалентом упаковаемого приложения регистрации COM-сервера, задав раздел реестра и не зависит от поставщиков веб-каналов. Добавьте следующий элемент com:Extension в качестве дочернего элемента Extensions . Измените GUID в атрибуте идентификатора элемента com:Class на GUID, созданный на предыдущем шаге.
<!-- Package.appxmanifest -->
<Extensions>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="ExampleFeedProvider\ExampleFeedProvider.exe" Arguments="-RegisterProcessAsComServer" DisplayName="C++ Feed Provider App">
<com:Class Id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" DisplayName="FeedProvider" />
</com:ExeServer>
</com:ComServer>
</com:Extension>
</Extensions>
Затем добавьте расширение, которое регистрирует приложение в качестве поставщика веб-канала. Вставьте элемент uap3:Extension в следующий фрагмент кода в качестве дочернего элемента Extensions. Обязательно замените атрибут ClassId элемента COM идентификатором GUID, который использовался на предыдущих шагах.
<!-- Package.appxmanifest -->
<Extensions>
...
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.widgets.feeds" DisplayName="ContosoFeed" Id="com.examplewidgets.examplefeed" PublicFolder="Public">
<uap3:Properties>
<FeedProvider Icon="ms-appx:Assets\StoreLogo.png" Description="FeedDescription">
<Activation>
<!-- Apps exports COM interface which implements IFeedProvider -->
<CreateInstance ClassId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
</Activation>
<Definitions>
<Definition Id="Contoso_Feed"
DisplayName="Contoso_Feed Feed"
Description="Feed representing Contoso"
ContentUri="https://www.contoso.com/"
Icon="ms-appx:Images\StoreLogo.png">
</Definition>
<Definition Id="Fabrikam_Feed"
DisplayName="Fabrikam Feed"
Description="Feed representing Example"
ContentUri="https://www.fabrikam.com/"
Icon="ms-appx:Images\StoreLogo.png">
</Definition>
</Definitions>
</FeedProvider>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
</Extensions>
Подробные описания и сведения о форматировании всех этих элементов см . в формате XML манифеста пакета поставщика веб-канала.
Добавление значков в проект упаковки
В Обозреватель решений щелкните правой кнопкой мыши объект ExampleFeedProviderPackage и выберите "Добавить новую> папку". Назовите эту папку ProviderAssets так, как это было использовано на Package.appxmanifest
предыдущем шаге. Здесь мы будем хранить значок для наших веб-каналов. После добавления нужных значков убедитесь, что имена изображений совпадают с тем, что происходит после Path=ProviderAssets\ в веб-каналах Package.appxmanifest
, которые не будут отображаться в доске мини-приложений.
Тестирование поставщика веб-канала
Убедитесь, что вы выбрали архитектуру, соответствующую компьютеру разработки, в раскрывающемся списке "Платформы решений", например "x64". В Обозреватель решений щелкните решение правой кнопкой мыши и выберите команду "Создать решение". После этого щелкните правой кнопкой мыши имя ExampleWidgetProviderPackage и выберите "Развернуть". Консольное приложение должно запускаться при развертывании, и вы увидите, что веб-каналы включены в выходных данных консоли. Откройте доску мини-приложений и вы увидите новые веб-каналы на вкладках в верхней части раздела веб-каналов.
Отладка поставщика веб-канала
После закрепления веб-каналов платформа мини-приложений запустит приложение поставщика веб-каналов для получения и отправки соответствующих сведений о веб-канале. Чтобы выполнить отладку запущенного веб-канала, можно подключить отладчик к приложению поставщика веб-каналов или настроить Visual Studio для автоматической отладки процесса поставщика веб-каналов после его запуска.
Чтобы подключиться к выполняемой процедуре, выполните следующие действия:
- В Visual Studio щелкните "Отладка—> присоединение к процессу".
- Отфильтруйте процессы и найдите нужное приложение поставщика веб-каналов.
- Подключение отладчика.
Чтобы автоматически подключить отладчик к процессу при первоначальном запуске:
- В Visual Studio щелкните "Отладка "> Другие целевые объекты отладки —> отладка установленного пакета приложения".
- Отфильтруйте пакеты и найдите нужный пакет поставщика веб-каналов.
- Установите его и установите флажок, который говорит, что не запускается, но отлаживать код при запуске.
- Нажмите кнопку Присоединить.
Преобразование консольного приложения в приложение Windows
Чтобы преобразовать консольное приложение, созданное в этом пошаговом руководстве, в приложение Windows:
- Щелкните правой кнопкой мыши проект ExampleWidgetProvider в Обозреватель решений и выберите "Свойства". Перейдите к компоновщику —> система и измените подсистему с консоли на Windows. Это также можно сделать, добавив <подсистему>Windows</SubSystem> в <Link>..</Link> раздела .vcxproj.
- В main.cpp перейдите
int main()
наint WINAPI wWinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ PWSTR pCmdLine, _In_ int /*nCmdShow*/)
.
Публикация приложения поставщика веб-каналов
После разработки и тестирования поставщика веб-каналов вы можете опубликовать приложение в Microsoft Store, чтобы пользователи могли устанавливать веб-каналы на своих устройствах. Пошаговые инструкции по публикации приложения см. в статье "Публикация приложения в Microsoft Store".
Коллекция хранилища веб-каналов
После публикации приложения в Microsoft Store вы можете запросить включение приложения в коллекцию магазинов веб-каналов, которая помогает пользователям обнаруживать приложения, которые содержат веб-каналы Windows. Чтобы отправить запрос, см. статью "Отправить веб-канал или доску" для добавления в коллекцию Магазинов.
Windows developer