Je sais que cela peut sembler assez basique aux geeks. Mais je veux que ce soit clair comme du cristal.
Lorsque je veux utiliser une DLL Win32, j'appelle généralement les API comme LoadLibrary () et GetProcAdderss (). Mais récemment, je développe avec DirectX9, et je dois ajouter des fichiers d3d9.lib , d3dx9.lib , etc.
J'ai assez entendu dire que LIB est pour la liaison statique et la DLL est pour la liaison dynamique.
Donc, ma compréhension actuelle est que LIB contient la mise en œuvre des méthodes et est lié statiquement au moment de la liaison dans le cadre du fichier EXE final. Alors que DLL est chargé dynamiquement au moment de l'exécution et ne fait pas partie du fichier EXE final.
Mais parfois, certains fichiers LIB sont fournis avec les fichiers DLL, donc:
- À quoi servent ces fichiers LIB?
- Comment réalisent-ils ce à quoi ils sont destinés?
- Existe-t-il des outils qui me permettent d'inspecter les composants internes de ces fichiers LIB?
Mise à jour 1
Après avoir vérifié wikipedia, je me souviens que ces fichiers LIB sont appelés bibliothèque d'importation . Mais je me demande comment cela fonctionne avec mon application principale et les DLL à charger dynamiquement.
Mise à jour 2
Tout comme RBerteig l'a dit, il y a du code stub dans les fichiers LIB nés avec les DLL. Donc, la séquence d'appel devrait être comme ceci:
Mon application principale -> stub dans la LIB -> véritable DLL cible
Alors, quelles informations devraient contenir ces LIB? Je pourrais penser à ce qui suit:
- Le fichier LIB doit contenir le chemin complet de la DLL correspondante; Ainsi, la DLL pourrait être chargée par le runtime.
- L'adresse relative (ou le décalage de fichier?) Du point d'entrée de chaque méthode d'exportation DLL doit être codée dans le stub; Ainsi, des sauts / appels de méthode corrects peuvent être effectués.
Ai-je raison sur ce point? Y a-t-il autre chose?
BTW: Existe-t-il un outil qui peut inspecter une bibliothèque d'importation? Si je peux le voir, il n'y aura plus de doutes.
la source
lib /list xxx.lib
etlink /dump /linkermember xxx.lib
. Consultez cette question sur le débordement de pile .dumpbin -headers xxx.lib
fournit des informations plus détaillées, par rapport aulib
et leslink
services publics.Réponses:
La liaison à un fichier DLL peut se produire implicitement au
moment de laliaison decompilation, ou explicitement au moment de l'exécution. Dans tous les cas, la DLL finit par être chargée dans l'espace mémoire des processus et tous ses points d'entrée exportés sont disponibles pour l'application.S'il est utilisé explicitement au moment de l'exécution, vous utilisez
LoadLibrary()
etGetProcAddress()
pour charger manuellement la DLL et obtenir des pointeurs vers les fonctions que vous devez appeler.S'ils sont liés implicitement lors de la génération du programme, les stubs pour chaque exportation DLL utilisée par le programme sont liés au programme à partir d'une bibliothèque d'importation, et ces stubs sont mis à jour lorsque l'EXE et la DLL sont chargés au lancement du processus. (Oui, j'ai simplifié plus d'un peu ici ...)
Ces stubs doivent provenir de quelque part, et dans la chaîne d'outils Microsoft, ils proviennent d'une forme spéciale de fichier .LIB appelée bibliothèque d'importation . Le .LIB requis est généralement généré en même temps que la DLL et contient un stub pour chaque fonction exportée à partir de la DLL.
De façon confuse, une version statique de la même bibliothèque serait également livrée sous forme de fichier .LIB. Il n'y a pas de moyen simple de les distinguer, sauf que les LIB qui sont des bibliothèques d'importation pour les DLL seront généralement plus petites (souvent beaucoup plus petites) que la LIB statique correspondante.
Si vous utilisez la chaîne d'outils GCC, par ailleurs, vous n'avez pas besoin de bibliothèques d'importation pour correspondre à vos DLL. La version de l'éditeur de liens Gnu portée sur Windows comprend directement les DLL et peut synthétiser la plupart des stubs requis à la volée.
Mise à jour
Si vous ne pouvez pas résister à savoir où se trouvent réellement tous les écrous et boulons et ce qui se passe réellement, il y a toujours quelque chose chez MSDN pour vous aider. L'article de Matt Pietrek Un examen approfondi du format de fichier exécutable portable Win32 est un aperçu très complet du format du fichier EXE et de la façon dont il est chargé et exécuté. Il a même été mis à jour pour couvrir .NET et plus depuis son apparition dans MSDN Magazine ca. 2002.
En outre, il peut être utile de savoir comment savoir exactement quelles DLL sont utilisées par un programme. L'outil pour cela est Dependency Walker, aka depend.exe. Une version de celui-ci est incluse avec Visual Studio, mais la dernière version est disponible auprès de son auteur à l' adresse http://www.dependencywalker.com/ . Il peut identifier toutes les DLL qui ont été spécifiées au moment de la liaison (chargement anticipé et chargement différé) et il peut également exécuter le programme et surveiller les DLL supplémentaires qu'il charge au moment de l'exécution.
Mise à jour 2
J'ai reformulé une partie du texte précédent pour le clarifier lors de la relecture, et pour utiliser les termes de l'art des liens implicites et explicites pour la cohérence avec MSDN.
Ainsi, nous avons trois façons de rendre les fonctions de bibliothèque disponibles pour être utilisées par un programme. La question de suivi évidente est alors: "Comment choisir quelle voie?"
La liaison statique est la façon dont la majeure partie du programme lui-même est liée. Tous vos fichiers objets sont répertoriés et rassemblés dans le fichier EXE par l'éditeur de liens. En cours de route, l'éditeur de liens s'occupe de tâches mineures comme la correction des références aux symboles globaux afin que vos modules puissent appeler les fonctions de l'autre. Les bibliothèques peuvent également être liées statiquement. Les fichiers objets qui composent la bibliothèque sont rassemblés par un bibliothécaire dans un fichier .LIB dans lequel l'éditeur de liens recherche les modules contenant les symboles nécessaires. L'un des effets de la liaison statique est que seuls les modules de la bibliothèque utilisés par le programme y sont liés; les autres modules sont ignorés. Par exemple, la bibliothèque mathématique C traditionnelle comprend de nombreuses fonctions de trigonométrie. Mais si vous liez contre et utilisez
cos()
, vous ne vous retrouvez pas avec une copie du code poursin()
ou àtan()
moins que vous n'ayez également appelé ces fonctions. Pour les grandes bibliothèques avec un ensemble riche de fonctionnalités, cette inclusion sélective de modules est importante. Sur de nombreuses plates-formes telles que les systèmes embarqués, la taille totale du code disponible pour une utilisation dans la bibliothèque peut être importante par rapport à l'espace disponible pour stocker un exécutable dans l'appareil. Sans inclusion sélective, il serait plus difficile de gérer les détails des programmes de construction pour ces plates-formes.Cependant, avoir une copie de la même bibliothèque dans chaque programme en cours d'exécution crée un fardeau pour un système qui exécute normalement de nombreux processus. Avec le bon type de système de mémoire virtuelle, les pages de mémoire qui ont un contenu identique ne doivent exister qu'une seule fois dans le système, mais peuvent être utilisées par de nombreux processus. Cela crée un avantage pour augmenter les chances que les pages contenant du code soient probablement identiques à certaines pages dans autant d'autres processus en cours que possible. Mais, si les programmes se lient statiquement à la bibliothèque d'exécution, chacun a un mélange différent de fonctions, chacune disposée dans ce qui traite la carte mémoire à différents endroits, et il n'y a pas beaucoup de pages de code partageables à moins que ce ne soit un programme qui est à lui seul courir dans plus que processus. L'idée d'une DLL a donc gagné un autre avantage majeur.
Une DLL pour une bibliothèque contient toutes ses fonctions, prêtes à être utilisées par n'importe quel programme client. Si de nombreux programmes chargent cette DLL, ils peuvent tous partager ses pages de codes. Tout le monde y gagne. (Eh bien, jusqu'à ce que vous mettiez à jour une DLL avec une nouvelle version, mais cela ne fait pas partie de cette histoire. Google DLL Hell pour ce côté de l'histoire.)
Donc, le premier grand choix à faire lors de la planification d'un nouveau projet est entre la liaison dynamique et statique. Avec la liaison statique, vous avez moins de fichiers à installer et vous êtes à l'abri des tiers mettant à jour une DLL que vous utilisez. Cependant, votre programme est plus volumineux et il n'est pas aussi bon citoyen de l'écosystème Windows. Avec la liaison dynamique, vous avez plus de fichiers à installer, vous pourriez avoir des problèmes avec un tiers mettant à jour une DLL que vous utilisez, mais vous êtes généralement plus convivial avec les autres processus du système.
Un gros avantage d'une DLL est qu'elle peut être chargée et utilisée sans recompiler ni même relier le programme principal. Cela peut permettre à un fournisseur de bibliothèque tiers (pensez à Microsoft et à l'environnement d'exécution C, par exemple) de corriger un bogue dans sa bibliothèque et de le distribuer. Une fois qu'un utilisateur final a installé la DLL mise à jour, il bénéficie immédiatement de cette correction de bogue dans tous les programmes qui utilisent cette DLL. (À moins qu'il ne casse les choses. Voir DLL Hell.)
L'autre avantage vient de la distinction entre chargement implicite et explicite. Si vous optez pour l'effort supplémentaire de chargement explicite, la DLL peut même ne pas avoir existé lorsque le programme a été écrit et publié. Cela permet des mécanismes d'extension qui peuvent découvrir et charger des plugins, par exemple.
la source
Ces fichiers de bibliothèque d'importation .LIB sont utilisés dans la propriété de projet suivante
Linker->Input->Additional Dependencies
, lors de la création d'un ensemble de dll nécessitant des informations supplémentaires au moment de la liaison, fournies par les fichiers .LIB de la bibliothèque d'importation. Dans l'exemple ci-dessous pour ne pas obtenir d'erreurs de l'éditeur de liens, je dois faire référence aux dll A, B, C et D via leurs fichiers lib. (notez que l'éditeur de liens pour trouver ces fichiers, vous devrez peut-être inclure leur chemin de déploiement dans le casLinker->General->Additional Library Directories
contraire, vous obtiendrez une erreur de construction indiquant que vous ne pourrez trouver aucun des fichiers lib fournis.)Si votre solution construit toutes les bibliothèques dynamiques, vous avez peut-être pu éviter cette spécification de dépendance explicite en vous appuyant à la place sur les indicateurs de référence exposés sous la
Common Properties->Framework and References
boîte de dialogue. Ces indicateurs semblent faire automatiquement la liaison en votre nom en utilisant les fichiers * .lib.Cependant, il s'agit comme il le dit de propriétés communes , qui ne sont pas spécifiques à la configuration ou à la plate-forme. Si vous avez besoin de prendre en charge un scénario de construction mixte comme dans notre application, nous avions une configuration de construction pour restituer une construction statique et une configuration spéciale qui a construit une construction contrainte d'un sous-ensemble d'assemblys qui ont été déployés en tant que bibliothèques dynamiques. J'avais utilisé les indicateurs
Use Library Dependency Inputs
etLink Library Dependencies
définis sur true dans divers cas pour obtenir des éléments à construire et plus tard réaliser pour simplifier les choses, mais lors de l'introduction de mon code dans les versions statiques, j'ai introduit une tonne d'avertissements de l'éditeur de liens et la construction était incroyablement lente pour les versions statiques. J'ai fini par introduire un tas de ce genre d'avertissements ...warning LNK4006: "bool __cdecl XXX::YYY() already defined in CoreLibrary.lib(JSource.obj); second definition ignored D.lib(JSource.obj)
Et j'ai fini par utiliser la spécification manuelle de
Additional Dependencies
pour satisfaire l'éditeur de liens pour les constructions dynamiques tout en gardant les constructeurs statiques heureux en n'utilisant pas une propriété commune qui les ralentissait. Lorsque je déploie la version de sous-ensemble dynamique, je ne déploie que les fichiers dll car ces fichiers lib ne sont utilisés qu'au moment de la liaison, pas au moment de l'exécution.la source
Il existe trois types de bibliothèques: les bibliothèques statiques, partagées et chargées dynamiquement.
Les bibliothèques statiques sont liées au code lors de la phase de liaison, elles sont donc en fait dans l'exécutable, contrairement à la bibliothèque partagée, qui n'a que des stubs (symboles) à rechercher dans le fichier de bibliothèque partagée, qui est chargé au moment de l'exécution avant le la fonction principale est appelée.
Les bibliothèques chargées dynamiquement ressemblent beaucoup aux bibliothèques partagées, sauf qu'elles sont chargées quand et si le besoin se fait sentir par le code que vous avez écrit.
la source
LoadLibrary()
et les API associées.Voici quelques rubriques MSDN connexes pour répondre à ma question:
Lier un exécutable à une DLL
Lier implicitement
Déterminer la méthode de liaison à utiliser
Création d'une bibliothèque d'importation et d'un fichier d'exportation
la source