Partager via


Activation sans inscription de composants .NET : une procédure pas à pas

 

Steve White
Premier Support pour les développeurs, Microsoft Royaume-Uni

Leslie Muller
Global IT Research & Development, Credit Suisse First Boston

Juillet 2005

Résumé: Le Kit de développement logiciel (SDK) de plateforme Microsoft fait un excellent travail en documentant les sujets des applications isolées et des assemblys côte à côte. Toutefois, tout le monde n’associe pas cette rubrique à celle de l’activation sans inscription des composants COM. COM sans inscription est une fonctionnalité de plateforme très intéressante pour les entreprises avec des serveurs verrouillés et des applications isolés sur des infrastructures partagées. Cet article décrit un exemple pratique d’activation sans inscription d’un composant .NET Framework par des clients natifs via COM Interop. (11 pages imprimées)

S’applique à :
   Microsoft Windows Server 2003
   Microsoft Windows XP Service Pack 2
   Microsoft .NET Framework version 1.1
   Microsoft Visual Studio .NET 2003
   Microsoft Visual Basic 6.0

Téléchargez l’exemple qui accompagne cet article ,MSDNRegFreeNet.msi.

Contents

Introduction
terminologie com Registration-Free
Exécution de l'exemple
Génération d’un assembly .NET en tant que serveur COM
Génération du client
Activation Registration-Free
Dépannage
Conclusion
En savoir plus

Introduction

COM sans inscription est un mécanisme disponible sur les plateformes Microsoft Windows XP (SP2 pour les composants basés sur .NET Framework) et Microsoft Windows Server 2003. Comme son nom l’indique, le mécanisme permet un déploiement facile (par exemple XCOPY) de composants COM sur une machine sans avoir à les inscrire.

Sur les plateformes cibles, l’une des étapes de l’initialisation d’un processus et de ses modules dépendants consiste à charger tous les fichiers manifeste associés dans une structure de mémoire appelée contexte d’activation. En l’absence d’entrées de Registre correspondantes, il s’agit d’un contexte d’activation qui fournit les informations de liaison et d’activation dont le runtime COM a besoin. Aucun code spécial n’est requis dans le serveur COM ou dans le client, sauf si vous choisissez d’annuler l’utilisation de fichiers en créant vous-même des contextes d’activation à l’aide de l’API de contexte d’activation.

Dans cette procédure pas à pas, je vais créer un assembly .NET simple et l’utiliser, à la fois inscrit et non inscrit, à partir de clients COM natifs écrits en Visual C++ et Visual Basic 6.0. Vous pouvez télécharger le code source et les exemples et les voir en action immédiatement, ou vous pouvez suivre la procédure pas à pas et les créer vous-même pas à pas.

terminologie com Registration-Free

Toute personne familiarisée avec la technologie .NET sera habituée au terme assembly , c’est-à-dire un ensemble d’un ou plusieurs modules déployés, nommés et versionnés en tant qu’unité, avec un module contenant un manifeste qui définit l’ensemble. Dans COM sans inscription, les termes assembly et manifest sont empruntés pour les idées qui sont similaires dans le concept mais qui ne sont pas identiques à leurs équivalents .NET.

COM sans inscription utilise l’assembly pour désigner un ensemble d’un ou plusieurs modules PE (c’est-à-dire natifs ou managés) déployés, nommés et versionnés en tant qu’unité. COM sans inscription utilise le manifeste pour faire référence aux fichiers texte avec l’extension .manifest contenant du code XML, qui définit l’identité d’un assembly (manifeste d’assembly) avec les détails de liaison et d’activation de ses classes, ou définit l’identité d’une application (manifeste d’application) avec une ou plusieurs références d’identité d’assembly. Un fichier manifeste d’assembly est nommé pour l’assembly et un fichier manifeste d’application est nommé pour l’application.

Le terme assemblys côte à côte (SxS) fait référence à la configuration de différentes versions du même composant COM, via des fichiers manifestes, afin qu’elles puissent être chargées simultanément par différents threads sans avoir à être inscrites. SxS active et est peu synonyme de COM sans inscription.

Exécution de l'exemple

Une fois que vous avez téléchargé et extrait l’exemple de code, vous trouverez un dossier appelé \deployed. Voici la version Visual C++ de l’application cliente (client.exe), son manifeste (client.exe.manifest) et la version C# du serveur COM (SideBySide.dll). Exécutez client.exe. Le résultat attendu est que client.exe active un instance de SideBySideClass (implémenté dans SideBySide.dll) et affiche le résultat de l’appel de sa méthode Version qui doit ressembler à « 1.0.0-C# ».

Génération d’un assembly .NET en tant que serveur COM

Étape 1

Dans Visual Studio .NET 2003 , créez un projet de bibliothèque de classes C# ou Visual Basic .NET et appelez-le SideBySide. Supprimer AssemblyInfo.[ cs/vb] fichier à partir du projet et implémentez une classe comme suit :

code 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#";
      }
   }
}

Code Visual Basic .NET

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

J’ai écrit les valeurs GUID, qui seront propres à votre projet, sous la forme d’espaces réservés. Vous devez utiliser l’outil guidgen pour générer des GUID uniques qui correspondront aux valeurs respectives que j’ai l’intention d’utiliser les espaces réservés par la suite.

Étape 2

Pour qu’une bibliothèque de types soit générée et inscrite au moment de la génération, définissez le paramètre Register for COM Interop du projet sur true.

Étape 3 :

Produisez une build de mise en production et copiezSideBySide.dll dans \deployed.

Génération du client

L’étape suivante consiste à générer le client et, pour cette procédure pas à pas, vous avez la possibilité de générer un client Visual C++ ou Visual Basic 6.0 .

Étape 4 (Option A : Visual C++)

Créez un projet de console Win32 Visual C++ appelé client dans un dossier frère relatif au dossier du projet SideBySide . Dans l’Assistant Application Win32, sous l’onglet Paramètres de l’application, case activée la case Ajouter la prise en charge d’ATL.

Modifiez stdafx.h et ajoutez la ligne suivante en haut du fichier, immédiatement après :#pragma once

#define _WIN32_DCOM

Dans stdafx.h , ajoutez également la ligne suivante en bas du fichier :

import "[path]\SideBySide.tlb" no_namespace

Ici, [path] doit être le chemin d’accès relatif à la bibliothèque de types qui a été générée lorsque vous avez généré votre assembly SideBySide . Ce chemin varie généralement selon que vous avez choisi un projet C# ou Visual Basic .NET à l’étape 1.

Remplacez le contenu de client.cpp par ce code :

#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;
}

Produisez une build de mise en production et copiez\release\client.exe dans \deployed.

Étape 4 (Option B : Visual Basic 6.0)

Créez un projet EXE Visual Basic 6.0 Standard . Dans project Explorer sélectionnez le nœud Project1 et, dans la fenêtre Propriétés, remplacez son nom par client. Choisir fichier | Enregistrez le projet sous et enregistrez le fichier de formulaire et le fichier projet dans un dossier frère relatif au dossier du projet SideBySide . Choisir Projet | Références, case activée la case à cocher en regard de SideBySide et choisissez OK.

Double-cliquez sur le formulaire main dans le concepteur de formulaires et collez le code suivant dans Sub Form_Load() :

    Dim obj As New SideBySideClass
    Dim isxs As SideBySide.ISideBySideClass
    Set isxs = obj
    MsgBox isxs.Version()

Choisir fichier | Faire client.exe... accédez au dossier \deployed , puis choisissez OK.

Étape 5

À l’heure actuelle, le dossier \deployed doit contenir, en dehors de certains fichiers intermédiaires, uniquement client.exe et SideBySide.dll; et ce dernier aura été inscrit par son processus de génération. Pour case activée que votre serveur et votre client fonctionnent ensemble dans ces circonstances normales, exécutez \deployed\client.exe et notez la sortie attendue « 1.0.0-C# » ou « 1.0.0-VB.NET ».

Étape 6

Cette procédure pas à pas concerne COM sans inscription . Nous devons donc annuler l’inscription de l’assembly SideBySide . À une invite de commandes Visual Studio 2003, accédez au dossier \deployed et exécutez la commande : regasm /u SideBySide.dll.

Étape 7

Pour voir l’effet de l’étape précédente, réexécutez\deployed\client.exe et vous verrez le message « Classe non inscrite » ou « Erreur d’exécution '429' : le composant ActiveX ne peut pas créer d’objet ». À ce stade, nous avons frustré le runtime COM de trouver les informations dont il a besoin dans le registre, mais nous n’avons pas encore mis ces informations à disposition par d’autres moyens. Nous y remédierons dans les étapes suivantes.

Activation Registration-Free

Étape 8

Dans le dossier \deployed , créez un fichier manifeste d’application (un fichier texte) pour l’application client.exe et appelez-le client.exe.manifest. Collez ce qui suit dans le fichier :

<?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>

Étape 9

Dans le dossier du projet SideBySide , créez un fichier manifeste d’assembly privé (un fichier texte) et appelez-le SideBySide.manifest. Collez ce qui suit dans le fichier :

<?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>

La tâche suivante consiste à incorporer le fichier manifeste d’assembly ci-dessus dans l’assembly SideBySide en tant que ressource Win32. Au moment de la rédaction de cet article, cette opération est obligatoire pour Windows XP, mais pas pour Windows Server 2003. Sur Windows Server 2003, vous pouvez simplement déployer le fichier manifeste d’assembly en même temps que l’assembly. Toutefois, je vous invite vivement à ne pas dépendre de ce comportement, car il pourrait bien changer dans un prochain Service Pack Windows Server 2003. Pour vous assurer que vous continuez à prendre en charge les deux plateformes à l’avenir, suivez les étapes suivantes et incorporez votre fichier manifeste d’assembly dans votre assembly .NET en tant que ressource Win32. Cela n’est nécessaire que pour l’activation sans inscription de . Composants basés sur NET et n’est pas une exigence pour l’activation sans inscription des composants COM natifs .

Étape 10

Dans le dossier du projet SideBySide , créez un fichier de script de définition de ressource (un fichier texte) et appelez-le SideBySide.rc. Collez ce qui suit dans le fichier :

#include <windows.h>
#define MANIFEST_RESOURCE_ID 1
MANIFEST_RESOURCE_ID RT_MANIFEST SideBySide.manifest

Le fichier windows.h et ses dépendances sont disponibles lorsque vous installez le Kit de développement logiciel (SDK) de plateforme (section Core SDK) ou Visual C++. La partie de windows.h requise ici est la définition :

#define RT_MANIFEST 24

Par conséquent, le contenu de SideBySide.rc se résout comme suit :

1 24 SideBySide.manifest

Toutefois, il est plus clair et plus général d’utiliser les définitions de macros comme indiqué.

Étape 11

Dans le dossier du projet SideBySide , créez un fichier de commandes de build (un fichier texte) et appelez-le build.cmd. Collez ce qui suit dans le fichier :

Pour générer C#:

rc SideBySide.rc
csc /t:library /out:..\deployed\SideBySide.dll 
/win32res:SideBySide.res Class1.cs

Pour générer Visual Basic .NET :

rc SideBySide.rc
vbc /t:library /out:..\deployed\SideBySide.dll 
/win32resource:SideBySide.res /rootnamespace:SideBySide Class1.vb

Ces commandes appellent d’abord l’outil Microsoft Windows Resource Compiler à partir du Kit de développement logiciel (SDK) de plateforme (rc.exe) pour compiler le script de définition de ressource de l’étape 10 dans un fichier de ressources compilé appelé SideBySide.res. Ensuite, il appelle le compilateur C# ou Visual Basic .NET pour générer votre fichier de code source dans un assembly et y incorporer le fichier de ressources compilé en tant que ressource Win32. L’assembly compilé est écrit dans le dossier \déployé , mais il n’est pas inscrit pour l’interopérabilité COM.

Étape 12

À une invite de commandes Visual Studio 2003, accédez au dossier du projet SideBySide et exécutez la commande : build.

Étape 13

Pour vérifier que, grâce aux fichiers manifestes, votre client est à nouveau en mesure d’activer la classe SideBySideClass via l’interopérabilité COM, d’exécuter \deployed\client.exe et de noter la sortie attendue « 1.0.0-C# » ou « 1.0.0-VB.NET ».

Résolution des problèmes

Comme nous l’avons vu, l’activation sans inscription des composants basés sur .NET Framework ne nécessite aucun code spécial dans le serveur ou dans le client. Tout ce qui est nécessaire est une paire de fichiers manifeste correspondants, dont l’un est incorporé dans l’assembly .NET en tant que ressource Win32 de type RT_MANIFEST.

Je vous suggère d’aborder votre propre développement sans inscription comme le fait cette procédure pas à pas. Plus précisément : accédez d’abord à un état connu en voyant votre client travailler avec un serveur inscrit ; annulez ensuite l’inscription du serveur et vérifiez que votre message d’erreur correspond à ce que vous attendiez ; et enfin remédier à la situation en créant et en déployant des fichiers manifestes. De cette façon, vos efforts de résolution des problèmes liés à l’activation sans inscription seront limités à la structure de vos fichiers manifestes et à l’incorporation correcte du manifeste d’assembly.

Lors de la résolution des problèmes COM sans inscription, le observateur d'événements sur Windows Server 2003 est votre ami. Lorsque Windows XP ou Windows Server 2003 détecte une erreur de configuration, il affiche généralement une zone de message d’erreur intitulée pour l’application que vous avez lancée et contenant le message « Cette application n’a pas pu démarrer, car la configuration de l’application est incorrecte. La réinstallation de l’application peut résoudre ce problème. » Je conseille que chaque fois que vous voyez ce message que vous reproduisez le problème sur Windows Server 2003, consultez le journal des événements système et recherchez les événements de la source SideBySide . La raison pour laquelle je ne suggère pas que vous examiniez le journal des événements de XP dans ces cas est qu’il contiendra invariablement un message tel que « Générer le contexte d’activation a échoué pour [chemin]\[nom de fichier de l’application]. Manifeste. Message d’erreur de référence : L’opération s’est terminée correctement », ce qui ne permet pas d’identifier le problème.

Avant de passer à la structure des fichiers manifestes, parlons des ressources Win32. Comme je l’ai mentionné ci-dessus, windows.h définit le symbole RT_MANIFEST comme valeur 24, qui est la valeur que le système d’exploitation reconnaîtra en tant que fichier manifeste incorporé. Si vous oubliez d’inclure windows.h dans votre script de définition de ressource (fichier .rc), votre build réussit toujours et votre fichier manifeste sera toujours incorporé en tant que ressource, mais pas du type correct. Pour vérifier que vous avez correctement incorporé son manifeste, ouvrez votre SideBySide.dll dans Visual Studio (Fichier | Ouvrir | Fichier...). Vous verrez une arborescence montrant les ressources à l’intérieur du module. Sous le nœud racine doit se trouver un nœud nommé RT_MANIFEST sous lequel doit être un autre nœud affichant le numéro de ressource de votre ressource manifeste (1 dans la procédure pas à pas). Double-cliquez sur ce dernier nœud pour voir les données dans une vue binaire et lui donner un aperçu rapide case activée qu’il ressemble à votre fichier manifeste XML. Bien qu’il soit binaire, les caractères de la plage ASCII seront évidents. Si les données binaires sont manquantes ou semblent incorrectes, vérifiez que votre script de définition de ressource (fichier .rc) fait référence à votre fichier manifeste. Si le texte du nœud RT_MANIFEST est entre guillemets, vous avez probablement oublié d’inclure windows.h dans votre script de définition de ressources (fichier .rc).

Chacune des erreurs qui viennent d’être mentionnées est signalée dans le journal des événements système Windows Server 2003 avec le message : « L’assembly dépendant [nom] est introuvable et la dernière erreur est L’assembly référencé n’est pas installé sur votre système ».

Les schémas des différents fichiers manifeste sont documentés dans le Kit de développement logiciel (SDK) de plateforme sous le titre Informations de référence des fichiers manifestes, et l’outil de validation de schémaManifestchk.vbs est disponible. Par conséquent, je n’appelle ici que quelques points pertinents pour la procédure pas à pas. Examinons d’abord le fichier manifeste d’assembly. Pour obtenir un exemple, revenez à l’étape 9.

Vous vous souviendrez que, dans le sens COM libre d’inscription , un assembly est une idée abstraite à laquelle vous associez un ou plusieurs fichiers physiques au moyen du contenu du fichier manifeste d’assembly .

L’élément assemblyIdentity définit l’identité de l’assembly. Pour. L’attribut nom de l’assembly .NET doit correspondre aux composants NET et donc à son nom de fichier. Sinon, vous verrez le message suivant dans le journal des événements système Windows Server 2003 : « L’assembly dépendant [valeur de l’attribut de nom ] est introuvable et la dernière erreur est L’assembly référencé n’est pas installé sur votre système ». Toutefois, l’attribut de version n’a pas besoin de correspondre à AssemblyVersion de l’assembly .NET, ni à son AssemblyFileVersion, bien qu’il soit judicieux d’appliquer une certaine cohérence.

L’élément clrClass n’a que deux attributs obligatoires : name et clsid. L’attribut namedoit correspondre à l’espace de noms combiné et au nom de classe de la classe CLR en cours d’activation. Si ce n’est pas le cas, CoCreateInstance retourne un HRESULT avec la valeur COR_E_TYPELOAD (0x80131522). Cela résulte de la levée d’une exception System.TypeLoadException lorsque le chargeur de type ne parvient pas à trouver le type CLR demandé dans votre assembly .NET. Une chose à watch si votre assembly .NET est écrit en Visual Basic .NET est que vous fournissez le commutateur /rootnamespace sur la ligne de commande au compilateur .NET Visual Basic (vbc.exe). L’attribut clsiddoit correspondre au CLSID attribué à la classe CLR activée via son GuidAttribute. Si ce n’est pas le cas, CoCreateInstance retourne un HRESULT avec la valeur REGDB_E_CLASSNOTREG (0x80040154), le texte du message pour lequel est « Classe non inscrite ».

Nous allons maintenant nous intéresser au fichier manifeste de l’application. Pour obtenir un exemple, revenez à l’étape 8. Le manifeste de l’application doit être nommé au format [nom_fichier de l’application].manifest. Ainsi, dans la procédure pas à pas, il a été nommé client.exe.manifest pour qu’il soit clair qu’il doit être lu chaque fois queclient.exe est chargé dans un processus. Si cela n’est pas effectué correctement, CoCreateInstance retourne un HRESULT avec la valeur REGDB_E_CLASSNOTREG (0x80040154), le texte du message pour lequel est « Classe non inscrite ».

L’élément le plus important dans le manifeste d’application est l’élémentassemblyIdentitydependentAssembly/. Cet élément est une référence à l’équivalent dans le manifeste de l’assembly et les deux doivent correspondre exactement. Un bon moyen de s’assurer qu’ils le font est de copier l’élément à partir du manifeste de l’assembly et de le coller ici. En cas de différence, le message suivant s’affiche dans le journal des événements système Windows Server 2003 : « L’identité du composant trouvé dans le manifeste ne correspond pas à l’identité du composant demandé ».

Conclusion

COM sans inscription est une technologie qui libère les composants COM d’une dépendance vis-à-vis du registre Windows et, par conséquent, libère les applications qui les utilisent d’avoir besoin de serveurs dédiés. Il permet aux applications ayant des dépendances sur différentes versions du même composant COM de partager une infrastructure et de charger ces différentes versions de composants COM côte à côte dans un écho du mécanisme de contrôle de version et de déploiement .NET.

Cet article vous guide tout au long d’une démonstration de l’activation sans inscription des composants basés sur .NET Framework par des applications clientes natives écrites dans Visual C++ et Visual Basic 6.0. Il a expliqué certains des fonctionnements du mécanisme et souligné certaines erreurs de configuration possibles et la façon de les résoudre.

En savoir plus

 

À propos de l’auteur

Steve White est consultant en développement d’applications au sein de l’équipe Premier Support for Developers de Microsoft UK. Il prend en charge le développement de clients avec Visual C#, Windows Forms et ASP.NET. Son blog contient plus d’informations sur ses intérêts dans la musique, les visualisations et la programmation.

Leslie Muller est technologue au sein de l’équipe de développement de la recherche & au Credit Suisse First Boston. Leslie a 12 ans d’expérience en tant que développeur et architecte technique, travaillant dans des environnements tels que les services financiers, les start-ups technologiques, l’automatisation industrielle et la défense. Lorsqu’il ne programme pas ou ne fait pas de recherche, il aime le ski, le hockey sur glace et, si possible, faire des choses un peu folles avec des véhicules motorisés dans des environnements extrêmes comme l’Islande ou les Rocheuses.