Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Na grande maioria dos casos, uma instância de uma classe Windows Runtime pode ser acedida a partir de qualquer thread (tal como a maioria dos objetos C++ padrão). Uma classe de Windows Runtime assim é ágil. Apenas um pequeno número de classes do Windows Runtime fornecidas com o Windows não são ágeis, mas, ao utilizá-las, tens de ter em conta o respetivo modelo de execução por threads e o comportamento de empacotamento (o empacotamento consiste na passagem de dados através da fronteira de um apartamento). É uma boa predefinição que todos os objetos do Windows Runtime sejam ágeis, pelo que os seus próprios tipos C++/WinRT são ágeis por predefinição.
Mas pode optar por não participar. Pode ter uma razão convincente para exigir que um objeto do seu tipo resida, por exemplo, num dado apartamento de uma só linha. Isto tem normalmente a ver com requisitos de reentrância. Mas, cada vez mais, até as APIs de interface de utilizador (UI) oferecem objetos ágeis. Em geral, a agilidade é a opção mais simples e de maior desempenho. Além disso, quando implementas uma fábrica de ativação, tem de ser ágil mesmo que a tua classe de execução correspondente não seja.
Note
O Windows Runtime baseia-se no COM. Em termos de COM, uma classe ágil está registada em ThreadingModel = ambos. Para mais informações sobre os modelos de segmentação em tarefas do COM e os apartamentos, consulte Compreender e Utilizar Modelos de Segmentação em Tarefas do COM.
Exemplos de código
Vamos usar um exemplo de implementação de uma classe em tempo de execução para mostrar como o C++/WinRT suporta 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 desativámos essa opção, esta implementação é flexível. A estrutura de base winrt::implements implementa IAgileObject e IMarshal. A implementação IMarshal usa o CoCreateFreeThreadedMarshaler para fazer o que é correto para código legado que não conhece o IAgileObject.
Este código verifica a agilidade de um objeto. A chamada para IUnknown:: as lança 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 tratar de uma exceção, pode chamar IUnknown::try_as em vez disso.
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.try_as<IAgileObject>() };
if (iagileobject) { /* myimpl is agile. */ }
O IAgileObject não tem métodos próprios, por isso não se pode fazer muito com ele. Esta próxima variante, portanto, é mais típica.
if (myimpl.try_as<IAgileObject>()) { /* myimpl is agile. */ }
IAgileObject é uma interface de marcadores. O simples sucesso ou insucesso da consulta a IAgileObject é tudo o que pode obter em termos de informação e utilidade.
Optar por não participar no suporte ágil de objetos
Podes optar explicitamente por não usar suporte ágil a objetos, passando a estrutura de marcadores winrt::non_agile como argumento modelo para a tua classe base.
Se derivar diretamente de winrt::implements.
struct MyImplementation: implements<MyImplementation, IStringable, winrt::non_agile>
{
...
}
Se estiveres a criar uma classe de runtime.
struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, winrt::non_agile>
{
...
}
Não importa onde no pacote de parâmetros variádicos aparece a estrutura de marcadores.
Quer optes por não usar agilidade, podes implementar IMarshal tu próprio. Por exemplo, pode usar o marcador winrt::non_agile para evitar a implementação padrão de agilidade, e implementar o IMarshal você próprio — talvez para suportar a semântica de marshal-by-value.
Referências ágeis (winrt::agile_ref)
Se estiveres a consumir um objeto que não é ágil, mas precisas de o passar num contexto potencialmente ágil, então 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 pode usar a função de ajuda winrt::make_agile .
NonAgileType nonagile_obj;
auto agile{ winrt::make_agile(nonagile_obj) };
Em qualquer dos casos, agile pode agora ser livremente passado para uma thread num apartamento diferente e aí utilizado.
co_await resume_background();
NonAgileType nonagile_obj_again{ agile.get() };
winrt::hstring message{ nonagile_obj_again.Message() };
A chamada agile_ref::get devolve um proxy que pode ser usado em segurança dentro do contexto do thread em que o get é chamado.
APIs importantes
- Interface IAgileObject
- Interface IMarshal
- modelo de estrutura winrt::agile_ref
- modelo de estrutura winrt::implements
- Modelo de função winrt::make_agile
- winrt::non_agile estrutura de marcadores
- função winrt::Windows::Foundation::IUnknown::as
- função winrt::Windows::Foundation::IUnknown::try_as
Tópicos relacionados
Windows developer