Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
A ATL fornece a ICollectionOnSTLImpl interface para permitir que você implemente rapidamente interfaces de coleção baseadas na Biblioteca Padrão C++ em seus objetos. Para entender como essa classe funciona, você trabalhará com um exemplo simples (abaixo) que usa essa classe para implementar uma coleção somente leitura destinada a clientes de automação.
O código de exemplo é do exemplo ATLCollections.
Para concluir este procedimento, deverá:
Edite o arquivo IDL para a interface gerada.
Crie cinco typedefs descrevendo como os itens de coleção são armazenados e como eles serão expostos aos clientes por meio de interfaces COM.
Crie typedefs para o enumerador e implementações de coleção.
Edite o código C++ gerado pelo assistente para usar a coleção typedef.
Gerando um novo objeto simples
Crie um novo projeto, garantindo que a caixa Atributos em Configurações do aplicativo esteja desmarcada. Use a caixa de diálogo ATL Add Class e Add Simple Object Wizard para gerar um Simple Object chamado Words. Certifique-se de que uma interface dupla chamada IWords é gerada. Os objetos da classe gerada serão usados para representar uma coleção de palavras (ou seja, strings).
Editando o arquivo IDL
Agora, abra o arquivo IDL e adicione as três propriedades necessárias para transformar IWords em uma interface de coleção somente leitura, conforme mostrado abaixo:
[
object,
uuid(7B3AC376-509F-4068-87BA-03B73ADC359B),
dual, // (1)
nonextensible, // (2)
pointer_default(unique)
]
interface IWords : IDispatch
{
[id(DISPID_NEWENUM), propget] // (3)
HRESULT _NewEnum([out, retval] IUnknown** ppUnk);
[id(DISPID_VALUE), propget] // (4)
HRESULT Item([in] long Index, [out, retval] BSTR* pVal); // (5)
[id(0x00000001), propget] // (6)
HRESULT Count([out, retval] long* pVal);
};
Este é o formulário padrão para uma interface de coleção somente leitura projetada com clientes de Automação em mente. Os comentários numerados nesta definição de interface correspondem aos comentários abaixo:
As interfaces de coleção geralmente são duplas porque os clientes de automação acedem à propriedade
_NewEnumatravés deIDispatch::Invoke. No entanto, os clientes de automação podem aceder aos métodos restantes através do vtable, portanto, as interfaces duplas são preferíveis às dispinterfaces.Se uma interface dupla ou dispinterface não for estendida em tempo de execução (ou seja, você não fornecerá métodos ou propriedades extras via
IDispatch::Invoke), você deve aplicar o atributo nonextensible à sua definição. Esse atributo permite que os clientes de automação executem a verificação completa do código em tempo de compilação. Neste caso, a interface não deve ser estendida.O DISPID correto é importante se você quiser que os clientes de automação possam usar essa propriedade. (Observe que há apenas um sublinhado em DISPID_NEWENUM.)
Você pode fornecer qualquer valor como o DISPID da
Itempropriedade. No entanto,Itemutiliza normalmente DISPID_VALUE, que a torna a propriedade padrão da coleção. Isso permite que os clientes de automação se refiram à propriedade sem nomeá-la explicitamente.O tipo de dados usado para o valor de retorno da
Itempropriedade é o tipo do item armazenado na coleção no que se refere aos clientes COM. A interface retorna strings, então você deve usar o tipo de string COM padrão, BSTR. Você pode armazenar os dados em um formato diferente internamente, como verá em breve.O valor utilizado para o DISPID da propriedade
Counté completamente arbitrário. Não existe um DISPID padrão para esta propriedade.
Criando Typedefs para armazenamento e exposição
Uma vez definida a interface de coleta, você precisa decidir como os dados serão armazenados e como os dados serão expostos por meio do enumerador.
As respostas a essas perguntas podem ser fornecidas na forma de um número de typedefs, que você pode adicionar perto da parte superior do arquivo de cabeçalho para sua classe recém-criada:
// Store the data in a vector of std::strings
typedef std::vector< std::string > ContainerType;
// The collection interface exposes the data as BSTRs
typedef BSTR CollectionExposedType;
typedef IWords CollectionInterface;
// Use IEnumVARIANT as the enumerator for VB compatibility
typedef VARIANT EnumeratorExposedType;
typedef IEnumVARIANT EnumeratorInterface;
Nesse caso, você armazenará os dados como um std::vetor de std::strings. std::vetor é uma classe de contêiner C++ Standard Library que se comporta como uma matriz gerenciada. std::string é a classe de cadeia de caracteres da Biblioteca Padrão C++. Essas classes facilitam o trabalho com uma coleção de strings.
Como o suporte do Visual Basic é vital para o sucesso desta interface, o enumerador retornado pela propriedade deve ser compatível com a interface _NewEnumIEnumVARIANT. Esta é a única interface de enumerador compreendida pelo Visual Basic.
Criando Typedefs para classes de política de cópia
Os typedefs que você criou até agora fornecem todas as informações necessárias para criar mais typedefs para as classes de cópia que serão usadas pelo enumerador e pela coleção:
// Typedef the copy classes using existing typedefs
typedef VCUE::GenericCopy<EnumeratorExposedType, ContainerType::value_type> EnumeratorCopyType;
typedef VCUE::GenericCopy<CollectionExposedType, ContainerType::value_type> CollectionCopyType;
Neste exemplo, você pode usar a classe personalizada GenericCopy definida em VCUE_Copy.h e VCUE_CopyString.h do exemplo ATLCollections . Você pode usar essa classe em outro código, mas talvez seja necessário definir outras especializações para dar suporte a tipos de GenericCopy dados usados em suas próprias coleções. Para obter mais informações, consulte ATL Copy Policy Classes.
Criando Typedefs para enumeração e coleção
Agora, todos os parâmetros de modelo necessários para especializar as CComEnumOnSTL classes e ICollectionOnSTLImpl para esta situação foram fornecidos na forma de typedefs. Para simplificar o uso das especializações, crie mais dois typedefs, conforme mostrado abaixo:
typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;
Agora, CollectionType é um sinônimo de uma especialização de ICollectionOnSTLImpl que implementa a interface IWords definida anteriormente e fornece um enumerador que suporta IEnumVARIANT.
Editando o código Wizard-Generated
Agora você deve derivar CWords da implementação da interface representada pelo CollectionType typedef em vez de IWords, como mostrado abaixo:
class ATL_NO_VTABLE CWords :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CWords, &CLSID_Words>,
// 'CollectionType' replaces 'IWords' in next line
public IDispatchImpl<CollectionType, &IID_IWords, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_WORDS)
BEGIN_COM_MAP(CWords)
COM_INTERFACE_ENTRY(IWords)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// Remainder of class declaration omitted.
Adicionando código para preencher a coleção
A única coisa que resta é preencher o vetor com dados. Neste exemplo simples, você pode adicionar algumas palavras à coleção no construtor da classe:
CWords()
{
m_coll.push_back("this");
m_coll.push_back("is");
m_coll.push_back("a");
m_coll.push_back("test");
}
Agora, você pode testar o código com o cliente de sua escolha.
Ver também
Coleções e Recenseadores
Amostra ATLCollections
Classes de política de cópia ATL