Посилання на файл DLL може відбуватися неявно під час компіляції або явно під час запуску. У будь-якому випадку DLL завантажується в простір пам'яті процесів, і всі експортовані точки входу доступні додатку.
Якщо явно використовується під час виконання, ви використовуєте LoadLibrary()
і GetProcAddress()
для ручного завантаження DLL і отримання покажчиків на функції, які вам потрібно викликати.
Якщо неявно пов’язані під час побудови програми, то заглушки для кожного експорту DLL, що використовується програмою, зв’язуються з програмою з бібліотеки імпорту, і ці заглушки оновлюються, коли EXE та DLL завантажуються під час запуску процесу. (Так, я тут трохи більше спростив ...)
Ці заглушки повинні надходити звідкись, а в ланцюжку інструментів Microsoft вони надходять із спеціальної форми файлу .LIB, яка називається бібліотекою імпорту . Необхідний .LIB зазвичай створюється одночасно з DLL і містить заглушку для кожної функції, експортованої з DLL.
Заплутано, але статична версія тієї ж бібліотеки також буде надіслана як файл .LIB. Немає тривіального способу їх відокремити, за винятком того, що LIB, які є бібліотеками імпорту для DLL, зазвичай будуть меншими (часто набагато меншими), ніж відповідні статичні LIB.
До речі, якщо ви використовуєте ланцюжок інструментів GCC, вам насправді не потрібні бібліотеки імпорту, щоб відповідати вашим бібліотекам DLL. Версія Gnu linker, перенесена на Windows, розуміє DLL-файли безпосередньо і може на льоту синтезувати більшість необхідних заглушок.
Оновлення
Якщо ви просто не можете встояти, знаючи, де насправді знаходяться всі гайки і болти, і що насправді відбувається, у MSDN завжди є що допомогти. Стаття Метта П'єтрека Поглиблений огляд портативного виконуваного файлу Win32 - це дуже повний огляд формату файлу EXE та способу його завантаження та запуску. Її навіть було оновлено, щоб охопити .NET і більше, оскільки вона спочатку з’явилася в журналі MSDN ca. 2002 рік.
Крім того, може бути корисно знати, як точно дізнатись, які бібліотеки DLL використовуються програмою. Інструментом для цього є Dependency Walker, він же залежний.exe. Його версія входить до складу Visual Studio, але остання версія доступна у її автора за адресою http://www.dependencywalker.com/ . Він може ідентифікувати всі бібліотеки DLL, які були вказані під час зв’язку (як раннє завантаження, так і затримка навантаження), а також може запустити програму та спостерігати за будь-якими додатковими бібліотеками DLL, які вона завантажує під час роботи.
Оновлення 2
Я переформулював деякі попередні тексти, щоб пояснити їх при повторному читанні та використати терміни мистецтва, що є неявними та явними посиланнями для узгодження з MSDN.
Отже, у нас є три способи, якими функції бібліотеки можуть бути доступними для використання програмою. Тоді очевидним подальшим запитанням є: "Як вибрати, який шлях?"
Статичне зв’язування - це те, як пов’язана основна частина програми. Всі ваші файли об’єктів перераховані та пов’язані разом у файл EXE. Попутно компонувальник піклується про дрібні клопоти, такі як виправлення посилань на глобальні символи, щоб ваші модулі могли викликати функції один одного. Бібліотеки також можуть бути статично пов’язані. Об'єктні файли, що складають бібліотеку, збираються бібліотекарем у файл .LIB, який компонувальник шукає модулі, що містять необхідні символи. Одним із ефектів статичного зв’язування є те, що до нього прив’язані лише ті модулі з бібліотеки, які використовуються програмою; інші модулі ігноруються. Наприклад, традиційна математична бібліотека C включає багато функцій тригонометрії. Але якщо ви посилаєтеся проти нього і використовуєтеcos()
, ви не отримаєте копію коду для sin()
або tan()
якщо ви також не викликали ці функції. Для великих бібліотек з багатим набором функцій це вибіркове включення модулів є важливим. На багатьох платформах, таких як вбудовані системи, загальний розмір коду, доступного для використання в бібліотеці, може бути великим порівняно з простором, доступним для зберігання виконуваного файлу в пристрої. Без вибіркового включення було б важче керувати деталями побудови програм для цих платформ.
Однак наявність копії тієї самої бібліотеки в кожній запущеній програмі створює тягар для системи, яка зазвичай запускає багато процесів. За правильного типу системи віртуальної пам'яті сторінки пам’яті, що мають однаковий вміст, повинні існувати лише один раз у системі, але можуть використовуватися багатьма процесами. Це створює перевагу для збільшення шансів на те, що сторінки, що містять код, можуть бути ідентичними деякій сторінці в якомога більшій кількості запущених процесів. Але якщо програми статично посилаються на бібліотеку середовища виконання, то кожна з них має різне поєднання функцій, кожна з яких викладена в картці пам'яті в різних місцях, і не так багато спільних сторінок коду, якщо це не програма, яка сама по собі є запустити більше, ніж процес. Тож ідея DLL отримала ще одну, головну, перевагу.
Бібліотека DLL для бібліотеки містить усі її функції, готові до використання будь-якою клієнтською програмою. Якщо багато програм завантажують цю DLL, усі вони можуть спільно використовувати її кодові сторінки. Усі виграють. (Ну, поки ви не оновите DLL новою версією, але це не є частиною цієї історії. Пекло Google DLL для тієї сторони казки.)
Отже, перший великий вибір, який потрібно зробити при плануванні нового проекту, - це між динамічним та статичним зв’язком. За допомогою статичного зв’язку у вас менше файлів для встановлення, і ви не застраховані від стороннього оновлення використовуваної вами DLL. Однак ваша програма є більшою, і вона не є настільки хорошим громадянином екосистеми Windows. За допомогою динамічного зв’язування вам потрібно встановити більше файлів, можливо, у вас виникнуть проблеми із оновленням використовуваної вами DLL третьою стороною, але, як правило, ви ставитесь до інших процесів у системі.
Великою перевагою DLL є те, що її можна завантажувати та використовувати без перекомпіляції та навіть перевстановлення основної програми. Це може дозволити сторонньому постачальнику бібліотек (наприклад, Microsoft і середовище виконання C) виправити помилку у своїй бібліотеці та розповсюдити її. Після того, як кінцевий користувач встановить оновлену бібліотеку DLL, вони негайно отримують переваги виправлення помилки у всіх програмах, що використовують цю бібліотеку DLL. (Якщо це не зламає речі. Див. DLL Hell.)
Інша перевага полягає в різниці між неявним та явним завантаженням. Якщо ви докладете максимум зусиль для явного завантаження, то DLL, можливо, навіть не існувало, коли програма була написана та опублікована. Це дозволяє використовувати механізми розширення, які можуть виявляти та завантажувати плагіни, наприклад.
lib /list xxx.lib
іlink /dump /linkermember xxx.lib
. Див. Це запитання щодо переповнення стека .