ICallFactory avec des bibliothèques de types 32 bits et 64 bits côte à côte

J’ai un serveur COM in-proc pour lequel je veux construire des versions 32 bits et 64 bits. Je peux le faire sans problème. Cependant, je rencontre certains problèmes lorsque les deux versions sont enregistrées.

Je n’utilise pas ATL. Dans ma fonction DllRegisterServer, j’utilise RegisterTypeLibForUser . Je suis en train d’acquérir l’instance ITypeLib pour l’appel RegisterTypeLibForUser en appelant LoadTypeLibEx avec le chemin de mon DLL et j’utilise l’indicateur REGKIND_NONE. Je crée ma bibliothèque de types en utilisant .idl et le compilateur MIDL. J’intègre la bibliothèque de types dans mon fichier .dll en tant que ressource. Compte tenu des deux premières puces ci-dessous (où tout fonctionne comme prévu), il ne semble pas y avoir de problèmes avec la façon dont je le fais.

  • Si je m’enregistre UNIQUEMENT 32 bits, tout fonctionne correctement dans un client 32 bits, et des échecs sont attendus sur un client 64 bits (classe non enregistrée).
  • Si je m’inscris UNIQUEMENT 64 bits, tout fonctionne correctement dans un client 64 bits, et les défaillances attendues sur un client 32 bits (classe non enregistrée) sont attendues.
  • Si j’enregistre 64 bits suivi de 32 bits, tout fonctionne bien sur un client 32 bits, mais j’obtiens des échecs dans un client 64 bits. Si je désinsère ensuite le serveur 32 bits, le client 64 bits continue à échouer. Si je ré-enregistre le serveur 64 bits (avec ou sans désenregistrement), le client 64 bits fonctionne.
  • Si j’enregistre 32 bits suivis de 64 bits, tout fonctionne bien dans un client 64 bits, mais j’obtiens des échecs dans un client 32 bits. Si je désinscris ensuite le serveur 64 bits, le client 32 bits continue d’échouer. Si je ré-enregistre le serveur 32 bits (avec ou sans désenregistrement), le client 32 bits fonctionne.

Il semble que lorsque j’inscris les deux serveurs, le dernier appel RegisterTypeLibForUser fait quelque chose qui viderait les parameters du registre pour l’appel précédent RegisterTypeLibForUser .

Quant aux erreurs que je reçois:

  • CoCreateInstance fonctionne toujours tant que le serveur correct est enregistré. Dans un client 32 bits, CoCreateInstance fonctionne tant que le serveur 32 bits est enregistré (même si le serveur 64 bits est également enregistré). Idem pour le client 64 bits avec serveur 64 bits.
  • Dans toutes les situations où CoCreateInstance fonctionne, je peux invoquer des méthodes sur l’object. Je peux regrouper mes interfaces entre les appartements (j’utilise la table d’interface globale) et je peux invoquer des méthodes sur les interfaces marshalées.
  • Les erreurs que j’obtiens sont spécifiquement liées à ICallFactory dans un appartement auquel les interfaces ont été marshalées. Je peux interroger ICallFactory sur l’interface marshalée sans aucun problème. Mais quand j’appelle CreateCall avec l’IID de mon interface asynchrone, je reçois l’erreur E_NOINTERFACE.
  • Comme mentionné dans la liste précédente, je ne reçois pas cette erreur tant que le dernier serveur enregistré est celui avec la même plate-forme cible que le client.

J’essaie de fouiller dans mon registre maintenant et de comprendre exactement ce qui est changé au fur et à mesure que les enregistrements se produisent, mais en raison du redirecteur de registre, ce n’est pas si simple. Je mettrai à jour ce message lorsque je découvrirai les informations du registre.

Deviner.

RegisterTypeLib et RegisterTypeLibForUser écrivent toujours des entrées 32 bits et 64 bits lors de l’exécution sur un système d’exploitation 64 bits (même si le processus est 32 bits). Ceci est parfaitement acceptable dans la plupart des cas, car ce sont uniquement les métadonnées de la bibliothèque d’interface et de type qui sont écrites. Lorsque la clé d’interface est écrite, RegisterTypeLib / RegisterTypeLibForUser définit ProxyStubClsid32 sur le rapport p / s par défaut générique approprié au type d’interface (dual, oleautomation, etc.). Cependant, les proxy / stubs génériques ne semblent pas fonctionner avec ICallFactory sur des interfaces asynchrones personnalisées. J’ai modifié ma routine d’enregistrement pour toujours configurer mes informations de proxy / stub personnalisées dans les clés de registre 32 bits et 64 bits. Cela garantit qu’une inscription ultérieure ne surpasse pas cette information d’une précédente inscription.

[MISE À JOUR]: Au final, j’ai dû écrire ma propre routine d’enregistrement en raison de plusieurs faiblesses dans l’APIS disponible:

  • RegisterTypeLib et RegisterTypeLibForUser n’écrivent pas les entrées de registre AsynchronousInterface, SynchronousInterface et NumMethods. En effet, la bibliothèque de types compilée ne contient aucune information qui lie explicitement les interfaces synchrones et asynchrones. Ma propre routine d’enregistrement correspond aux interfaces par nom – elle trouve que les interfaces IXxx avec les interfaces AsyncIXxx correspondantes (par nom uniquement, pas de comparaison de méthode) et définit ces entrées de registre comme il convient.
  • RegisterTypeLib et RegisterTypeLibForUser écrivent toujours des clés de Registre 32 bits et 64 bits, y compris, mais sans s’y limiter, ProxyStubClsid32. Cela signifie que l’enregistrement d’une bibliothèque de types par ce moyen écrasera tout ProxyStubClsid32 pour l’architecture opposée précédemment écrite par d’autres moyens. Pour résoudre ce problème, il suffit d’enregistrer les deux bibliothèques de types (32 et 64), puis d’enregistrer les fichiers proxy / stub. Toutefois:
  • Le code proxy / stub généré par le compilateur MIDL ne semble pas fournir de moyen pour enregistrer les p / s dans le registre par utilisateur. Si l’enregistrement par utilisateur est obligatoire, la routine d’enregistrement générée est inutile.
  • Même si la routine d’enregistrement de proxy / stub générée peut être par utilisateur, si le proxy / stub est fusionné dans la DLL de serveur com, il n’ya qu’une seule possibilité d’enregistrement: le simple DllRegisterServer dans la seule DLL. Si cette routine écrit uniquement l’entrée ProxyStubClsid32 d’un côté du registre (32 ou 64 bits, pas les deux), l’enregistrement ultérieur de la DLL pour l’autre architecture modifiera ProxyStubClsid32 pour la première architecture.
  • Je n’ai pas testé certaines des apis comme CoRegisterPSClsid. Comme la documentation ne dit rien sur l’enregistrement par utilisateur, j’imagine qu’elle n’est pas prise en charge.