Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans la grande majorité des cas, une instance d’une classe Windows Runtime est accessible à partir de n’importe quel thread (comme la plupart des objets C++ standard peuvent). Une telle classe Windows Runtime est agile. Seules quelques classes du runtime Windows fournies avec Windows ne sont pas agiles, mais lorsque vous les utilisez, vous devez tenir compte de leur modèle de threading et de leur comportement de marshaling (le marshaling consiste à faire passer des données à travers une frontière d’appartement). Il est recommandé par défaut pour chaque objet Windows Runtime d'être agile, de sorte que vos propres types C++/WinRT sont agiles par défaut.
Mais vous pouvez refuser. Vous pouvez avoir une raison convaincante de demander à un objet de votre type de résider, par exemple, dans un appartement à thread unique donné. Cela doit généralement être lié aux exigences de réentrance. Mais de plus en plus, même les API d’interface utilisateur offrent des objets agiles. En général, l’agilité est l’option la plus simple et la plus performante. De plus, lorsque vous implémentez une fabrique d’activation, elle doit être agile même si votre classe d’exécution correspondante ne l’est pas.
Note
Le Windows Runtime est basé sur COM. Dans la terminologie COM, une classe agile est enregistrée avec ThreadingModel = Both. Pour plus d’informations sur les modèles de thread COM et les appartements, consultez Présentation et utilisation des modèles de thread COM.
Exemples de code
Utilisons un exemple d’implémentation d’une classe runtime pour montrer comment C++/WinRT prend en charge l’agilité.
#include <winrt/Windows.Foundation.h>
using namespace winrt;
using namespace Windows::Foundation;
struct MyType : winrt::implements<MyType, IStringable>
{
winrt::hstring ToString(){ ... }
};
Comme nous n’avons pas choisi de nous retirer, cette mise en œuvre est agile. La structure de base winrt::implements implémente IAgileObject et IMarshal. L’implémentation IMarshal utilise CoCreateFreeThreadedMarshaler pour faire ce qu’il faut avec le code hérité qui ne connaît pas IAgileObject.
Ce code vérifie l’agilité d’un objet. L’appel à IUnknown::as génère une exception si myimpl n’est pas agile.
winrt::com_ptr<MyType> myimpl{ winrt::make_self<MyType>() };
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.as<IAgileObject>() };
Au lieu de gérer une exception, vous pouvez appeler IUnknown ::try_as à la place.
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.try_as<IAgileObject>() };
if (iagileobject) { /* myimpl is agile. */ }
IAgileObject n’a pas de méthodes propres, donc vous ne pouvez pas faire beaucoup avec elle. Cette variante suivante, alors, est plus typique.
if (myimpl.try_as<IAgileObject>()) { /* myimpl is agile. */ }
IAgileObject est une interface de marqueur. Le simple succès ou échec de l’interrogation de IAgileObject, c’est tout ce que cela peut vous apporter comme information et utilité.
Désactiver la prise en charge des objets agiles
Vous pouvez choisir explicitement de ne pas utiliser la prise en charge des objets agiles en passant la structure marqueur winrt::non_agile comme argument de modèle à votre classe de base.
Si vous dérivez directement de winrt::implements.
struct MyImplementation: implements<MyImplementation, IStringable, winrt::non_agile>
{
...
}
Si vous créez une classe runtime.
struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, winrt::non_agile>
{
...
}
Peu importe où se trouve la structure marqueur dans le pack de paramètres variadique.
Que vous refusiez ou non l’agilité, vous pouvez implémenter IMarshal vous-même. Par exemple, vous pouvez utiliser le marqueur winrt ::non_agile pour éviter l’implémentation d’agilité par défaut et implémenter IMarshal vous-même, peut-être pour prendre en charge la sémantique marshal-by-value.
Références agiles (winrt ::agile_ref)
Si vous consommez un objet qui n’est pas agile, mais que vous devez le transmettre dans un contexte potentiellement agile, une option consiste à utiliser le modèle de struct winrt ::agile_ref pour obtenir une référence agile à une instance d’un type non agile ou à une interface d’un objet non agile.
NonAgileType nonagile_obj;
winrt::agile_ref<NonAgileType> agile{ nonagile_obj };
Vous pouvez également utiliser la fonction d’assistance winrt ::make_agile .
NonAgileType nonagile_obj;
auto agile{ winrt::make_agile(nonagile_obj) };
Dans les deux cas, agile peut maintenant être transmis librement à un thread dans un autre appartement, et utilisé là-bas.
co_await resume_background();
NonAgileType nonagile_obj_again{ agile.get() };
winrt::hstring message{ nonagile_obj_again.Message() };
L’appel agile_ref ::get retourne un proxy qui peut être utilisé en toute sécurité dans le contexte de thread dans lequel obtenir est appelé.
API importantes
- Interface IAgileObject
- Interface IMarshal
- modèle de structure winrt::agile_ref
- modèle de structure winrt::implements
- modèle de fonction winrt ::make_agile
- winrt ::non_agile struct de marqueur
- winrt ::Windows ::Foundation ::IUnknown ::as, fonction
- winrt ::Windows ::Foundation ::IUnknown ::try_as, fonction
Rubriques connexes
Windows developer