Ответ 1
Связывание с DLL файлом может происходить неявно на время ссылки compile или явно во время выполнения. В любом случае, DLL загружается в пространство памяти процессов, а все экспортированные точки входа доступны для приложения.
Если он используется явно во время выполнения, вы используете LoadLibrary()
и GetProcAddress()
для ручной загрузки DLL и получения указателей на функции, которые вам нужно вызвать.
Если он связан неявно при создании программы, то заглушки для каждого экспорта DLL, используемые программой, связаны с программой из библиотеки импорта, и эти заглушки обновляются, когда EXE и DLL загружаются при запуске процесса, (Да, я упростил больше, чем немного здесь...)
Эти заглушки должны появиться откуда-то, а в цепочке инструментов Microsoft они поступают из специальной формы .LIB файла, называемой библиотекой импорта. Требуемый .LIB обычно создается одновременно с DLL и содержит заглушку для каждой функции, экспортированной из DLL.
Смутно, статическая версия той же библиотеки также будет отправлена как .LIB файл. Нет никакого тривиального способа рассказать им обособленно, за исключением того, что LIB, которые являются библиотеками импорта для DLL, обычно будут меньше (часто намного меньше), чем соответствующий статический LIB.
Если вы используете инструментальную цепочку GCC, кстати, вам не нужны библиотеки импорта в соответствии с вашими DLL. Версия компоновщика Gnu, портированного в Windows, напрямую понимает библиотеки DLL и может синтезировать большинство любых необходимых заглушек на лету.
Update
Если вы просто не можете удержаться, зная, где все гайки и болты действительно и что действительно происходит, в MSDN всегда есть что-то, что может помочь. Matt Pietrek article Глубокий взгляд на формат исполняемого файла Win32 Portable - это очень полный обзор формата EXE файл и как он загружается и запускается. Он даже был обновлен, чтобы охватить .NET и многое другое, поскольку он изначально появился в журнале MSDN ca. 2002.
Кроме того, может быть полезно узнать, как узнать, какие библиотеки DLL используются программой. Инструментом для этого является Dependency Walker, aka depend.exe. Версия его включена в Visual Studio, но последняя версия доступна от ее автора по адресу http://www.dependencywalker.com/. Он может идентифицировать все DLL, которые были указаны во время соединения (как ранняя загрузка, так и загрузка с задержкой), а также может запускать программу и следить за загрузкой любых дополнительных DLL файлов во время выполнения.
Обновление 2
Я изложил некоторые из более ранних текстов, чтобы уточнить его при повторном чтении, и использовать термины искусства неявные и явные ссылки для согласованности с MSDN.
Итак, у нас есть три способа, которыми библиотечные функции могут быть доступны для использования программой. Очевидный следующий вопрос заключается в следующем: "Как выбрать, каким образом?"
Статическая связь - это то, как связана основная часть самой программы. Все ваши объектные файлы перечислены и собраны вместе в файл EXE с помощью компоновщика. По пути, компоновщик заботится о небольших задачах, таких как исправление ссылок на глобальные символы, чтобы ваши модули могли вызывать функции друг друга. Библиотеки также могут быть статически связаны между собой. Объектные файлы, составляющие библиотеку, собираются вместе библиотекарем в файле .LIB, который компоновщик ищет модули, содержащие необходимые символы. Один из эффектов статического связывания заключается в том, что к нему привязаны только те модули из библиотеки, которые используются программой; другие модули игнорируются. Например, традиционная математическая библиотека C включает в себя множество функций тригонометрии. Но если вы ссылаетесь на него и используете cos()
, вы не получите копию кода для sin()
или tan()
, если вы также не вызвали эти функции. Для больших библиотек с богатым набором функций это выборочное включение модулей важно. На многих платформах, таких как встроенные системы, общий размер кода, доступного для использования в библиотеке, может быть большим по сравнению с пространством, доступным для хранения исполняемого файла в устройстве. Без выборочного включения было бы сложнее управлять деталями построения программ для этих платформ.
Однако наличие копии одной и той же библиотеки в каждой запущенной программе создает нагрузку на систему, которая обычно запускает много процессов. При правильном виде системы виртуальной памяти страницы памяти, имеющие идентичный контент, должны существовать только один раз в системе, но могут использоваться многими процессами. Это создает выгоду для увеличения шансов, что страницы, содержащие код, могут быть идентичны некоторым страницам как можно большего числа других запущенных процессов. Но если программы статически ссылаются на библиотеку времени выполнения, то каждый из них имеет различное сочетание функций, каждый из которых выложен на карте памяти процессов в разных местах, и не так много скопированных кодовых страниц, если это не программа, которая сама по себе является работать в более чем процесс. Таким образом, идея DLL получила другое, основное преимущество.
DLL для библиотеки содержит все ее функции, готовые для использования любой клиентской программой. Если многие программы загружают эту DLL, все они могут делиться своими кодовыми страницами. Все побеждают. (Ну, пока вы не обновите DLL с новой версией, но это не является частью этой истории. DLL Hell для этой стороны сказки.)
Итак, первый большой выбор, который нужно сделать при планировании нового проекта, - это динамическая и статическая привязка. Со статической связью у вас меньше файлов для установки, и вы невосприимчивы к третьим сторонам, обновляя используемую вами DLL. Тем не менее, ваша программа больше, и она не так хороша, как гражданин экосистемы Windows. С динамической связью у вас есть больше файлов для установки, возможно, у вас есть проблемы с сторонним обновлением используемой DLL, но вы, как правило, дружелюбны к другим процессам в системе.
Большое преимущество DLL заключается в том, что его можно загружать и использовать без перекомпиляции или даже перезапуска основной программы. Это может позволить стороннему поставщику библиотеки (например, Microsoft и C runtime, например) исправить ошибку в своей библиотеке и распространить ее. После того, как конечный пользователь установит обновленную DLL, они сразу получат выгоду от этого исправления ошибок во всех программах, которые используют эту DLL. (Если это не сломает вещи. См. DLL Hell.)
Другим преимуществом является различие между неявной и явной загрузкой. Если вы перейдете к дополнительной нагрузке на явную загрузку, тогда DLL, возможно, даже не существовало, когда программа была написана и опубликована. Это позволяет использовать механизмы расширения, которые могут открывать и загружать плагины, например.