7
votes

DLL C ++ non gérés avec le même nom coexistant dans le même processus

Utilisation de Visual Studio C ++ V10, j'essaie de déterminer comment construire une DLL et résoudre un conflit de dénomination DLL. Voici les détails.

La société S expédition un produit appelé m.exe . Supposons que m.exe est installé dans \ s \ bin \ m.exe . Société s statiquement liens vers une DLL appelée u.dll , qui est installé dans \ s \ bin \ u.dll . u.dll contient du code open source et est construit avec des options de compilateur Visual C ++ / ZC: WCHAR_T - , qui ne reconnaît pas WCHAR en tant que type natif.

Société C expédiée une DLL appelée o.dll et publie l'API pour cette DLL et expédie une bibliothèque d'importation pour o.dll . Supposons que o.dll est installé dans \ c \ bin \ o.dll . o.dll liens statiquement vers une DLL appelée u.dll , qui est installé dans \ c \ bin \ u.dll . u.dll est construit sur le même code open source, mais est construit avec des options de compilateur Visual C ++ / ZC: WCHAR_T , qui reconnaît wchar_t En tant que type natif.

Idéally Société C et Société S accepterait de construire u.dll à l'aide des mêmes options Visual C ++, mais cela n'est pas possible. < p> m.exe de la société S est extensible, en ce que je peux construire ma propre dll dans non géré C ++, appelez-le nœud.dll que m.exe < / Code> invoquera si je fixais tout correctement. Je voudrais construire nœud.dll de sorte qu'il lie statilement vers o.dll de la société C. mais le problème est qu'une fois m.exe est en cours d'exécution, il a chargé la bibliothèque u.dll à partir de \ s \ bin et les symboles de \ s \ bin \ u.dll sont légèrement différents que ceux de \ c \ bin \ u.dll , car comment u.dll a été construit par chaque entreprise. Donc, lorsque m.exe tente de charger nœud.dll , il échoue, car quand node.dll charges o.dll , qui nécessite u.dll , les symboles nécessaires à partir de \ c \ bin \ u.dll ne sont pas là, car Windows voit u.dll Comme déjà en cours de chargement.

Un diagramme de la situation est le suivant: xxx

efficacement, j'ai besoin des deux \ s \ bin \ U.dll et \ c \ bin \ u.dll pour coexister dans le même espace de processus et que m.exe utilise sa version de u.dll et o.dll utilise sa version de u.dll .

Notez que je n'ai pas le Option pour reconstruire m.exe ou o.dll pour modifier la manière dont ils chargent u.dll . Ils viennent de tiers. La liaison statique ne peut donc pas être modifiée. Je n'ai pas non plus la possibilité d'utiliser loadlibrary sur o.dll , car il s'agit d'une bibliothèque C ++, fournie avec une bibliothèque d'importation.

Je crois que les manifestes peuvent être utilisés de sorte que lorsque je construit nœud.dll est lié statilement à o.dll, j'ai défini les choses dans le manifeste du noeud .Dll de sorte que o.dll charge sa propre copie de u.dll installé dans \ c \ bin \ u.dll . Je ne peux tout simplement pas comprendre comment faire cela. Idéalement, je voudrais ne pas modifier le manifeste de o.dll , mais si c'est la seule solution, je vais vivre avec ça.


2 commentaires

DLL, dll de partout! (Désolé, je ne pouvais pas m'en empêcher) Bonjour et bienvenue.


Essentiellement, le problème est que o.dll dans son IAT spécifie qu'il s'agit de liens contre u.dll , non qualifié.


4 Réponses :


4
votes

Vous pouvez avoir plusieurs dlls avec le même nom de fichier dans le même processus en chargeant un ou plusieurs d'entre eux avec des chemins absolus. Cela nécessite que la DLL soit chargée de manière dynamique, mais le comportement est autrement identique.

Au lieu de la liaison pendant le processus de construction, vous devez std :: string modulename = AppPath + "\ s \ bin \ u.dll"; LOADMODULE (MODULENAME.C_STR ()) . Parce que cela est sans ambiguïté sur lequel la DLL doit être chargée, elle vous permet de charger plusieurs personnes avec le "même" nom.

Une fois que vous avez chargé le module, vous pouvez affecter chacune des fonctions nécessaires aux pointeurs de fonction, puis enveloppez-les ou utilisez le légal mais peu utilisé Syntaxe des fonctions d'appel Pointeurs comme fonctions normales ( FuncPtr (paramètres) ).

Si vous êtes sur une version plus récente de Windows, vous pourrez peut-être utiliser des manifests DLL pour renforcer la version / la nommée autour du module et faire charger l'EXE de charger une DLL différente de celle qu'il ne le ferait généralement. Je ne connais pas exactement comment cela serait fait, bien qu'il soit documenté sur MSDN (et probablement ici aussi).


3 commentaires

Ce n'est pas une option, car je n'ai pas la capacité de reconstruire m.exe ou o.dll. Ils viennent de tiers différents.


Si l'un de ces modules utilise un chemin partiel ou absolu ou que l'on utilise un chargement dynamique, vous pourrez peut-être obtenir. Sinon, les manifestés seront votre seule chance.


Je crois que les manifestations sont le seul choix. J'aimerais savoir quoi mettre dans le manifeste pour faire fonctionner les choses. M.EXE et O.DLL sont construits à l'aide de bibliothèques importées qui chargent ensuite U.dll à l'aide des règles de chargement normales de la DLL. Chaque entreprise met sa propre version de U.DLL dans son propre répertoire bin. Lorsque M.EXE est exécuté, il récupère sa copie de U.dll. Lorsque vous écrivez un exe standard qui utilise o.dll, il récupère sa copie de u.dll.



0
votes

Essayez d'utiliser LoadLibrary et GetProcAddress. Cela nécessitera une restructuration de votre code pour utiliser des pointeurs de fonction partout. Voir:

page Web MSDN pour LoadLibrary


1 commentaires

Ce n'est pas une option, car je n'ai pas la capacité de reconstruire m.exe ou o.dll. Ils viennent de tiers différents.



1
votes

Vous pouvez résoudre la DLL source programmatique à Runtiome à l'aide de l'option / DelayLoad Linker Option (Linker / Entrée / Délais DLLS chargés dans les propriétés du projet VS) avec un crochet personnalisé. Dans l'un de vos fichiers source, vous devez définir et enregistrer une fonction de crochet de retard de connexion. Dans le gestionnaire de notification DLINoteProLoadlibrary DLINOTEPRELODLibrary de la fonction de crochet, appelez simplement LoadLibrary avec un chemin explicite de la DLL souhaitée, puis transmettez le HMODULE de DLL au code de diffusion. Le code de retard de retard résoudra les fonctions importées à la DLL que vous le donnez, que, si une autre DLL du même nom est déjà chargée dans le processus.

Off le sommet de ma tête, votre crochet ressemblera à ceci (où myCustMoadLibrary doit être remplacé par code qui appelle Chargement de chargement avec le chemin complet de la DLL souhaitée dans le cas contradictoire, ou juste le nom de fichier non qualifié autrement): P>

#include <delayimp.h>
FARPROC WINAPI MyDliNotifyHook( unsigned dliNotify, PDelayLoadInfo pdli )
{
  if( dliNotify == dliNotePreLoadLibrary )
    return (FARPROC)MyCustomLoadLibrary( pdli->szDll );
  return NULL;
}
extern "C" PfnDliHook __pfnDliNotifyHook2 = MyDliNotifyHook;


7 commentaires

Cela fonctionne uniquement si nœud.dll est celui qui se trouve à la DLL conflictuelle. Après avoir réaffecté votre question, je vois que vous dites que c'est l'une des DLL à charge qui relie la DLL contradictoire. Dans ce cas, vous devrez résoudre le tableau d'adresses d'importation de la DLL dépendante de manière programmatique. Ce n'est pas difficile à faire, mais il est trop complexe pour décrire les étapes ici.


"Résoudre le tableau d'adresses d'importation de la DLL dépendante Programmatiquement": pouvez-vous donner un pointeur, nous pouvons en savoir plus?


Il y a deux cas: le cas où le chargeur peut résoudre avec succès toutes les importations (bien qu'à la mauvaise DLL); et le cas où le chargeur ne peut pas résoudre les importations. Si votre cas est le premier, je peux fournir des indications. Si votre cas est ce dernier, vous devez reproduire essentiellement le code Windows Loader (résoudre les importations et appliquer des fixes, puis appeler la fonction du point d'entrée). Il y a une petite documentation précieuse et je ne connais aucune source d'information publique. Ce n'est pas pour les faibles de cœur, mais c'est possible: je l'ai fait avec succès.


"Si votre cas est le premier, je peux fournir des indications". Oui, s'il vous plaît monsieur.


Harper, je viens de réaliser que vous n'êtes pas le PO. Puisque cela est hors-thème pour l'OP, veuillez commencer votre propre question.


@ Owen-Wengerd - Mon cas est ce dernier. Le chargeur ne peut pas résoudre toutes les importations. Certains sont les mêmes, et certains sont différents. Idéalement, parce que M.Exe et o.dll sont construits par différents tiers et que je souhaite obtenir un soutien de chacun des tiers, je veux vraiment que M.EXe utilise la mise en œuvre de U.dll qu'elle fournit et avoir O.dll pour utiliser la mise en œuvre de U.dll qu'elle fournit. Comme je l'ai dit dans le poste d'origine, je pense que cela peut être fait avec des manifestes. Je ne peux tout simplement pas comprendre la manifeste.


@Irv J'ai très peu d'expérience en utilisant des manifestes car mon travail nécessite généralement une prise en charge des anciennes versions de Windows. Cela pourrait fonctionner et en théorie devrait fonctionner, mais j'ai bien peur de ne pouvoir offrir aucune aide concrète avec des manifestations.



0
votes

Vous avez de la chance que u.dll est open source. Vous devrez créer une version prenant en charge le / zc: wchar_t - et / zc: wchar_t fonctions. La première option définit simplement wchar_t - comme non signé court . Vous obtiendrez une tonne d'avertissements de liaison pour les symboles en double, pour chaque fonction qui ne dispose pas d'un argument wchar_t , mais sinon vous venez de vous retrouver avec une dll plus nombreuse.

Mind You, s'il existe des variables globales ou statiques à l'aide de wchar_t , vous aurez également deux copies de ceux-ci. Mais vous auriez le même effet que si vous chaisez deux copies de u.dll dans un processus.


0 commentaires