Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Na grande maioria dos casos, uma instância de uma classe Windows Runtime pode ser acessada de qualquer thread (assim como a maioria dos objetos C++ padrão pode). Essa classe Windows Runtime é ágil. Apenas poucas classes do Windows Runtime que acompanham o Windows não são ágeis, mas ao consumi-las, é necessário levar em consideração o modelo de threading e o comportamento de marshaling (transmissão de dados por um limite de apartment). É uma boa configuração padrão que todo objeto do Windows Runtime seja ágil, portanto seus próprios tipos C++/WinRT também são ágeis por padrão.
No entanto, é possível recusá-los. Você pode ter um motivo convincente para exigir que um objeto do seu tipo resida, por exemplo, em um determinado single-threaded apartment. Normalmente, isso tem a ver com os requisitos de reentração. Mas cada vez mais, até mesmo as APIs de interface do usuário (UI) oferecem objetos ágeis. Em geral, a agilidade é a opção mais simples e com maior desempenho. Além disso, quando você implementa um alocador de ativação, ele deve ser ágil mesmo que a classe de runtime correspondente não seja.
Note
O Windows Runtime é baseado em COM. Em termos COM, uma classe agile é registrada com ThreadingModel = Both. Para saber mais sobre os modelos de threading COM e apartments, confira as noções básicas e uso de modelos de threading COM.
Exemplos de código
Vamos usar uma implementação de exemplo de uma classe de runtime para mostrar como o C++/WinRT dá suporte à agilidade.
#include <winrt/Windows.Foundation.h>
using namespace winrt;
using namespace Windows::Foundation;
struct MyType : winrt::implements<MyType, IStringable>
{
winrt::hstring ToString(){ ... }
};
Como não optamos por não participar, esta implementação é ágil. A estrutura base winrt::implements implementa IAgileObject e IMarshal. A implementação IMarshal usa CoCreateFreeThreadedMarshaler para fazer a coisa certa para o código herdado que não sabe sobre IAgileObject.
Esse código verifica um objeto quanto à agilidade. A chamada para IUnknown::as gera uma exceção se myimpl não for ágil.
winrt::com_ptr<MyType> myimpl{ winrt::make_self<MyType>() };
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.as<IAgileObject>() };
Em vez de lidar com uma exceção, você pode chamar IUnknown::try_as em vez disso.
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.try_as<IAgileObject>() };
if (iagileobject) { /* myimpl is agile. */ }
IAgileObject não tem métodos próprios, portanto, você não pode fazer muito com ele. Essa próxima variante, então, é mais típica.
if (myimpl.try_as<IAgileObject>()) { /* myimpl is agile. */ }
IAgileObject é uma interface de marcador. O simples sucesso ou fracasso ao consultar IAgileObject é tudo o que você obtém disso em termos de informação e utilidade.
Recusar o suporte a objetos agile
Você pode optar explicitamente por desabilitar o suporte a objetos ágeis passando a estrutura marcadora winrt::non_agile como parâmetro de modelo para sua classe base.
Se você derivar diretamente de winrt::implements.
struct MyImplementation: implements<MyImplementation, IStringable, winrt::non_agile>
{
...
}
Se você estiver criando uma classe de runtime.
struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, winrt::non_agile>
{
...
}
Não importa onde o struct de marcador apareça no pacote de parâmetros variadic.
Independentemente de você desativar ou não a agilidade, você mesmo pode implementar IMarshal. Por exemplo, você pode usar o marcador winrt::non_agile para evitar a implementação de agilidade padrão e implementar o IMarshal por conta própria, talvez para dar suporte à semântica marshal-by-value.
Referências ágeis (winrt::agile_ref)
Se você estiver consumindo um objeto que não seja ágil, mas precisar passá-lo em algum contexto potencialmente ágil, uma opção é usar o modelo de struct winrt::agile_ref para obter uma referência ágil a uma instância de um tipo não ágil ou a uma interface de um objeto não ágil.
NonAgileType nonagile_obj;
winrt::agile_ref<NonAgileType> agile{ nonagile_obj };
Ou você pode usar a função auxiliar winrt::make_agile .
NonAgileType nonagile_obj;
auto agile{ winrt::make_agile(nonagile_obj) };
Em ambos os casos, agora agile pode ser livremente passado a um thread em um apartment diferente e ser usado lá.
co_await resume_background();
NonAgileType nonagile_obj_again{ agile.get() };
winrt::hstring message{ nonagile_obj_again.Message() };
A chamada agile_ref::get retorna um proxy que pode ser usado com segurança dentro do contexto de thread no qual get é chamado.
APIs importantes
- Interface IAgileObject
- Interface IMarshal
- Modelo de struct winrt::agile_ref
- winrt::implementa modelo de estrutura
- Modelo de função winrt::make_agile
- Struct de marcador winrt::non_agile
- função winrt::Windows::Foundation::IUnknown::as
- Função winrt::Windows::Foundation::IUnknown::try_as
Tópicos relacionados:
Windows developer