Je comprends python.h code> dans mon Visual C ++ projet de fichier DLL qui provoque une liaison implicite avec
python25.dll code>. Cependant, je souhaite charger un
python25.dll spécifique> (plusieurs peut être présent sur l'ordinateur), donc j'ai créé un fichier manifeste très simple nommé test.manifest em>:
Configuration Properties -> Manifest Tool -> Input and Output -> Additional Manifest Files
-->$(ProjectDir)\src\test.manifest
4 Réponses :
Walker de dépendance est généralement le meilleur outil de résolution de ce type de problème. Je ne suis pas trop sûr à quel point il se manifeste bien que ... p>
où dans ce désordre enchevêtré est le fichier exécutable de processus réel? p>
Deux possibilités viennent à l'esprit: p>
Vous écrivez un fichier DLL d'extension Python. Donc, le processus Python charge votre fichier DLL et il serait déjà em> avoir sa propre dépendance python25.dll. P> li>
Le fichier EXE Chargement de votre fichier DLL est en cours de construction avec des fichiers d'en-tête et des bibliothèques fournies par le projet de fichier DLL. Donc, il hérit d'un commentaire Mon problème avec le deuxième scénario est, je m'attendrais à ce que le fichier EXE et à votre fichier DLL, d'être dans le même dossier dans le cas où le fichier EXE charge implicitement votre fichier DLL. Auquel cas le fichier EXE, votre fichier DLL et le python25.dll sont tous déjà dans le même dossier. Pourquoi alors la version System32 serait-elle jamais chargée? La commande de recherche pour les fichiers DLL implicitement chargés est toujours dans le dossier du fichier EXE de l'application. P>
Donc, la question intéressante réelle implicite dans votre requête est la suivante: comment est le système32 python26.dll étant chargé du tout? p> #pragma (lib, "python25.lib") code> à partir de votre fichier d'en-tête et loge ainsi le fichier DLL lui-même. P> LI>
ol>
Merci Chris, j'ai clarifié le scénario dans une réponse que j'ai posté. Maintenant, j'ai compris que la question est causée par la dll Boost.python ...
D'une manière ou d'une autre, le contexte d'activation de votre DLL n'est pas utilisé par le Boost - faites-vous une charge statique ou dynamique, de Boost?, Et de la DLL Python? La DLL de Boost aura-t-elle son propre manifeste qui pourrait réinitialiser le courant alternatif et / ou en quelque sorte référencer explicitement la DLL Python dans System32?
J'ai fait des progrès pour la compréhension de la question. P>
Permettez-moi de clarifier le scénario: P>
python25.dll code> dans le même dossier que mon fichier DLL, ainsi qu'un boost_python-vc90-mt-1_39.dll code>. li>
- Puis j'ai un fichier exe qui est une démonstration pour montrer comment créer un lien vers mon fichier DLL: ce fichier EXE ne doit pas nécessairement être dans le même dossier que mon fichier DLL, tant que le fichier DLL peut être trouvé. Sur le chemin (je suppose que l'utilisateur final peut ne pas le mettre dans le même dossier). LI>
ul>
Ensuite, lors de l'exécution du fichier EXE, le répertoire actuel n'est pas celui contenant python25.dll code>, et c'est pourquoi la commande de recherche est utilisée et un autre python25.dll code > peut être trouvé avant le mien. p>
Maintenant, j'ai compris que la technique Manifeste était la bonne approche: j'ai réussi à rediriger le chargement à "mon" python25.dll code>. p>.
Le problème est que c'est le boost fichier dll < Code> boost_python-vc90-mt-1_39.dll code> c'est responsable du chargement "double"! strong> p>
Si je ne charge pas celui-ci, alors python25.dll code> est correctement redirigé. Maintenant, je dois trouver en quelque sorte comment dire au fichier DLL de Boost de ne pas charger un autre python25.dll code> ... p>
J'ai réussi à recompiler Boost.python Libs avec l'option "Embed-Manifest = Off". Miracle! "python25.dll" pas plus chargé deux fois. Mais maintenant, chaque fois que j'importe une extension PYD de mon code C ++, elle est chargée deux fois à nouveau ... problème sans fin ...
Essayez de faire le même hanjakcing Manifest pour BOOST_PYTHON-VC90-MT-1_39.DLL CODE> - tel que en mettant un fichier manifeste à côté, ou changeez-le à l'aide de
MT code>. C'est mon impression. Je n'ai pas essayé cela, je me débats aussi avec Winsxs i>.
Après une bataille exhaustive avec winsxs et redirection DLL , voici mon conseil pour vous: p>
Diverses choses peuvent faire charger un fichier DLL sous Windows: P>
LoadLibrary code>) - Le chargeur utilise le contexte d'activation actuel du fichier EXE exécutant. C'est intuitif. Li>
- liaison implicite ("linge de charge", les "auto") - Le chargeur utilise le contexte d'activation par défaut em> du fichier
en fonction de dll fort>. Si a.exe code> dépend de b.dll code> dépend de c.dll code> (toutes les liaisons implicites), le chargeur utilisera b. DLL CODE> Contexte d'activation de la DLL lors du chargement c.dll code>. IIRC, cela signifie que si B 'code> dllmain code> charges c.dll code>, il peut utiliser b.dll code> Context d'activation - la plupart du temps Cela signifie le contexte d'activation par défaut à l'échelle du système. Donc, vous obtenez votre dll python de % systemroot% code>. Li>
- com (
coCreateInstance code>) - C'est le méchant. Extrêmement subtile. Il s'avère que le chargeur peut rechercher le chemin complet em> d'un fichier DLL à partir du registre à l'aide de COM (sous HKCR \ CLSID code>). LoadLibrary Code> ne fera aucune recherche si l'utilisateur lui confère un chemin complet, le contexte d'activation ne peut donc affecter la résolution du fichier DLL. Ceux-ci peuvent être redirigés avec l'élément COMCLASS code> et amis, voir [Référence] [MSDN_AXEMBLY_RF]. LI>
- Même si vous avez le manifeste correct, quelqu'un peut parfois changer le contexte d'activation au moment de l'exécution à l'aide du Contexte d'activation API . Si tel est le cas, il n'ya généralement pas grand chose que vous pouvez faire à ce sujet (voir la solution ultime ci-dessous); Ceci est juste ici pour la complétude. Si vous voulez savoir qui est en train de gâcher avec le contexte d'activation, WINDBG
BP Kernel32! ActivateAccTX code>. Li>
ul>
maintenant sur la recherche du coupable h3>
- Le moyen le plus simple de savoir ce qui provoque un fichier DLL de charger consiste à utiliser moniteur de processus . Vous pouvez surveiller " chemin em> contenant
python25.dll code>" ou "em> détail em> contenant python25.dll code>" (pour com Recherches). Double-cliquant sur une entrée vous montrera une trace de pile (vous devez d'abord définir les chemins de recherche de symboles, puis définir le serveur PDB de Microsoft). Cela devrait suffire à la plupart de vos besoins. LI>
- Parfois, la trace de pile obtenue d'en haut pourrait être engendrée d'un nouveau fil. Pour cette fin, vous avez besoin Windbg . Cela peut être un autre sujet, mais il suffit de dire que vous pouvez
SXE LD Python25 Code> et regardez quels autres threads font (! Findstack MyExemodulename code> ou ~ * k code>) qui provoque la charge d'un fichier DLL. li>
ol>
Solution du monde réel h3>
Au lieu de violer cette chose Winsxs, essayez d'accrocher Loadlibraryw code> à l'aide de Mhook ou easyHook . Vous pouvez simplement remplacer totalement cet appel avec votre logique personnalisée. Vous pouvez terminer cela avant le déjeuner et trouver le sens de la vie à nouveau. P>
[msdn_assembly_ref]: Manifestes d'assemblage em> p>
Récemment, j'ai frappé un Problème similaire A >: p>
Pourquoi le python32.dll a-t-il été chargé deux fois? Comme je l'ai expliqué dans Mon message sur Python-Capi , cela a été causé par le fait que l'application chargait Python32.dll de Winsxs, mais L'assemblage Python.Manifest + Python32.dll a été reconnu par la machine de chargement DLL comme module différent (sous Différents contextes d'activation), que le python32.dll demandé par _TKinter.pyd. P>
Retrait de la référence à Python.Manifest de l'application Incorporer Python et permettant au chemin de recherche DLL de rechercher les DLL résolvés le problème. P>
importer tkinter code> à l'intérieur de l'interprète python incorporé a provoqué une seconde charge de la même charge
_pythreadstate_current == null code>). Évidemment,
py_initialize () code> n'a jamais été appelé pour le deuxième interprète Python chargé de la duplicate python32.dll. Li>
ol>
Comment le chargement implicite est-il fait? Y a-t-il un commentaire
#pragma (lib xxx) code> dans les en-têtes Python?
Oui, le lien est fait grâce à #pragma Commentaire.
Juste hors de curiosité, que se passe-t-il si vous supprimez le python25.dll à SYSWOW64?
Merci pour l'idée de test, le résultat est assez intéressant! Maintenant, ma DLL "bonne", celle pointée par le manifeste, est elle-même chargée deux fois !!!
Eh bien, c'est assez étrange. Ont-ils des adresses de charge différentes?
Si vous voulez dire la colonne "Adresse de base" dans Process Explorer, YEP: premier -> 0xf10000 Deuxième -> 0x1e000000
Votre application et les images Python25.dll sont 32 bits, non? Vous pouvez voir avec la colonne "Type d'image". Peut-être que c'est une sorte de bizarrerie sur wow64.