Problemas de implementação para provedores ADSI

Para implementar interfaces ADSI, primeiro implemente a interface COM IDirectoryObject. Ao fornecer essa interface como uma camada de sobrecarga mínima, você fornece aos aplicativos cliente o controle necessário para acessar objetos de diretório diretamente do diretório, em vez de por meio do cache ADSI, que otimiza o desempenho da rede. O uso dessa interface também fornecerá sua própria implementação com a maior flexibilidade.

Em segundo lugar, implemente as interfaces ADSI fundamentais, IADs, IADsContainer, IADsCollection e as interfaces de cache de propriedades IADsPropertyValue, IADsPropertyEntry, IADsPropertyList. IADsGroup e IADsMembers também são interfaces em demanda frequente por softwares de administração de sistemas.

Em terceiro lugar, implemente as interfaces de gerenciamento de esquema se o serviço de diretório tiver um esquema subjacente: IADsClass, IADsProperty, IADsSyntax. Se não houver nenhum esquema subjacente, use essas interfaces para abstrair as classes e propriedades usadas pelo serviço de diretório. Os esquemas podem ser usados para publicar os recursos do serviço de diretório em clientes ADSI.

Coleções

Os componentes do provedor ADSI podem seguir um dos três modelos para armazenar coleções em cache durante a enumeração. A escolha de um modelo de cache determina o comportamento do ADSI quando um objeto em uma coleção é excluído do serviço de diretório subjacente externo ao ADSI.

Os modelos de cache incluem:

  • Coleções armazenadas em cache com antecedência. A coleção de instâncias de objeto é recuperada do serviço de diretório subjacente em sua totalidade quando IADsCollection::get__NewEnum é chamado para criar um novo objeto enumerador. Se o objeto de origem de uma instância de objeto do Active Directory na coleção recuperada for excluído do serviço de diretório subjacente, o cliente não reconhecerá a exclusão até que um IADs::GetInfo ou IADs::SetInfo tente acessar a coleção.
  • Coleções incrementalmente armazenadas em cache. A coleção é recuperada do serviço de diretório subjacente um objeto por vez quando IEnumVARIANT::Next é chamado. IEnumVARIANT::Reset retornará ao início da coleção no cache e IEnumVARIANT::Next retornará objetos armazenados em cache até que o final do cache seja atingido, momento em que novos objetos serão adicionados do armazenamento subjacente. Quando uma instância de objeto do Active Directory está no cache, o cliente não perceberá sua exclusão do serviço de diretório subjacente até que um IADs::GetInfo ou IADs::SetInfo tente acessar o objeto.
  • Coleções não armazenadas em cache. A coleção é recuperada do serviço de diretório subjacente um objeto por vez quando IEnumVARIANT::Next é chamado. IEnumVARIANT::Reset retornará ao início da coleção no armazenamento subjacente. As operações IEnumVARIANT::Next e IEnumVARIANT::Reset não podem recuperar objetos excluídos, porque os objetos são recuperados sob demanda do serviço de diretório subjacente. Somente o objeto atual é armazenado em cache; se o objeto atual for excluído, o cliente não tomará conhecimento de sua exclusão do serviço de diretório subjacente até que um IADs::GetInfo ou IADs::SetInfo tente acessar o objeto.

Independentemente do modelo de cache, esteja ciente de que a enumeração ADSI retorna interfaces de serviço do Active Directory para o chamador. Para evitar a sobrecarga de obter um novo ponteiro de interface, os aplicativos ADSI devem armazenar em cache os ponteiros de interface retornados para objetos que pretendem manipular. Por exemplo, um aplicativo Visual Basic que enumera um contêiner e preenche uma caixa de listagem com nomes pode armazenar em cache os ponteiros de interface associados aos nomes para uso posterior. Essa abordagem fornecerá um desempenho maior do que preencher a caixa de listagem durante a enumeração e obter um novo ponteiro de interface quando o usuário fizer uma seleção.

Sobre IDs de despacho

IDispatch é uma interface de automação definida por COM para controladores que não usam interfaces COM diretamente. O acesso a um objeto por meio de IDispatch é chamado de acesso vinculado a nome ou tardio, porque ocorre em tempo de execução ("atrasado") e usa nomes de cadeia de caracteres de propriedades e métodos para resolver referências ("nome"). Em tempo de execução, os clientes passam o nome da cadeia de caracteres da propriedade ou método que desejam chamar para o método IDispatch::GetIDsOfNames(). Se a propriedade ou o método existir no objeto, o identificador de despacho (dispID) da função correspondente será recuperado. O dispID é então usado para executar a função através de IDispatch::Invoke(). Usando IDispatch, propriedades e métodos nas interfaces expostas por um único objeto aparecem como uma lista simples. Como o acesso vinculado a nome requer duas chamadas de função, ele é menos eficiente do que usar uma interface COM diretamente. Os clientes são incentivados a usar as interfaces ADSI COM nos objetos quando o desempenho é uma consideração. Controladores de automação avançada, como o Visual Basic 4.0, podem chamar outras interfaces COM, bem como IDispatch, se as interfaces estiverem em conformidade com as restrições de automação para tipos de dados e passagem de parâmetros.

Os provedores ADSI geram dispIDs dinamicamente para cada objeto do Active Directory. Os dispIDs recuperados por meio de IDispatch::GetIDsOfNames para um determinado objeto são os valores gerados, mas não os valores que estão no IDL do objeto. Os usuários IDispatch devem chamar GetIDsOfNames para obter dispIDs válidos em tempo de execução.

Informações de tipo e bibliotecas de tipos

O ADSI SDK fornece uma biblioteca de tipos, Activeds.tlb, que documenta todas as interfaces padrão suportadas pelo ADSI. Um provedor deve fornecer uma biblioteca de tipos semelhante para todas as interfaces encontradas no Activeds.tlb, além de quaisquer dados de tipo adicionais para as interfaces implementadas no componente do provedor.

Veja a seguir um exemplo de código IDL.

[ object, uuid(IID_IADsXYZ), oleautomation, dual ]
interface IADsXYZ: IDispatch
{
// Read-only properties.
[propget]
HRESULT AReadOnlyProp ([out, retval]BSTR *pbstrAReadOnlyProp);
 
// Read/write properties.
[propget]
HRESULT AReadWriteProp ([out, retval]long *plAReadWriteProp);
[propput]
HRESULT AReadWriteProp ([in]long lAReadWriteProp);
 
// Methods.
HRESULT AMethod ([in]DATE dateInParameter,
[out, retval]BSTR *pbstrReturnValue);
};

Acesso thread-safe

O COM (Component Object Model) descreve os três modelos de threading a seguir. Aplicativos COM indicam qual modelo está em uso ao inicializar a biblioteca COM usando as funções CoInitialize e CoInitializeEx:

  • Rosca única. O modelo de thread único assume um único thread de execução em um processo, assumindo ainda mais que as estruturas de dados COM em um processo não precisam de serialização de acesso.
  • Rosqueamento de apartamentos. Um objeto COM está associado ao thread que o criou. As chamadas para um objeto em outro thread devem ser executadas pelo thread que criou esse objeto. Para fazer isso, o thread de origem invoca um proxy de cliente que organiza a chamada de método e a entrega a uma função de stub de servidor no thread de destino por meio da fila de mensagens Win32 associada ao thread de destino.
  • Rosqueamento livre. Presume-se que os objetos COM sejam thread safe. Vários threads têm permissão de acesso a qualquer objeto no processo sem serialização imposta.

ADSI não assume nenhum modelo de threading específico. Os gravadores de componentes do provedor devem assumir o modelo de threading livre e garantir a consistência de suas estruturas de dados internas, protegendo-os de atualizações inseguras de thread, ou seja, descoordenadas, por meio do uso de objetos de sincronização, como seções críticas ou semáforos.

Bloqueio de objetos

O ADSI não impõe nem define um esquema de bloqueio de objetos. Os provedores de namespaces que oferecem suporte à serialização de acesso usando bloqueio podem expor o esquema de bloqueio subjacente por meio de extensões específicas do provedor para ADSI.

Nomes de propriedade dentro de um esquema

ADSI representa propriedades como objetos de propriedade dentro do contêiner de esquema ADSI. Isso requer que os nomes de propriedade sejam exclusivos dentro de cada contêiner de esquema. O provedor deve garantir que não haja colisões de nome.

Interface Primária

Quando um provedor não consegue identificar qual interface deve ser retornada como a interface principal, IID_IADs deve ser retornada. Isso fornece acesso vinculado a nome a todas as propriedades de um objeto por meio de IDispatch e dos métodos IADs::Get, IADs::GetEx, IADs::P ut e IADs::P utEx.