Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В большинстве случаев доступ к экземпляру класса среда выполнения Windows можно получить из любого потока (как и большинство стандартных объектов C++). Такой класс среда выполнения Windows является гибким. Лишь небольшое число классов среда выполнения Windows, поставляемых с Windows, не являются agile-объектами, но при работе с ними необходимо учитывать их модель потоков и поведение при маршалинге (маршалинг — это передача данных через границу апартамента). Для каждого объекта среда выполнения Windows хорошо, если он по умолчанию является agile-объектом, поэтому ваши собственные типы C++/WinRT также по умолчанию являются agile-объектами.
Но вы можете отказаться от этого. У вас могут быть убедительные основания требовать, чтобы объект вашего типа находился, например, в определённом однопоточном апартаменте. Обычно это связано с требованиями к повторному входу. Но все чаще даже API пользовательского интерфейса предлагают гибкие объекты. Как правило, гибкость является самым простым и наиболее производительным вариантом. Кроме того, при реализации фабрики активации необходимо, чтобы она была agile, даже если соответствующий класс среды выполнения agile не является.
Note
среда выполнения Windows основана на COM. В терминах COM агильный класс регистрируется как ThreadingModel = Both. Дополнительные сведения о моделях потоков COM и апартаментах см. в статье Основы и использование моделей потоков COM.
Примеры кода
Давайте рассмотрим пример реализации класса среды выполнения, чтобы показать, как C++/WinRT поддерживает гибкость.
#include <winrt/Windows.Foundation.h>
using namespace winrt;
using namespace Windows::Foundation;
struct MyType : winrt::implements<MyType, IStringable>
{
winrt::hstring ToString(){ ... }
};
Поскольку мы не отказались от этого, это решение остается гибким. Winrt::реализует базовую структуру, реализуя IAgileObject и IMarshal. Реализация IMarshal использует CoCreateFreeThreadedMarshaler, чтобы корректно работать с устаревшим кодом, который не поддерживает IAgileObject.
Этот код проверяет объект для гибкости. Вызов IUnknown::as вызывает исключение, если myimpl не является agile-объектом.
winrt::com_ptr<MyType> myimpl{ winrt::make_self<MyType>() };
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.as<IAgileObject>() };
Вместо того чтобы обрабатывать исключение, вместо этого можно вызвать IUnknown::try_as .
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.try_as<IAgileObject>() };
if (iagileobject) { /* myimpl is agile. */ }
IAgileObject не имеет собственных методов, поэтому вы не можете сделать много с ним. Следующий вариант, в таком случае, более типичен.
if (myimpl.try_as<IAgileObject>()) { /* myimpl is agile. */ }
IAgileObject — это интерфейс маркера. Сам факт успешного или неуспешного выполнения запроса к IAgileObject — это всё, что можно из этого узнать и какую практическую пользу извлечь.
Отказ от поддержки гибких объектов
Вы можете явно отказаться от поддержки гибких объектов, передав структуру маркера winrt::non_agile в качестве аргумента шаблона в базовый класс.
Если вы наследуете непосредственно от winrt::implements.
struct MyImplementation: implements<MyImplementation, IStringable, winrt::non_agile>
{
...
}
Если вы создаете класс среды выполнения.
struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, winrt::non_agile>
{
...
}
Не имеет значения, где именно в вариативном пакете параметров находится структура-маркер.
Независимо от того, вы отказываетесь от гибкости, вы можете реализовать IMarshal самостоятельно. Например, вы можете использовать маркер winrt::non_agile, чтобы избежать стандартной реализации agile-объекта и самостоятельно реализовать IMarshal — возможно, для поддержки семантики маршалинга по значению.
Agile-ссылки (winrt::agile_ref)
Если вы используете объект, который не является гибким, но вам нужно передать его в некотором потенциально гибком контексте, то один из вариантов — использовать шаблон структуры winrt::agile_ref , чтобы получить гибкую ссылку на экземпляр негибкого типа или интерфейс не гибкого объекта.
NonAgileType nonagile_obj;
winrt::agile_ref<NonAgileType> agile{ nonagile_obj };
Кроме того, можно использовать функцию winrt::make_agile вспомогательной функции.
NonAgileType nonagile_obj;
auto agile{ winrt::make_agile(nonagile_obj) };
В любом случае agile теперь может быть свободно передан потоку в другой квартире и использоваться там.
co_await resume_background();
NonAgileType nonagile_obj_again{ agile.get() };
winrt::hstring message{ nonagile_obj_again.Message() };
Вызов agile_ref::get возвращает прокси-сервер, который может безопасно использоваться в контексте потока, в котором вызывается get.
Важные API
- Интерфейс IAgileObject
- Интерфейс IMarshal
- шаблон структуры winrt::agile_ref
- winrt::реализует шаблон структуры
- Шаблон функции winrt::make_agile
- структура маркера winrt::non_agile
- функция winrt::Windows::Foundation::IUnknown::as
- функция winrt::Windows::Foundation::IUnknown::try_as
Связанные темы
Windows developer