Qu'est-ce que Reg-Free COM - Utiliser COM sans enregistrement

· Mis à jour le: · · COM, Reg-Free COM, Registration-Free COM, Développement Windows, Technologie héritée

Dans les projets COM / ActiveX / OCX, la même boue ressurgit à chaque déploiement et à chaque mise à jour.

  • regsvr32 est nécessaire
  • Les droits administrateur ont tendance à devenir nécessaires
  • On entre en collision avec une version différente installée par une autre application
  • Une désinstallation entraîne d’autres produits avec elle
  • Cela fonctionne sur la machine de développement mais échoue dans un environnement propre

Ce qui peut considérablement réduire ce bourbier, c’est Reg-Free COM. Cela dit, malgré son nom, ce n’est pas « la magie qui fait disparaître tous les tracas de COM ». Ce qui disparaît, ce sont surtout les tracas entraînés par l’enregistrement global. Les difficultés liées à la bitness, aux DLL dépendantes, aux bibliothèques de types ou aux modèles de threading, elles, ne s’évanouissent pas.

Dans cet article, nous organisons Reg-Free COM principalement autour du contexte consistant à confiner les DLL / OCX COM au niveau de l’application dans les applications de bureau Windows.

1. La conclusion d’abord (en une phrase)

Commençons par une formulation approximative mais utile.

  • Reg-Free COM est une manière de conserver les informations d’enregistrement COM dans un manifeste plutôt que dans le registre
  • À l’exécution, lors de la résolution de CoCreateInstance ou CLSIDFromProgID, le contexte d’activation est consulté en premier
  • Par conséquent, les DLL / OCX COM peuvent être conservées privées par application
  • Les principaux avantages sont un déploiement XCOPY facile, un évitement plus aisé des conflits de version, et des désinstallations plus difficiles à casser
  • Cependant, le problème 32 bits / 64 bits ne disparaît pas. Aucune volonté ne permet de le contourner
  • De plus, les DLL dépendantes, les bibliothèques de types, les références au moment de la conception et les dépendances d’enregistrement non standard doivent être envisagées séparément
  • En pratique, c’est un très bon choix quand on veut livrer des composants COM spécifiques à l’application aux côtés de celle-ci

En résumé, Reg-Free COM est un mécanisme qui ramène l’activation COM au niveau de chaque application.

2. Ce que cet article entend par Reg-Free COM

Reg-Free COM est l’abréviation de Registration-Free COM. En japonais, on le désigne parfois par une expression qui se traduit littéralement par « COM sans enregistrement requis ».

Ici, « sans enregistrement » signifie ne pas dépendre entièrement de l’enregistrement global dans le registre — comme HKCR / CLSID / InprocServer32 — pour utiliser COM. Cela ne signifie ni que COM lui-même disparaît, ni que les GUID deviennent inutiles.

Les principaux sujets de cet article sont les suivants.

  • DLL COM natives
  • Serveurs COM basés sur ATL
  • ActiveX / OCX
  • Interopérabilité COM basée sur .NET Framework
  • Exposition COM via le COM host de .NET 5+ / .NET 8

À l’inverse, il y a deux points que cet article souhaite souligner.

  1. Reg-Free COM concerne l’« activation »
  2. La distribution des informations de type et la configuration des références au moment de la conception peuvent rester des questions distinctes

Les mélanger brouille considérablement la discussion.

3. Vue d’ensemble en un coup d’œil

Il est plus rapide de commencer par voir l’ensemble du tableau en une seule fois.

MyApp.exeApplication ManifestdependentAssemblyComponent / Assembly Manifestfile / comClass / typelibVendorControl.dll / .ocxActivation ContextCLSIDFromProgID / CoCreateInstance

Avec un COM ordinaire, l’appel à CoCreateInstance parcourt le registre pour décider quelle DLL charger. Avec Reg-Free COM, avant cela, c’est le contexte d’activation actuellement actif qui est consulté, et la résolution se fait à partir des informations de manifeste qui y sont inscrites.

Grâce à cela, l’application A et l’application B sur une même machine peuvent plus facilement fonctionner chacune avec des versions différentes d’une même famille de composants COM. Cela ramène un peu la culture du partage de COM vers quelque chose de plus local à l’application.

4. Pourquoi le déploiement COM classique a tendance à devenir lourd

Si le déploiement COM classique est lourd, ce n’est pas tant parce que COM lui-même est mauvais, mais à cause de l’hypothèse d’un enregistrement global.

Pour utiliser une classe COM, il faut environ ce type d’informations.

Information Rôle
CLSID GUID identifiant la classe de façon unique
ProgID Nom lisible par un humain
InprocServer32 Quelle DLL charger
ThreadingModel Hypothèses telles que Apartment / Both
TypeLib Informations de type

Une fois ces informations placées dans le registre, elles deviennent pratiques à l’échelle de toute la machine, car elles sont faciles à partager entre plusieurs applications.

En pratique, cependant, ce partage se retourne contre nous.

  • L’installation d’un produit écrase l’enregistrement COM d’un autre produit
  • Un désinstalleur, persuadé de « ne retirer que ses propres éléments », casse un COM partagé
  • Un enregistrement qui se trouve par hasard sur la machine de développement n’existe pas sur la machine de production
  • Les enregistrements 32 bits et 64 bits ne s’accordent pas, et seuls les symptômes dérivent de façon inquiétante

Autrement dit, c’est bien plus souvent le modèle de déploiement que COM lui-même qui pose problème. Reg-Free COM est un mécanisme destiné à réduire la difficulté de ce modèle de déploiement.

5. Comment fonctionne Reg-Free COM

5.1 Déclarer les dépendances dans le manifeste d’application

Tout d’abord, côté application, on écrit dans le manifeste d’application de quels assemblies side-by-side l’application dépend.

Ce manifeste peut être géré de deux façons :

  • placé à côté de l’EXE, comme MyApp.exe.manifest
  • intégré dans l’EXE en tant que ressource

En pratique, on distingue souvent ainsi : un fichier externe si l’on veut garder le déploiement et le remplacement visibles, ou l’intégration si l’on privilégie la robustesse et la simplicité de la distribution.

Notez que, lorsque les deux versions — fichier externe et version intégrée — existent, c’est le manifeste présent sur le système de fichiers qui a priorité.

5.2 Décrire les informations COM dans le manifeste de composant

Ensuite, côté COM, les informations qui iraient normalement dans le registre sont portées par le manifeste de composant.

On y trouve par exemple des informations telles que :

  • comClass
  • clsid
  • progid
  • threadingModel
  • typelib
  • si nécessaire, proxy / stub, window class, etc.

Autrement dit, l’idée est de décrire le visage du composant COM en XML, à la place du registre.

Ce manifeste peut lui aussi être configuré de deux façons :

  • placé comme fichier séparé à côté de la DLL
  • intégré dans la DLL en tant que ressource

En pratique, l’intégrer dans la DLL en tant que private assembly provoque souvent moins d’incidents. Fonctionner avec un fichier séparé est plus facile à comprendre, mais on trébuche facilement sur la correspondance entre le nom de fichier et l’assemblyIdentity, sur l’emplacement, ou sur des copies oubliées.

5.3 À l’exécution, le contexte d’activation est consulté en premier

C’est là le cœur de Reg-Free COM.

Quand l’application appelle CLSIDFromProgID ou CoCreateInstance, le runtime COM regarde le contexte d’activation actif. Si les informations nécessaires ProgID → CLSID et CLSID → DLL s’y trouvent, la résolution aboutit sans passer par le registre.

À l’inverse, si les informations nécessaires manquent dans le manifeste, on retombe sur la résolution habituelle basée sur l’enregistrement. Ce comportement crée le piège du « ça fonctionne par hasard sur la machine de développement » : on croit être passé en Reg-Free, alors qu’en réalité on est secouru par un enregistrement local.

C’est le piège le plus vicieux de Reg-Free COM.

6. Ce que l’on y gagne

En pratique, les avantages de Reg-Free COM sont assez nets.

6.1 Déploiement XCOPY facilité

On peut regrouper tous les fichiers nécessaires dans le dossier de l’application, ce qui allège l’installateur et les étapes d’enregistrement. Bien sûr, si l’on écrit sous Program Files, les droits d’accès sont une autre question, mais on peut au moins réduire le travail d’administrateur nécessaire à l’enregistrement COM.

6.2 Réduction plus facile des conflits de version

Même si plusieurs versions d’un composant COM coexistent sur la même machine, il devient plus facile de séparer la version utilisée par chaque application. On évite ainsi largement l’incident où « le comportement change soudainement à cause de l’installation d’un autre produit ».

6.3 Souvent peu de changements nécessaires dans le code existant

Reg-Free COM est un mécanisme qui change la manière dont la résolution s’opère, plutôt que de changer fondamentalement la façon dont le code existant effectue ses appels. Ainsi, lorsque cela s’adapte bien, on peut l’adopter en touchant à peine au code du côté CoCreateInstance.

6.4 Suppression et retour arrière facilités

Comme tout est confiné au niveau de l’application, les mises à jour et les retours en arrière deviennent beaucoup plus directs. Pour le dire de façon un peu extrême, il devient facile d’adopter l’idée de remplacer le dossier entier.

7. Situations adaptées et situations à éviter

7.1 Situations où c’est adapté

Dans des cas comme ceux-ci, Reg-Free COM est une option très solide.

Situation Adéquation
Vous voulez fournir une DLL / un OCX COM spécifique à l’application Très bonne
Vous voulez faire coexister plusieurs versions sur le même PC Très bonne
Vous voulez éviter les incidents d’enregistrement liés aux composants d’un fournisseur Bonne
Vous voulez utiliser un ActiveX / OCX en privé dans une application de bureau existante Bonne
Vous voulez alléger le déploiement sans modifier profondément les appels existants Bonne

Typiquement, cela s’accorde bien avec les applications de bureau métier, les outils d’intégration d’équipements, et les actifs existants en VB6 / MFC / WinForms.

7.2 Situations où ce n’est pas adapté, ou à examiner avec prudence

À l’inverse, certains cas méritent un examen prudent.

Situation Commentaire
Vous voulez partager COM à l’échelle de la machine L’intérêt de Reg-Free est réduit
La bitness ne correspond pas Reg-Free ne résout pas cela
Forte dépendance à des informations d’enregistrement non standard ou à une installation maison Difficile à exprimer sous forme de manifeste
La distribution des DLL dépendantes ou du runtime VC++ n’est pas réglée On trébuchera de toute façon ailleurs
Les outils de conception ou les références de l’IDE présupposent le registre Une conception d’exploitation distincte est nécessaire

Le dernier point compte particulièrement. Reg-Free COM aide l’activation à l’exécution, mais il ne change pas d’un coup ce que présuppose l’interface de configuration des références au moment de la conception.

8. Idées reçues courantes

8.1 « Avec Reg-Free COM, le problème de bitness disparaît »

Faux. Un processus 32 bits ne peut charger que des DLL COM in-proc 32 bits, et un processus 64 bits ne peut charger que des DLL 64 bits. Cela reste exactement pareil avec Reg-Free.

8.2 « Avec Reg-Free COM, le registre n’est jamais consulté »

C’est faux également. Si les informations nécessaires manquent dans le manifeste, on retombe sur la résolution habituelle basée sur l’enregistrement. C’est pourquoi un succès sur la machine de développement ne garantit pas que la configuration Reg-Free est correcte.

8.3 « Avec Reg-Free COM, la question des bibliothèques de types se règle automatiquement »

Ce n’est vrai qu’à moitié. Le manifeste peut aussi porter des informations typelib, mais il est parfaitement normal que la gestion des informations de type — les références VBA, le #import en C++, la génération de références au moment de la conception côté .NET, etc. — nécessite une conception séparée.

Reg-Free COM traite d’abord de faire en sorte que ça démarre. Comment développer de façon typée est la question suivante.

8.4 « Avec Reg-Free COM, n’importe quel ActiveX / OCX passe tel quel »

C’est également risqué. Si le composant repose sur des informations d’enregistrement COM standard, on avance facilement, mais si sa dépendance à des paramètres de registre propriétaires, à une installation additionnelle, à un traitement de licence ou à un groupe d’autres modules est forte, le passage en Reg-Free devient soudain difficile.

8.5 « Reg-Free COM sur .NET Framework et sur .NET 8, c’est à peu près pareil »

Il y a des similitudes, mais les chaînes d’outils diffèrent considérablement. Le contexte .NET Framework + RegAsm et le contexte .NET 5+ / .NET 8 + comhost reposent sur des bases différentes, même s’il s’agit de COM dans les deux cas.

9. Différences entre natif / .NET Framework / .NET 5+ / .NET 8

C’est un point facile à confondre, séparons-le une bonne fois.

Famille Résumé sommaire
DLL / OCX COM natives Fondamentalement, on raisonne avec manifeste d’application + manifeste de composant
Interopérabilité COM basée sur .NET Framework En plus d’un manifeste d’application de style Win32, un manifeste côté composant managé est également nécessaire
Exposition COM sur .NET 5+ / .NET 8 EnableComHosting crée un COM host, et EnableRegFreeCom peut générer un manifeste pour Reg-Free

9.1 COM basé sur .NET Framework

Avec le COM basé sur .NET Framework, on se retrouve avec une structure à deux niveaux : un manifeste d’application de style Win32 côté application COM, et un manifeste de composant côté composant managé.

Cette partie est un peu plus compliquée que le COM natif. Au moment où l’on se dit « j’ai compris Reg-Free COM, mais dès qu’un composant managé entre en jeu, un manifeste supplémentaire apparaît soudainement », la conversation redevient un peu boueuse.

9.2 Exposition COM sur .NET 5+ / .NET 8

Sur .NET 5+ / .NET 8, le point d’entrée de l’exposition COM devient *.comhost.dll. En ajoutant EnableRegFreeCom=true, un manifeste side-by-side pour Reg-Free COM est également généré.

Cependant, ce qui compte ici aussi, c’est que Reg-Free COM et la stratégie TLB sont deux choses distinctes. .NET Core / .NET 5+ n’est pas le monde de l’époque .NET Framework où « un TLB sortait naturellement de l’assembly ». Si un usage typé est nécessaire, il est plus sûr de traiter séparément la génération, l’intégration et l’enregistrement du TLB.

10. Esquisse d’une configuration minimale

Voici une esquisse minimale où MyApp.exe utilise Vendor.CameraControl.dll via Reg-Free COM.

10.1 Esquisse de la structure des fichiers

MyApp.exe
MyApp.exe.manifest
Vendor.CameraControl.dll
Vendor.Helper.dll

Dans l’exemple ci-dessus, on suppose que le manifeste de composant est intégré du côté de la DLL. Un fichier séparé fonctionne aussi, mais l’intégration est plus simple à organiser pour commencer.

10.2 Esquisse du manifeste d’application

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="KomuraSoft.MyApp"
    version="1.0.0.0"
    processorArchitecture="amd64" />

  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Vendor.CameraControl.Asm"
        version="1.0.0.0"
        processorArchitecture="amd64" />
    </dependentAssembly>
  </dependency>
</assembly>

10.3 Esquisse du manifeste de composant

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="Vendor.CameraControl.Asm"
    version="1.0.0.0"
    processorArchitecture="amd64" />

  <file name="Vendor.CameraControl.dll">
    <comClass
      clsid="{01234567-89AB-CDEF-0123-456789ABCDEF}"
      progid="Vendor.CameraControl.1"
      threadingModel="Apartment"
      tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}" />

    <typelib
      tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}"
      version="1.0"
      helpdir="" />
  </file>
</assembly>

Ce qui compte vraiment dans cet exemple, plus que les détails du XML, c’est que le dependentAssembly côté application et l’assemblyIdentity côté composant correspondent. Si cela diverge, on en souffre de façon assez silencieuse.

Notez que les GUID et les noms ci-dessus sont des exemples à des fins d’explication. En pratique, il faut les écrire correctement, en cohérence avec le CLSID / TLBID / ProgID / modèle de threading réellement exposés par le composant.

11. Pièges courants

11.1 Ça fonctionne sur la machine de développement mais pas sur le poste de destination

Le premier suspect à examiner est le cas où l’on était en réalité secouru par un enregistrement de registre. Il est plus sûr de vérifier Reg-Free COM dans un environnement propre autant que possible.

11.2 Échec de démarrage avec « side-by-side configuration is incorrect »

Cette famille d’erreurs survient à cause d’incohérences de manifeste, de DLL dépendantes manquantes, d’un runtime VC++ absent, d’une différence d’architecture, etc. Le message d’erreur en surface seul étant peu explicite, l’approche classique consiste à remonter la cause via le journal des événements et sxstrace.

11.3 Le manifeste de composant et le manifeste d’application se désynchronisent

  • Le name diffère
  • La version diffère
  • Le processorArchitecture diffère
  • Le manifeste que l’on pensait avoir copié est obsolète

Ce sont des différences qui paraissent minimes en apparence, mais qui ont un impact considérable au démarrage.

11.4 Oublier de placer une DLL dépendante

Si l’on se satisfait de ne voir que Vendor.CameraControl.dll, on oublie Vendor.Helper.dll chargée ensuite, le runtime VC++, ainsi que les DLL proxy / stub. Reg-Free COM réduit les problèmes d’enregistrement COM, mais il ne fait pas non plus disparaître les problèmes de résolution des dépendances natives.

11.5 Repousser la gestion de la bibliothèque de types et des références

Même une fois l’activation à l’exécution en place, dès que l’on veut

  • faire du early binding depuis VBA
  • utiliser #import en C++
  • générer de l’interop au moment de la conception côté .NET

il faut une façon de distribuer les informations de type. Reg-Free COM ne règle pas automatiquement tout cela, il est donc important de penser séparément le runtime et le design-time.

12. Résumé

Si l’on devait résumer Reg-Free COM en une phrase, c’est un mécanisme qui fait glisser les informations d’enregistrement COM de l’échelle de la machine entière vers l’échelle de chaque application.

Cela apporte les avantages suivants :

  • Plus facile de confiner les DLL / OCX COM au niveau de l’application
  • Plus facile de réduire les conflits de version
  • Plus facile de simplifier le déploiement et le retour arrière

En revanche,

  • 32 bits / 64 bits
  • DLL dépendantes
  • TLB / configuration des références
  • dépendances d’enregistrement non standard
  • vérification dans un environnement propre

restent tout aussi importants.

L’attitude de base à adopter lors de l’introduction de Reg-Free COM est donc la suivante :

  1. Accepter que c’est une question d’activation
  2. Séparer les questions de runtime et de design-time
  3. Vérifier dans un environnement propre
  4. Régler d’abord la bitness et les DLL dépendantes

En suivant cet ordre, on réduit considérablement les risques d’incident.

13. Articles connexes

14. Références

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

Qu'est-ce que Reg-Free COM et comment fonctionne-t-il ?
Reg-Free COM (COM sans enregistrement) est une manière de conserver les informations d'enregistrement COM dans des manifestes plutôt que dans le registre. Le manifeste d'application déclare les assemblies side-by-side dont l'application dépend, et un manifeste de composant porte les informations comClass, clsid, progid, threadingModel et typelib qui vivraient sinon dans le registre. À l'exécution, lorsque l'application appelle CoCreateInstance ou CLSIDFromProgID, le contexte d'activation est consulté en premier, ce qui permet de garder les DLL et OCX COM privées à chaque application, sans regsvr32 ni enregistrement administrateur.
Reg-Free COM résout-il le problème 32 bits / 64 bits ?
Non. Un processus 32 bits ne peut charger que des DLL COM in-proc 32 bits, et un processus 64 bits ne peut charger que des DLL 64 bits ; cela reste exactement pareil avec Reg-Free COM. Reg-Free COM n'efface pas non plus les problèmes de résolution des dépendances natives : les DLL dépendantes, le runtime VC++ et les DLL proxy / stub doivent toujours être placées correctement. Ce qu'il supprime, ce sont les tracas entraînés par l'enregistrement global, comme les conflits de version et les désinstallations qui cassent des composants partagés.
Pourquoi mon application Reg-Free COM fonctionne-t-elle sur la machine de développement mais échoue-t-elle sur le poste cible ?
Le premier suspect est que, sur la machine de développement, vous étiez en réalité secouru par un enregistrement de registre déjà présent. Si le manifeste manque des informations nécessaires, COM retombe sur la résolution habituelle basée sur l'enregistrement ; un succès sur la machine de développement ne garantit donc pas que la configuration Reg-Free est correcte. Vérifiez dans un environnement propre autant que possible. Pour les erreurs de démarrage « side-by-side configuration is incorrect », remontez la cause via le journal des événements et sxstrace, et vérifiez que le dependentAssembly côté application et l'assemblyIdentity côté composant correspondent exactement en nom, version et processorArchitecture.
Reg-Free COM gère-t-il aussi les bibliothèques de types et les références au moment de la conception ?
Seulement en partie. Un manifeste peut porter des informations typelib, mais Reg-Free COM concerne avant tout l'activation à l'exécution - faire en sorte que les choses démarrent. La manière de développer avec des types est une question distincte : les références VBA, le #import en C++, et la génération de références d'interop au moment de la conception côté .NET nécessitent en général leur propre conception pour la distribution des informations de type. Sur .NET 5+ / .NET 8, EnableRegFreeCom peut générer un manifeste Reg-Free pour le COM host, mais la génération et l'enregistrement du TLB doivent encore être réglés séparément.

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog