Criando COM componentes de interoperação
Se você planeja escrever aplicativos baseados em COM no futuro, você pode criar o seu código para interoperar com código gerenciado com eficiência. Com um planejamento avançado, você também pode simplificar a migração de código não gerenciado para código gerenciado.
As recomendações a seguir resumem as práticas recomendadas para escrever os tipos COM que interagem com código gerenciado.
Forneça as bibliotecas de tipos
Na maioria das situações, o common language runtime requer metadados para todos os tipos, incluindo tipos COM. O Type Library Importer (Tlbimp. exe), que está incluído na Windows Software Development Kit (SDK), pode converter as bibliotecas de tipos COM para.NET Framework metadados. Depois que a biblioteca de tipos é convertida em metadados, clientes gerenciados podem chamar o tipo COM. Para facilidade de uso, sempre fornece informações de tipo em uma biblioteca de tipos.
Você pode compactar uma biblioteca de tipos, como um arquivo separado ou incorporá-lo como um recurso dentro de um arquivo. dll,. exe ou. ocx. Além disso, você pode gerar os metadados diretamente, que permite que você assine os metadados com um par de chaves do publisher. Assinado com uma chave de metadados tem uma fonte definitiva e podem ajudar a evitar a ligação quando o chamador tem a chave errada, melhorando a segurança.
Registre as bibliotecas de tipo
Para empacotar chamadas corretamente, o tempo de execução, talvez seja necessário localizar a biblioteca de tipos que descreve um tipo específico. Uma biblioteca de tipos deve ser registrada antes do tempo de execução pode vê-lo, exceto no caso de ligação tardia.
Você pode registrar a biblioteca de tipos chamando a API do Win32 Microsoft LoadTypeLibEx funcionar com o regkind sinalizador definido como REGKIND_REGISTER. Regsvr32. exe registra automaticamente uma biblioteca de tipos incorporada em um arquivo. dll.
Usar matrizes seguras em vez de matrizes de comprimento variável
Matrizes seguras de COM são autodescritivos. Examinando a matriz segura, o empacotador de tempo de execução pode determinar a posição, tamanho, limites e geralmente o tipo do conteúdo da matriz em tempo de execução. Comprimento variável (ou estilo C) arrays não possuem a mesma qualidade autodescritivo. Por exemplo, a seguinte assinatura de método não-gerenciado não fornece nenhuma informação sobre o parâmetro de matriz diferente do tipo de elemento.
HRESULT DoSomething(int cb, [in] byte buf[]);
Na verdade, a matriz é idêntico a qualquer outro parâmetro passado por referência. Como resultado, Tlbimp. exe não converte o parâmetro de matriz do DoSomething método. Em vez disso, a matriz aparece como uma referência a um bytes o tipo, como mostra o código a seguir.
Public Sub DoSomething(cb As Integer, ByRef buf As Byte)
public void DoSomething(int cb, ref Byte buf);
Para melhorar a interoperação, você pode digitar o argumento como um SAFEARRAY na assinatura do método não gerenciado. Por exemplo:
HRESULT DoSomething(SAFEARRAY(byte)buf);
Tlbimp. exe converte o SAFEARRAY nas seguintes gerenciado tipo de matriz:
Public Sub DoSomething(buf As Byte())
public void DoSomething(Byte[] buf);
Usar tipos de dados compatível com a automação
O runtime automaticamente o serviço de empacotamento oferece suporte a todos os tipos de dados compatível com automação. Tipos que não são compatíveis com podem ou não suporte.
Fornecer a versão e a localidade em bibliotecas de tipo
Quando você importa uma biblioteca de tipos, as informações de versão e a localidade de biblioteca do tipo também são propagadas para o assembly. Clientes gerenciados, em seguida, podem ligar para uma versão específica ou a localidade do assembly ou a versão mais recente do assembly. Fornecendo informações de versão na biblioteca de tipos permite que os clientes escolham precisamente qual versão do assembly para usar.
Use tipos Blittable
Tipos de dados são blittable ou não-blittable. Tipos blittable têm uma representação comum entre o limite de interoperabilidade. Inteiro e tipos de ponto flutuante são blittable. Matrizes e estruturas de tipos blittable são também blittable. Seqüências de caracteres, datas e objetos são exemplos de tipos de não-blittable convertidos durante o processo de empacotamento.
Tipos blittable e o blittable não são suportados pelo interop marshaling de serviço; No entanto, os tipos requerem conversão durante o empacotamento não executar, bem como tipos blittable. Quando você usa os tipos de não-blittable, esteja ciente de que há é adicionado sobrecarga associado com o empacotamento-los.
Strings são particularmente problemáticos. Gerenciado de seqüências de caracteres é armazenado como caracteres Unicode e, conseqüentemente, pode ser empacotado com maior eficiência para código não gerenciado que espera os argumentos de caractere Unicode. É melhor evitar seqüências de caracteres compostas de caracteres ANSI, quando possível.
Implementar IProvideClassInfo
Quando o empacotamento de interfaces de não gerenciados para código gerenciado, o runtime cria um wrapper de um tipo específico. A assinatura do método normalmente indica o tipo da interface, mas o tipo de objeto implementando a interface pode ser desconhecido. Se o tipo de objeto for desconhecido, o runtime empacota a interface com um wrapper de objeto COM genérico, que é menos funcional que o tipo específico wrappers.
Por exemplo, considere a seguinte assinatura de método COM:
interface INeedSomethng {
HRESULT DoSomething(IBiz *pibiz);
}
Quando importado, o método é convertido da seguinte maneira:
Interface INeedSomething
Sub DoSomething(pibiz As IBiz)
End Interface
interface INeedSomething {
void DoSomething(IBiz pibiz);
}
Se você passar um objeto gerenciado que implementa o INeedSomething interface para o IBiz interface, o empacotador de interoperabilidade tenta quebrar a interface com um invólucro de objeto de um tipo específico sobre o lançamento inicial do IBiz para código gerenciado. Para identificar o tipo correto de wrapper, o empacotador deve saber o tipo de objeto implementando a interface. Uma maneira do empacotador tenta determinar o tipo de objeto é a consulta para o IProvideClassInfo interface. Se o objeto implementa IProvideClassInfo, o empacotador determina o tipo do objeto e a interface de um wrapper de tipo de quebra.
Usar chamadas modulares
O empacotamento de dados entre código gerenciado e tem um custo. Você pode atenuar o custo, tornando menos transições entre o limite. Interfaces que minimizam o número de transições geralmente têm um melhor desempenho do que interfaces cruzar o limite com freqüência, realizar pequenas tarefas com cada interseção.
Use falha HRESULTs conservadoramente
Quando um cliente gerenciado chama um objeto COM, o runtime mapeia HRESULTs de falha do objeto COM exceções, que o empacotador lança no retorno de chamada. O modelo de exceção gerenciada foi otimizado para casos que não são excepcionais; Não há quase nenhuma sobrecarga associada ao capturar exceções quando nenhuma exceção ocorre. Inversamente, quando ocorre uma exceção, captura a exceção pode ser caro.
Use exceções com moderação e evite retornando HRESULTs de falha para fins informativos. Reserve falha HRESULTs para situações excepcionais. Percebe-se de que o uso excessivo de falha HRESULTS pode afetar o desempenho.
Libere recursos externos explicitamente
Alguns objetos usam recursos externos durante a vida útil; uma conexão de banco de dados, por exemplo, pode atualizar um conjunto de registros. Normalmente, um objeto mantiver um recurso externo para a duração da validade, enquanto uma versão explícita pode retornar imediatamente o recurso. Por exemplo, você pode usar o Fechar método em um objeto de arquivo em vez de fechar o arquivo no destruidor de classe ou com IUnknown.Release. Fornecendo um equivalente para o Fechar método no seu código, você pode liberar o recurso de arquivo externo, mesmo que o objeto de arquivo continua a existir.
Evitar a redefinição de tipos não gerenciados
A maneira correta de implementar uma interface existente de COM em código gerenciado é começar importando a definição da interface com Tlbimp. exe ou uma API equivalente. Os metadados resultante fornecem uma definição compatível da interface COM (mesmo IID mesmo DispIds e assim por diante).
Evite redefinindo a interfaces COM manualmente no código gerenciado. Esta tarefa consome tempo e raramente produz uma interface gerenciada compatível com a interface COM existente. Em vez disso, use Tlbimp. exe para manter a compatibilidade de definição.
Evite usar HRESULTs de sucesso
Capturando exceções é a forma mais natural para aplicativos gerenciados lidar com situações de erro. Para tornar usando tipos de COM transparentes, o tempo de execução lança uma exceção automaticamente sempre que um método COM retorna uma falha HRESULT.
Se o seu objeto COM retorna um HRESULT de sucesso, o runtime retorna o valor que está sendo o retval parâmetro. Por padrão, o HRESULT é descartado, tornando muito difícil para o cliente gerenciado examinar o valor de um sucesso HRESULT. Embora você pode preservar um HRESULT com o PreserveSigAttribute atributo, o processo requer esforço. Você deve adicionar o atributo manualmente para um assembly gerado com Tlbimp. exe ou uma API equivalente.
É melhor evitar o sucesso HRESULTs sempre que possível. Você pode retornar informações sobre o status de uma chamada através de um parâmetro de saída em vez disso.
Evite utilizar funções do módulo
Bibliotecas de tipos podem conter funções definidas em um módulo. Normalmente, você deve usar essas funções para fornecer informações de tipo para os pontos de entrada DLL. Tlbimp. exe não importar essas funções.
Evitar o uso de membros de Object em Interfaces padrão
Clientes gerenciados e coclasses de COM de interagem com a Ajuda de wrappers fornecidos pelo runtime. Quando você importa um tipo COM, o processo de conversão adiciona a classe de wrapper que deriva de todos os métodos da interface padrão do coclass a System.Object classe. Tenha cuidado para nomear os membros de interface padrão para que não ocorram conflitos de nomes com os membros do Object. Se ocorrer um conflito, o método importado substitui o método da classe base.
Essa ação pode ser favorável se o método de interface padrão e o método de Object fornecem a mesma funcionalidade. Ele pode ser problemático, no entanto, se os métodos da interface padrão são usados de maneira não intencional. Para evitar conflitos de nomes, evitar o uso de interfaces padrão de nomes a seguir: O objeto, Equals, Finalize GetHashCode, GetType, MemberwiseClone e ToString.
Consulte também
Referência
Tlbimp. exe (importador da biblioteca)