Agila objekt i C++/WinRT

I de allra flesta fall kan en instans av en Windows Runtime-klass nås från valfri tråd (precis som de flesta C++-standardobjekt kan). En sådan Windows Runtime klass är flexibel. Endast ett litet antal Windows Runtime-klasser som levereras med Windows är inte trådagila, men när du använder dem måste du ta hänsyn till deras trådmodell och marshalingbeteende (marshaling innebär att data skickas över en apartmentgräns). Det är en bra standard för varje Windows Runtime objekt att vara agilt, så dina egna C++/WinRT-typer är agila som standard.

Men du kan avregistrera dig. Du kan ha en övertygande anledning att kräva att ett objekt av din typ ska finnas, till exempel i en viss entrådad lägenhet. Detta har vanligtvis att göra med krav på återinträdesbarhet. Men i allt högre grad erbjuder även API:er för användargränssnitt (UI) agila objekt. I allmänhet är flexibilitet det enklaste och mest högpresterande alternativet. När du också implementerar en aktiveringsfabrik måste den vara agil även om din motsvarande runtime-klass inte är det.

Note

Windows Runtime baseras på COM. I COM-termer registreras en agil klass med ThreadingModel = Båda. Mer information om COM-trådmodeller och lägenheter finns i Förstå och använda COM-trådmodeller.

Kodexempel

Nu ska vi använda en exempelimplementering av en körningsklass för att visa hur C++/WinRT stöder flexibilitet.

#include <winrt/Windows.Foundation.h>

using namespace winrt;
using namespace Windows::Foundation;

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

Eftersom vi inte har valt bort den här implementeringen är den agil. Winrt::implements base struct implementerar IAgileObject och IMarshal. IMarshal-implementeringen använder CoCreateFreeThreadedMarshaler för att göra det rätta för äldre kod som inte känner till IAgileObject.

Den här koden kontrollerar ett objekt efter flexibilitet. Anropet av IUnknown::as genererar ett undantag om myimpl inte är agilt.

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

I stället för att hantera ett undantag kan du anropa IUnknown::try_as i stället.

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

IAgileObject har inga egna metoder, så du kan inte göra mycket med det. Nästa variant är alltså mer typisk.

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

IAgileObject är ett markörgränssnitt. Huruvida en fråga efter IAgileObject lyckas eller misslyckas är all den information och nytta du får av den.

Avregistrera dig från agilt objektstöd

Du kan välja att uttryckligen välja bort agilt objektstöd genom att skicka winrt::non_agile markör struct som ett mallargument till basklassen.

Om du härleder direkt från winrt::implements.

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

Om du skapar en runtimeklass.

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

Det spelar ingen roll var i det variadiska parameterpaketet som markörstrukturen förekommer.

Oavsett om du väljer bort agilitet eller inte, kan du implementera IMarshal själv. Du kan till exempel använda markören winrt::non_agile för att undvika standardimplementeringen av flexibilitet och implementera IMarshal själv – kanske för att stödja marskalk-för-värde-semantik.

Agila referenser (winrt::agile_ref)

Om du använder ett objekt som inte är agilt, men du behöver skicka runt det i någon potentiellt agil kontext, är ett alternativ att använda winrt::agile_ref struct-mall för att få en flexibel referens till en instans av en icke-agil typ eller till ett gränssnitt för ett icke-agilt objekt.

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

Du kan också använda hjälpfunktionen winrt::make_agile .

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

I båda fallen agile kan nu fritt skickas till en tråd i en annan lägenhet och användas där.

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

Det agile_ref::get-anropet returnerar en proxy som säkert kan användas i trådkontexten där get anropas.

Viktiga API:er