Ativação sem registro de componentes baseados no .NET: um passo a passo
Steve White
Suporte premier para desenvolvedores, Microsoft UK
Leslie Muller
Desenvolvimento global de pesquisa de & TI, Credit Suisse First Boston
Julho de 2005
Resumo: O SDK da Plataforma Microsoft faz um excelente trabalho documentando os tópicos de aplicativos isolados e assemblies lado a lado. No entanto, nem todos comparam este tópico com o da ativação sem registro de componentes COM. O COM sem registro é um recurso de plataforma de grande interesse para empresas com servidores bloqueados e aplicativos isolados em infraestruturas compartilhadas. Este artigo explica um exemplo de trabalho da ativação sem registro de um componente baseado em .NET Framework por clientes nativos por meio da interoperabilidade COM. (11 páginas impressas)
Aplica-se a:
Microsoft Windows Server 2003
Microsoft Windows XP Service Pack 2
Microsoft .NET Framework versão 1.1
Microsoft Visual Studio .NET 2003
Microsoft Visual Basic 6.0
Baixe o exemplo que acompanha este artigo, MSDNRegFreeNet.msi.
Contents
Introdução
terminologia COM Registration-Free
Executando o exemplo
Criando um assembly do .NET como um servidor COM
Criando o cliente
Ativação do Registration-Free
Solução de problemas
Conclusão
Leitura Adicional
Introdução
O COM sem registro é um mecanismo disponível nas plataformas Microsoft Windows XP (SP2 para componentes baseados em .NET Framework) e Microsoft Windows Server 2003. Como o nome sugere, o mecanismo permite a implantação fácil (por exemplo, XCOPY) de componentes COM em um computador sem a necessidade de registrá-los.
Nas plataformas de destino, um dos estágios de inicialização de um processo e seus módulos dependentes é carregar todos os arquivos de manifesto associados em uma estrutura de memória chamada contexto de ativação. Na ausência de entradas correspondentes do Registro, é um contexto de ativação que fornece as informações de associação e ativação de que o runtime COM precisa. Nenhum código especial é necessário no servidor COM ou no cliente, a menos que você opte por evitar o uso de arquivos criando contextos de ativação por conta própria usando a API de contexto de ativação.
Neste passo a passo, criarei um assembly .NET simples e o consumirei, registrado e não registrado, de clientes COM nativos escritos no Visual C++ e no Visual Basic 6.0. Você pode baixar o código-fonte e os exemplos e vê-los em ação imediatamente ou pode acompanhar o passo a passo e compilá-los passo a passo.
terminologia COM Registration-Free
Qualquer pessoa familiarizada com a tecnologia .NET estará acostumada com o assembly de termos, o que significa um conjunto de um ou mais módulos implantados, nomeados e com versão como uma unidade, com um módulo contendo um manifesto que define o conjunto. No COM sem registro, os termos assembly e manifesto são emprestados para ideias semelhantes no conceito, mas não idênticas aos respectivos equivalentes do .NET.
O COM sem registro usa assembly para significar um conjunto de um ou mais módulos PE (ou seja, nativos ou gerenciados) implantados, nomeados e com versão como uma unidade. O COM sem registro usa manifesto para se referir a arquivos de texto com a extensão .manifest contendo XML, que define a identidade de um assembly (manifesto do assembly ) junto com os detalhes de associação e ativação de suas classes ou define a identidade de um aplicativo (manifesto do aplicativo ) junto com uma ou mais referências de identidade de assembly. Um arquivo de manifesto do assembly é nomeado para o assembly e um arquivo de manifesto do aplicativo é nomeado para o aplicativo.
O termo assemblies SxS (lado a lado) refere-se à configuração de diferentes versões do mesmo componente COM, por meio de arquivos de manifesto, para que possam ser carregados simultaneamente por threads diferentes sem a necessidade de serem registrados. O SxS habilita e é vagamente sinônimo de COM sem registro.
Executando o exemplo
Depois de baixar e extrair o código de exemplo, você encontrará uma pasta chamada \deployed. Aqui está a versão do Visual C++ do aplicativo cliente (client.exe), seu manifesto (client.exe.manifest) e a versão C# do servidor COM (SideBySide.dll). Vá em frente e execute client.exe. O resultado esperado é que client.exe ativará uma instância de SideBySideClass (implementada em SideBySide.dll) e exibirá o resultado de chamar seu método Version , que deve se parecer com "1.0.0-C#".
Criando um assembly do .NET como um servidor COM
Etapa 1
No Visual Studio .NET 2003 , crie um novo projeto de biblioteca de classes C# ou Visual Basic .NET e chame-o de SideBySide. Remova o AssemblyInfo.[ arquivo cs/vb] do projeto e implemente uma classe da seguinte maneira:
código C#
using System;
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: Guid("[LIBID_SideBySide]")]
namespace SideBySide
{
[Guid("[IID_ISideBySideClass]")]
public interface ISideBySideClass
{
string Version();
}
[Guid("[CLSID_SideBySideClass]")]
public class SideBySideClass : ISideBySideClass
{
public string Version()
{
return "1.0.0-C#";
}
}
}
Código .NET do Visual Basic
Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: Guid("[LIBID_SideBySide]")>
<Guid("[IID_ISideBySideClass]")> _
Public Interface ISideBySideClass
Function Version() As String
End Interface
<Guid("[CLSID_SideBySideClass]")> _
Public Class SideBySideClass
Implements ISideBySideClass
Function Version() As String Implements ISideBySideClass.Version
Version = "1.0.0-VB.NET"
End Function
End Class
Escrevi os valores guid, que serão particulares ao seu projeto, na forma de espaços reservados. Você precisará usar a ferramenta guidgen para gerar GUIDs exclusivos que serão os respectivos valores que pretendo quando usar os espaços reservados posteriormente.
Etapa 2
Para que uma biblioteca de tipos seja gerada e registrada no momento do build, defina a configuração Registrar para Interoperabilidade COM do projeto como true.
Etapa 3
Produza uma compilação de versão e copie SideBySide.dll em \deployed.
Criando o cliente
A próxima etapa é criar o cliente e, para este passo a passo, você tem a opção de criar um visual C++ ou um cliente do Visual Basic 6.0 .
Etapa 4 (opção A: Visual C++)
Crie um novo Projeto de Console do Visual C++ Win32 chamado cliente em uma pasta irmão em relação à pasta do projeto SideBySide . No Assistente de Aplicativo Win32, na guia Configurações do Aplicativo, marcar caixa de seleção Adicionar suporte para ATL.
Edite stdafx.h e adicione a seguinte linha na parte superior do arquivo, imediatamente após o #pragma once
:
#define _WIN32_DCOM
Também em stdafx.h , adicione a seguinte linha na parte inferior do arquivo:
import "[path]\SideBySide.tlb" no_namespace
Aqui, [caminho] deve ser o caminho relativo para a biblioteca de tipos que foi gerada quando você criou o assembly SideBySide . Esse caminho geralmente varia dependendo se você escolheu um C# ou um projeto .NET do Visual Basic na Etapa 1.
Substitua o conteúdo de client.cpp por este código:
#include "stdafx.h"
#include <iostream>
using namespace std;
void ErrorDescription(HRESULT hr)
{
TCHAR* szErrMsg;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&szErrMsg, 0, NULL) != 0)
{
cout << szErrMsg << endl;
LocalFree(szErrMsg);
}
else
cout << "Could not find a description for error 0x"
<< hex << hr << dec << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitializeEx(0, COINIT_MULTITHREADED);
{
ISideBySideClassPtr ptr;
HRESULT hr =
ptr.CreateInstance(__uuidof(SideBySideClass));
if (SUCCEEDED(hr))
{
cout << ptr->Version() << endl;
}
ErrorDescription(hr);
char c;
cin >> c;
}
CoUninitialize();
return 0;
}
Produza uma compilação de versão e copie \release\client.exe em \deployed.
Etapa 4 (opção B: Visual Basic 6.0)
Crie um novo projeto do Visual Basic 6.0 Standard EXE . No Project Explorer selecione o nó Project1 e, na Janela Propriedades, altere seu nome para cliente. Escolher Arquivo | Salve o Project As e salve o arquivo de formulário e o arquivo de projeto em uma pasta irmão em relação à pasta do projeto SideBySide . Escolher Projeto | Referências, marcar a caixa de seleção ao lado de SideBySide e escolha OK.
Clique duas vezes no formulário main no designer de formulários e cole o seguinte código em Sub Form_Load():
Dim obj As New SideBySideClass
Dim isxs As SideBySide.ISideBySideClass
Set isxs = obj
MsgBox isxs.Version()
Escolher Arquivo | Faça client.exe... e navegue até a pasta \implantado e escolha OK.
Etapa 5
No momento, a pasta \deployed deve conter, além de alguns arquivos intermediários, apenas client.exe e SideBySide.dll; e o último terá sido registrado por seu processo de build. Para marcar que o servidor e o cliente trabalhem juntos nessas circunstâncias normais, execute \deployed\client.exe e observe a saída esperada "1.0.0-C#" ou "1.0.0-VB.NET".
Etapa 6
Este passo a passo é sobre COM sem registro , portanto, agora precisamos cancelar o registro do assembly SideBySide . Em um Prompt de Comando do Visual Studio 2003, navegue até a pasta \deployed e execute o comando: regasm /u SideBySide.dll
.
Etapa 7
Para ver o efeito que a etapa anterior teve, execute \deployed\client.exe novamente e você verá a mensagem "Classe não registrada" ou "Erro de tempo de execução '429': o componente ActiveX não pode criar objeto". Nesta fase, frustramos o runtime COM de encontrar as informações necessárias no Registro, mas ainda não disponibilizamos as informações por meios alternativos. Corrigiremos isso nas etapas a seguir.
Ativação do Registration-Free
Etapa 8
Na pasta \deployed , crie um arquivo de manifesto do aplicativo (um arquivo de texto) para o aplicativo client.exe e chame-o declient.exe.manifest. Cole o seguinte no arquivo:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type = "win32"
name = "client"
version = "1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="SideBySide"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>
Etapa 9
Na pasta do projeto SideBySide , crie um arquivo de manifesto de assembly privado (um arquivo de texto) e chame-o de SideBySide.manifest. Cole o seguinte no arquivo:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type="win32"
name=" SideBySide"
version="1.0.0.0" />
<clrClass
clsid="{[CLSID_SideBySideClass]}"
progid="SideBySide.SideBySide"
threadingModel="Both"
name="SideBySide.SideBySideClass" >
</clrClass>
</assembly>
A próxima tarefa é inserir o arquivo de manifesto do assembly acima no assembly SideBySide como um recurso Win32. No momento da gravação, isso é obrigatório para o Windows XP, mas não para o Windows Server 2003. No Windows Server 2003, você pode se safar simplesmente implantando o arquivo de manifesto do assembly junto com o assembly. No entanto, peço que você não dependa desse comportamento, pois ele pode muito bem mudar em um Próximo Service Pack do Windows Server 2003. Para garantir que você continue dando suporte a ambas as plataformas no futuro, siga as próximas etapas e insira o arquivo de manifesto do assembly no assembly do .NET como um recurso Win32. Isso só é necessário para ativação sem registro de . Componentes baseados em NET e não é um requisito para ativação sem registro de componentes COM nativos .
Etapa 10
Na pasta do projeto SideBySide , crie um arquivo de script de definição de recurso (um arquivo de texto) e chame-o de SideBySide.rc. Cole o seguinte no arquivo:
#include <windows.h>
#define MANIFEST_RESOURCE_ID 1
MANIFEST_RESOURCE_ID RT_MANIFEST SideBySide.manifest
O arquivo windows.h e suas dependências estão disponíveis quando você instala o SDK da Plataforma (seção SDK principal) ou o Visual C++. A parte do windows.h necessária aqui é a definição:
#define RT_MANIFEST 24
Consequentemente, o conteúdo de SideBySide.rc resolve para:
1 24 SideBySide.manifest
No entanto, é mais claro e geral usar as definições de macro conforme indicado.
Etapa 11
Na pasta do projeto SideBySide , crie um arquivo de comando de build (um arquivo de texto) e chame-o de build.cmd. Cole o seguinte no arquivo:
Para compilar C#:
rc SideBySide.rc
csc /t:library /out:..\deployed\SideBySide.dll
/win32res:SideBySide.res Class1.cs
Para criar o .NET do Visual Basic:
rc SideBySide.rc
vbc /t:library /out:..\deployed\SideBySide.dll
/win32resource:SideBySide.res /rootnamespace:SideBySide Class1.vb
O que esses comandos fazem é primeiro invocar a ferramenta Microsoft Windows Resource Compiler do SDK da Plataforma (rc.exe) para compilar o script de definição de recurso da etapa 10 em um arquivo de recurso compilado chamado SideBySide.res. Em seguida, ele invoca o compilador C# ou Visual Basic .NET para criar seu arquivo de código-fonte em um assembly e inserir o arquivo de recurso compilado nele como um recurso Win32. O assembly compilado é gravado na pasta \deployed , mas não está registrado para interoperabilidade COM.
Etapa 12
Em um Prompt de Comando do Visual Studio 2003, navegue até a pasta do projeto SideBySide e execute o comando: build
.
Etapa 13
Para verificar se, cortesia dos arquivos de manifesto, seu cliente poderá ativar mais uma vez a classe SideBySideClass por meio da interoperabilidade COM, executar \deployed\client.exe e observar a saída esperada "1.0.0-C#" ou "1.0.0-VB.NET".
Solução de problemas
Como vimos, a ativação sem registro de componentes baseados em .NET Framework não requer nenhum código especial no servidor ou no cliente. Tudo o que é necessário é um par correspondente de arquivos de manifesto, um dos quais é inserido no assembly do .NET como um recurso Win32 do tipo RT_MANIFEST.
Sugiro que você aborde seu próprio desenvolvimento sem registro da maneira como este passo a passo faz. Especificamente: primeiro chegue a um estado conhecido vendo seu cliente trabalhando com um servidor registrado; em seguida, cancele o registro do servidor e confirme se sua mensagem de erro é o que você esperava; e, por fim, remediar a situação criando e implantando arquivos de manifesto. Dessa forma, seus esforços de solução de problemas em torno da ativação sem registro serão limitados à estrutura dos arquivos de manifesto e à inserção correta do manifesto do assembly.
Ao solucionar problemas com sem registro, o Visualizador de Eventos no Windows Server 2003 é seu amigo. Quando o Windows XP ou o Windows Server 2003 detecta um erro de configuração, ele normalmente mostrará uma caixa de mensagem de erro intitulada para o aplicativo que você iniciou e contendo a mensagem "Este aplicativo não foi iniciado porque a configuração do aplicativo está incorreta. A reinstalação do aplicativo pode corrigir esse problema." Aconselho que sempre que vir essa mensagem, reproduza o problema no Windows Server 2003, consulte o Log de Eventos do Sistema e procure eventos da fonte SideBySide . O motivo pelo qual não sugiro que você examine o Log de Eventos do XP nesses casos é que ele invariavelmente conterá uma mensagem como "Falha ao gerar contexto de ativação para [caminho]\[nome do arquivo de aplicativo]. Manifesto. Mensagem de erro de referência: a operação foi concluída com êxito", o que não ajuda a identificar o problema.
Antes de passar para a estrutura de arquivos de manifesto, vamos falar sobre os recursos do Win32. Como mencionei acima, windows.h define o símbolo RT_MANIFEST como o valor 24, que é o valor que o sistema operacional reconhecerá como um arquivo de manifesto inserido. Se você esquecer de incluir windows.h em seu script de definição de recurso (arquivo .rc), o build ainda terá êxito e o arquivo de manifesto ainda será inserido como um recurso, mas não do tipo correto. Para verificar se você inseriu corretamente seu manifesto, abra o SideBySide.dll no Visual Studio (Arquivo | Abrir | Arquivo...). Você verá uma exibição de árvore mostrando os recursos dentro do módulo. No nó raiz deve ser um nó chamado RT_MANIFEST abaixo do qual deve ser outro nó mostrando o número de recursos do recurso de manifesto (1 no passo a passo). Clique duas vezes neste último nó para ver os dados em uma exibição binária e dê a ele uma sanidade rápida marcar que ele se assemelha ao arquivo de manifesto XML. Embora seja binário, os caracteres do intervalo ASCII serão óbvios. Se os dados binários estiverem ausentes ou parecerem incorretos, verifique se o script de definição de recurso (arquivo .rc) faz referência ao arquivo de manifesto. Se o texto do nó RT_MANIFEST estiver entre aspas, você provavelmente esqueceu de incluir windows.h no script de definição de recurso (arquivo.rc).
Cada um dos erros mencionados será relatado no Log de Eventos do Sistema do Windows Server 2003 com a mensagem: "Assembly dependente [nome] não foi encontrado e Último Erro foi O assembly referenciado não está instalado em seu sistema".
Os esquemas dos vários arquivos de manifesto estão documentados no SDK da Plataforma sob o título Referência de Arquivos de Manifesto e a ferramenta de validação de esquema Manifestchk.vbs está disponível, portanto, aqui, chamarei apenas alguns pontos relevantes para o passo a passo. Primeiro, vamos examinar o arquivo de manifesto do assembly. Por exemplo, volte para a Etapa 9.
Você lembrará que, no sentido COM sem registro , um assembly é uma ideia abstrata à qual você associa um ou mais arquivos físicos por meio do conteúdo do arquivo de manifesto do assembly .
O elemento assemblyIdentity define a identidade do assembly. Para. Componentes baseados em NET seu atributo de nome deve corresponder ao nome do assembly .NET e, portanto, seu nome de arquivo, caso contrário, você verá a seguinte mensagem no Log de Eventos do Sistema do Windows Server 2003: "Assembly dependente [valor do atributo de nome ] não pôde ser encontrado e Último Erro foi O assembly referenciado não está instalado em seu sistema.". No entanto, o atributo de versão não precisa corresponder ao AssemblyVersion do assembly do .NET nem ao AssemblyFileVersion, embora seja uma boa ideia aplicar algum tipo de consistência.
O elemento clrClass tem apenas dois atributos obrigatórios: name e clsid. O atributo namedeve corresponder ao namespace combinado e ao nome de classe da classe CLR que está sendo ativada. Se isso não acontecer, CoCreateInstance retornará um HRESULT com o valor COR_E_TYPELOAD (0x80131522). Isso resulta de um System.TypeLoadException sendo gerado quando o carregador de tipo não encontra o tipo CLR solicitado em seu assembly .NET. Uma coisa a watch se o assembly do .NET for escrito no .NET do Visual Basic é que você está fornecendo a opção /rootnamespace na linha de comando para o compilador do .NET do Visual Basic (vbc.exe). O atributo clsiddeve corresponder ao CLSID atribuído à classe CLR que está sendo ativada por meio de seu GuidAttribute. Se isso não acontecer, CoCreateInstance retornará um HRESULT com o valor REGDB_E_CLASSNOTREG (0x80040154), o texto da mensagem para o qual é "Classe não registrada".
Agora, vamos voltar nossa atenção para o arquivo de manifesto do aplicativo. Por exemplo, volte para a Etapa 8. O manifesto do aplicativo deve ser nomeado no formato [nome do arquivo do aplicativo].manifest. Portanto, no passo a passo foi nomeado client.exe.manifest para deixar claro que ele deve ser lido sempre que client.exe é carregado em um processo. Se isso não for feito corretamente, CoCreateInstance retornará um HRESULT com o valor REGDB_E_CLASSNOTREG (0x80040154), o texto da mensagem para o qual é "Classe não registrada".
O elemento mais importante no manifesto do aplicativo é o elemento dependentAssembly/assemblyIdentity . Esse elemento é uma referência ao equivalente no manifesto do assembly e os dois precisam corresponder exatamente. Uma boa maneira de garantir que eles façam isso é copiar o elemento do manifesto do assembly e colá-lo aqui. Se houver alguma diferença, você verá a seguinte mensagem no Log de Eventos do Sistema do Windows Server 2003: "A identidade do componente encontrada no manifesto não corresponde à identidade do componente solicitado".
Conclusão
O COM sem registro é uma tecnologia que libera componentes COM de uma dependência no Registro do Windows e, consequentemente, libera os aplicativos que os usam da necessidade de servidores dedicados. Ele permite que aplicativos com dependências em diferentes versões do mesmo componente COM compartilhem uma infraestrutura e carreguem essas várias versões de componente COM lado a lado em um eco do mecanismo de implantação e controle de versão do .NET.
Este artigo explica uma demonstração da ativação sem registro de componentes baseados em .NET Framework por aplicativos cliente nativos escritos no Visual C++ e no Visual Basic 6.0. Ele explicou alguns de como o mecanismo funciona e sublinhou alguns possíveis erros de configuração e como solucioná-los.
Leitura Adicional
- Ativação sem registro de componentes COM: um passo a passo
- Aplicativos isolados e assemblies lado a lado
- Esquema de arquivo de manifesto
- Usando a API de Contexto de Ativação
Sobre o autor
Steve White é um Consultor de Desenvolvimento de Aplicativos que trabalha na equipe de Suporte Premier para Desenvolvedores da Microsoft UK. Ele dá suporte ao desenvolvimento de clientes com Visual C#, Windows Forms e ASP.NET. Seu blog tem mais informações sobre seus interesses em música, visualizações e programação.
Leslie Muller é tecnóloga da equipe de Desenvolvimento de Pesquisa & do Credit Suisse First Boston. Leslie tem 12 anos de experiência como desenvolvedor e arquiteta técnica, trabalhando em ambientes como serviços financeiros, startups de tecnologia, automação industrial e defesa. Quando ele não está programando ou fazendo pesquisas ele gosta de esquiar, hóquei no gelo e quando possível fazer coisas ligeiramente loucas com veículos motorizados em ambientes extremos como a Islândia ou as Montanhas Rochosas.