Un exemple concret de pont COM pour appeler une DLL 64 bits depuis une application 32 bits

· Mis à jour le: · · COM, Développement Windows, 32bit, 64bit

Vouloir appeler une DLL 64 bits depuis une application 32 bits est une exigence assez classique sous Windows. Notamment lorsqu’on souhaite conserver les ressources existantes en place et n’utiliser que les fonctionnalités du côté 64 bits, une architecture en pont COM tend à être la réponse pratique.

Sommaire

  1. Le scénario
  2. La solution
  3. Déroulement du traitement (diagramme de séquence)
  4. Exemple de code (conceptuel)
  5. Exemple de code complet
  6. Références

1. Le scénario

C’est le cas où l’on souhaite conserver une application 32 bits existante telle quelle, mais utiliser un traitement qui réside dans une DLL 64 bits. Le problème est qu’un processus 32 bits ne peut pas charger une DLL 64 bits. Il s’agit d’une contrainte au niveau du système d’exploitation - ce n’est pas quelque chose que l’on peut contourner par une astuce quelconque.

La situation typique ressemble à ceci.

  • L’application 32 bits existante est un actif volumineux qui ne peut pas être migré à court terme
  • La DLL 64 bits possède de nouvelles fonctionnalités, ou ses dépendances sont exclusivement 64 bits
  • On souhaite l’appeler depuis le côté 32 bits « de façon typée »

Avec cette combinaison, la voie in-process est fermée dès le départ.

2. La solution

La solution de base consiste à séparer via un COM out-of-proc (un serveur EXE). La DLL 64 bits est appelée depuis un serveur COM 64 bits (EXE), et l’application 32 bits l’utilise via COM.

Le déroulement est le suivant.

  1. Construire un COM LocalServer 64 bits (EXE) qui appelle la DLL 64 bits en interne
  2. Partager l’interface COM (IDL/TypeLib) pour exposer les types
  3. L’application 32 bits appelle COM « de façon typée » (communication via proxy/marshaling)

Il existe toutefois des points d’attention.

  • Les enregistrements 32 bits et 64 bits sont distincts (y compris WOW6432Node)
  • Les structures personnalisées nécessitent une conception de marshaling
  • La surcharge de l’IPC existe, donc soyez attentif aux appels à haute fréquence

En bref, l’approche éprouvée consiste à « déplacer le traitement 64 bits vers un processus séparé et faire le pont avec COM ».

3. Déroulement du traitement (diagramme de séquence)

Voici le déroulement lorsque l’application 32 bits invoque un traitement de la DLL 64 bits.

Pris en charge par l'infrastructure de marshaling COM enregistréeDLL 64bitServeur COM 64bit(EXE)COM Stub(côté 64bit)RPC/IPC(communication inter-processus)COM Proxy(côté 32bit)Application cliente 32bitDLL 64bitServeur COM 64bit(EXE)COM Stub(côté 64bit)RPC/IPC(communication inter-processus)COM Proxy(côté 32bit)Application cliente 32bitMarshaling des paramètresDémarshaling des paramètresMarshaling de la valeur de retourDémarshaling de la valeur de retourICalcService.Add(1, 2)Données sérialiséesTransfert au-delà de la frontière de processusAdd(1, 2)Appel de fonction nativeRésultat : 3Résultat : 3Résultat sérialiséTransfert au-delà de la frontière de processusRésultat : 3

Points clés :

  • L’application 32 bits peut effectuer des appels typés via l’interface ICalcService
  • Le runtime COM franchit la frontière entre processus en utilisant la DLL proxy/stub enregistrée, le marshaleur TypeLib, le marshaleur standard, etc.
  • En raison de la surcharge de la communication inter-processus, regrouper le travail est préférable à de nombreux appels fins

4. Exemple de code (conceptuel)

Ce qui suit est une esquisse conceptuelle. En pratique, l’enregistrement et la génération de la TypeLib sont également nécessaires.

// Interface partagée (équivalent IDL)
[ComVisible(true)]
[Guid("7A4B5B23-0A2F-4D2B-9D4D-8A2A92B8B001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICalcService
{
    int Add(int a, int b);
}

// COM LocalServer 64bit (côté EXE)
[ComVisible(true)]
[Guid("1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11")]
[ClassInterface(ClassInterfaceType.None)]
public class CalcService : ICalcService
{
    public int Add(int a, int b)
    {
        // Appeler la DLL 64bit ici
        return a + b;
    }
}

// Côté application 32bit (client)
Type t = Type.GetTypeFromProgID("KomuraSoft.CalcService");
var calc = (ICalcService)Activator.CreateInstance(t);
int result = calc.Add(1, 2);

Sous cette forme, le côté 32 bits peut travailler « de façon typée ». COM utilise des proxies/stubs en interne et effectue l’appel via IPC pour vous.

5. Exemple de code complet

Une implémentation fonctionnelle du concept ci-dessus est publiée sur GitHub.

Call64bitDLLFrom32bitProc - GitHub

Le dépôt contient les éléments suivants :

  • Call64bitDLLFrom32bitProc/ - COM LocalServer 64bit (EXE)
  • X64DLL/ - DLL 64bit (le traitement réel)
  • X86App/ - Client 32bit (WinForms)
  • scripts/ - Scripts d’enregistrement/désenregistrement du serveur COM

Si vous le compilez et l’enregistrez en suivant les étapes du README, vous pouvez observer un processus 32 bits appelant réellement une DLL 64 bits.

6. Références

  • Vue d’ensemble du Component Object Model (COM) https://learn.microsoft.com/en-us/windows/win32/com/component-object-model–com–portal
  • Enregistrement de COM LocalServer32 https://learn.microsoft.com/en-us/windows/win32/com/localserver32
  • Notions de base sur les interfaces COM https://learn.microsoft.com/en-us/windows/win32/com/the-component-object-model
  • COM Interop (utilisation depuis .NET) https://learn.microsoft.com/en-us/dotnet/standard/native-interop/cominterop

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.

Une application 32 bits peut-elle charger une DLL 64 bits ?
Non. Un processus 32 bits ne peut pas charger une DLL 64 bits - il s'agit d'une contrainte au niveau du système d'exploitation Windows, pas d'un problème que l'on peut contourner par une astuce quelconque. La voie in-process est fermée dès le départ. Si vous avez besoin d'une fonctionnalité qui réside dans une DLL 64 bits, ce traitement doit s'exécuter dans un processus 64 bits séparé, et un pont COM est un moyen éprouvé de relier les deux.
Comment un pont COM relie-t-il une application 32 bits à une DLL 64 bits ?
Vous construisez un COM LocalServer 64 bits (un EXE) qui appelle la DLL 64 bits en interne, vous partagez l'interface COM via IDL ou une bibliothèque de types (TypeLib) pour exposer les types, et l'application 32 bits l'appelle via COM. Le runtime COM franchit la frontière entre processus grâce aux proxies, aux stubs et au marshaling, ce qui permet au côté 32 bits d'effectuer des appels typés via l'interface partagée.
Quels sont les principaux points d'attention avec un pont COM out-of-process ?
Il y en a trois principaux. Premièrement, les enregistrements COM 32 bits et 64 bits sont distincts, y compris la zone de registre WOW6432Node. Deuxièmement, les structures personnalisées nécessitent une conception de marshaling plutôt qu'un fonctionnement automatique. Troisièmement, la communication inter-processus ajoute une surcharge à chaque appel, il est donc préférable de regrouper le travail plutôt que de multiplier les appels fins dans des scénarios à haute fréquence.
Existe-t-il un exemple fonctionnel de pont COM 32 bits vers 64 bits ?
Oui. Une implémentation complète et fonctionnelle est publiée sur GitHub sous le nom du dépôt Call64bitDLLFrom32bitProc. Il contient un COM LocalServer EXE 64 bits, une DLL 64 bits avec le traitement réel, un client WinForms 32 bits, ainsi que des scripts d'enregistrement. Si vous le compilez et l'enregistrez en suivant le README, vous pouvez observer un processus 32 bits appelant réellement une DLL 64 bits.

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