Agilní objekty v C++/WinRT

Ve většině případů je instance třídy prostředí Windows Runtime přístupná z libovolného vlákna (stejně jako většina standardních objektů C++). Taková třída prostředí Windows Runtime je agilní. Pouze malý počet tříd prostředí Windows Runtime dodávaných se systémem Windows je neagilních, ale když je používáte, musíte brát v úvahu jejich model vláknění a chování při marshalingu (marshaling je předávání dat přes hranici apartmentu). Pro každý prostředí Windows Runtime objekt je vhodné, aby byl agilní, takže vaše vlastní typy C++/WinRT jsou ve výchozím nastavení agilní.

Můžete se ale rozhodnout tuto možnost nevyužít. Můžete mít například pádný důvod vyžadovat, aby objekt vašeho typu byl umístěn v daném jednovláknovém apartmentu. Obvykle to souvisí s požadavky na reentrantnost. Ale i API uživatelského rozhraní (UI) stále častěji nabízejí agilní objekty. Obecně platí, že flexibilita je nejjednodušší a nejvýkonnější možností. Pokud implementujete aktivační továrnu, musí být agilní i v případě, že odpovídající třída modulu runtime není.

Note

prostředí Windows Runtime je založená na modelu COM. V terminologii COM je agilní třída zaregistrována s hodnotou ThreadingModel = Both. Další informace o modelech vláken a apartmánech v COM naleznete v článku Vysvětlení a používání modelů vláken v COM.

Příklady kódu

Pojďme použít ukázkovou implementaci třídy modulu runtime k zobrazení toho, jak C++/WinRT podporuje agilitu.

#include <winrt/Windows.Foundation.h>

using namespace winrt;
using namespace Windows::Foundation;

struct MyType : winrt::implements<MyType, IStringable>
{
    winrt::hstring ToString(){ ... }
};

Vzhledem k tomu, že jsme se neodhlásili, je tato implementace agilní. winrt::implements je základní struktura, která implementuje IAgileObject a IMarshal. Implementace IMarshal používá CoCreateFreeThreadedMarshaler k provedení správné věci pro starší kód, který neví o IAgileObject.

Tento kód zkontroluje agilitu objektu. Volání IUnknown::as vyvolá výjimku, pokud myimpl není agilní.

winrt::com_ptr<MyType> myimpl{ winrt::make_self<MyType>() };
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.as<IAgileObject>() };

Místo zpracování výjimky můžete místo toho volat IUnknown::try_as .

winrt::com_ptr<IAgileObject> iagileobject{ myimpl.try_as<IAgileObject>() };
if (iagileobject) { /* myimpl is agile. */ }

IAgileObject nemá žádné vlastní metody, takže s ním nemůžete moc dělat. Tato další varianta je pak typickější.

if (myimpl.try_as<IAgileObject>()) { /* myimpl is agile. */ }

IAgileObject je značkovací rozhraní. Pouhý úspěch nebo selhání dotazování na IAgileObject je rozsah informací a nástrojů, které z něj získáte.

Výslovný nesouhlas s podporou agilních objektů

Explicitně můžete vyjádřit výslovný nesouhlas s podporou agilních objektů předáním struktury značky winrt::non_agile jako argumentu šablony do základní třídy.

Pokud odvozujete přímo z winrt::implements.

struct MyImplementation: implements<MyImplementation, IStringable, winrt::non_agile>
{
    ...
}

Pokud vytváříte třídu runtime.

struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, winrt::non_agile>
{
    ...
}

Nezáleží na tom, kde se ve balíčku variadických parametrů objeví značková struktura.

Bez ohledu na to, jestli se odhlásíte z flexibility, můžete implementovat IMarshal sami. Můžete například použít značku winrt::non_agile , abyste se vyhnuli výchozí implementaci flexibility a implementovali IMarshal sami – třeba kvůli podpoře sémantiky marshal-by-value.

Agilní odkazy (winrt::agile_ref)

Pokud používáte objekt, který není agilní, ale potřebujete ho předat v některém potenciálně agilním kontextu, je jednou z možností použití šablony struktury winrt::agile_ref k získání agilního odkazu na instanci negilního typu nebo rozhraní negilního objektu.

NonAgileType nonagile_obj;
winrt::agile_ref<NonAgileType> agile{ nonagile_obj };

Nebo můžete použít pomocnou funkci winrt::make_agile.

NonAgileType nonagile_obj;
auto agile{ winrt::make_agile(nonagile_obj) };

V obou případech lze nyní agile volně předat vláknu v jiném apartmá a tam použít.

co_await resume_background();
NonAgileType nonagile_obj_again{ agile.get() };
winrt::hstring message{ nonagile_obj_again.Message() };

Volání agile_ref::get vrátí proxy server, který se může bezpečně použít v kontextu vlákna, ve kterém se volá get .

Důležitá rozhraní API