Как соединить dll и exe в один файл

Обновлено: 04.07.2024

Исполняемый файл можно связать с библиотекой DLL (загрузить ее) одним из двух способов:

Неявное связывание — операционная система загружает библиотеку DLL в тот момент, когда она используется исполняемым файлом. Исполняемый файл клиента вызывает экспортированные функции библиотеки DLL так же, как статически скомпонованные и включенные в состав самого исполняемого файла функции. Процесс неявного связывания также иногда называют статической загрузкой или динамической компоновкой времени загрузки.

Явное связывание — операционная система загружает библиотеку DLL по запросу во время выполнения. Исполняемый файл, который использует библиотеку DLL, должен явно загружать и выгружать ее. Кроме того, в нем должен быть настроен указатель функции для доступа к каждой используемой функции из библиотеки DLL. В отличие от вызовов функций в статически скомпонованной или неявно связанной библиотеке DLL, при работе с явно связанной DLL исполняемый файл клиента должен вызывать экспортированные функции с помощью указателей функций. Процесс явного связывания также иногда называют динамической загрузкой или динамической компоновкой времени выполнения.

Для связывания с одной и той же библиотекой DLL исполняемый файл может использовать любой из этих способов. Кроме того, они не являются взаимоисключающими, то есть два разных исполняемых файла могут связываться с одной библиотекой DLL разными способами.

Определение подходящего метода связывания

Решение о применении неявного или явного связывания принимается на уровне архитектуры приложения. Каждый из этих способов имеет свои преимущества и недостатки.

Неявное связывание

Неявное связывание происходит в момент, когда из кода приложения вызывается экспортированная функция библиотеки DLL. При компиляции или сборке исходного кода вызывающего исполняемого файла для вызова функции DLL в коде объекта создается ссылка на внешнюю функцию. Для разрешения этой внешней ссылки приложение должно связаться с библиотекой импорта (LIB-файл), которая предоставляется разработчиком библиотеки DLL.

Библиотека импорта содержит только код для загрузки библиотеки DLL и реализации вызовов ее функций. При поиске внешней функции в библиотеке импорта компоновщик определяет, что код этой функции находится в библиотеке DLL. Для разрешения внешних ссылок на библиотеки DLL компоновщик просто добавляет в исполняемый файл сведения, на основании которых система определяет, где следует искать код DLL при запуске процесса.

Если любая из библиотек DLL содержит функцию точки входа для инициализации и завершения кода, например DllMain , операционная система вызывает эту функцию. С помощью одного из параметров, передаваемого в функцию точки входа, задается код, который указывает на связывание библиотеки DLL с процессом. Если функция точки входа не возвращает значение TRUE, система завершает процесс и возвращает ошибку.

Наконец, система изменяет код исполняемого файла процесса и предоставляет функциям DLL начальные адреса.

Как и в случае с остальном кодом программы, загрузчик сопоставляет код DLL в адресном пространстве процесса при запуске процесса. Операционная система загружает его в память только при необходимости. В связи с этим атрибуты кода PRELOAD и LOADONCALL , которые использовались DEF-файлами для управления загрузкой в предыдущих версиях Windows, более не имеют смысла.

Явное связывание

В большинстве приложений используется более простой способ неявного связывания. Тем не менее иногда явное связывание необходимо. Такой подход может требоваться в следующих случаях:

Имя библиотеки DLL, которую необходимо загружать, становится известно приложению только во время выполнения. Например, приложение может получать имя библиотеки DLL и экспортированные функции из файла конфигурации во время запуска.

Если при запуске не удается найти нужную библиотеку DLL, процесс, в котором используется неявное связывание, завершается операционной системой. Процесс с явным связыванием в таких ситуациях не завершается и может попытаться восстановиться после ошибки. Например, процесс может уведомить пользователя об ошибке и запросить указать другой путь к библиотеке DLL.

Процесс с неявным связыванием также завершается, если в любой из связанных библиотек DLL функция DllMain завершается сбоем. Процесс с явным связыванием в таких ситуациях не завершается.

Приложение, в котором применяется неявное связывание с множеством библиотек DLL, может долго запускаться, поскольку операционная система Windows при загрузке приложения загружает все библиотеки DLL. Чтобы ускорить процесс запуска приложения, можно выполнять неявное связывание только с теми библиотеками DLL, которые необходимы непосредственно после загрузки. Другие библиотеки DLL могут загружаться позднее по мере необходимости посредством явного связывания.

При явном связывании приложению не требуется библиотека импорта. Если из-за изменений в библиотеке DLL изменяются порядковые номера экспорта, приложениям не нужно будет повторно выполнять связывание, если для вызова GetProcAddress в них используется имя функции, а не ее порядковый номер. Если приложение использует неявное связывание, в случае изменений в библиотеке импорта им потребуется выполнить связывание повторно.

При использовании явного связывания следует учитывать два потенциально опасных фактора:

Если библиотека DLL имеет функцию точки входа DllMain , операционная система вызывает функцию в контексте потока, который вызывал LoadLibrary . Функция точки входа не вызывается, если библиотека DLL уже связана с процессом в рамках предыдущего вызова LoadLibrary , во время которого не выполнялся соответствующий вызов функции FreeLibrary . При явном связывании могут возникать проблемы, если библиотека DLL использует функцию DllMain для инициализации каждого потока в процессе, поскольку все потоки, существовавшие на момент вызова LoadLibrary (или AfxLoadLibrary ), не инициализируются.

Если в библиотеке DLL статические элементы данных объявляются как __declspec(thread) , при явном связывании может произойти сбой системы защиты. После загрузки библиотеки DLL посредством вызова LoadLibrary сбой системы защиты будет происходить каждый раз, когда в коде используется ссылка на такие данные. Статические элементы данных включают как глобальные, так и локальные статические элементы. Поэтому при создании библиотеки DLL не рекомендуется использовать локальную память потока. Если это все же необходимо, следует проинформировать пользователей библиотеки о возможных проблемах при ее динамической загрузке. Дополнительные сведения см. в разделе Использование локальной памяти потока в библиотеке динамической компоновки (пакет SDK для Windows).

Использование неявного связывания

Чтобы использовать библиотеку DLL посредством неявного связывания, исполняемые файлы клиента должны получить от ее поставщика следующие файлы:

Один или несколько файлов заголовка (с расширением h), в которых содержатся объявления экспортированных данных, функций и классов C++ в библиотеке DLL. Все классы, функции и данные, экспортируемые из библиотеки DLL, должны быть отмечены в файле заголовка как __declspec(dllimport) . Дополнительные сведения см. в статье dllexport, dllimport.

Библиотека импорта, которая связывается с исполняемым файлом. Библиотека импорта создается компоновщиком при построении DLL. Дополнительные сведения см. в разделе Использование LIB-файлов в качестве входных данных для компоновщика.

Чтобы использовать данные, функции и классы в библиотеке DLL посредством неявного связывания, исходный файл клиента должен содержать файлы заголовков, в которых они объявляются. С точки зрения кода вызовы экспортированных функций выполняются так же, как и в случае с любыми другими функциями.

Для построения исполняемого файла клиента необходимо выполнить связывание с библиотекой импорта DLL. Если вы используете внешние файл makefile или систему сборки, необходимо указывать библиотеку импорта вместе с другими связываемыми файлами объектов или библиотеками.

При вызове исполняемого файла операционная система должна иметь возможность найти DLL-файл. Это означает, что при установке приложения необходимо либо развернуть нужную библиотеку DLL, либо проверить ее наличие.

Явное связывание с библиотекой DLL

Чтобы использовать библиотеку DLL посредством явного связывания, необходимо вызвать функцию для явной загрузки библиотеки DLL во время выполнения. Для явного связывания с библиотекой DLL приложение должно выполнить следующие действия:

Вызвать LoadLibraryEx или аналогичную функцию для загрузки библиотеки DLL и получения дескриптора модуля.

Вызвать GetProcAddress, чтобы получить указатель для каждой экспортированной функции, которую вызывает приложение. Поскольку приложения вызывают функции DLL с помощью указателя, компилятор не создает внешние ссылки и нет необходимости связываться с библиотекой импорта. Тем не менее, необходимо использовать оператор typedef или using , определяющий сигнатуру вызова для вызываемых экспортированных функций.

По завершении работы с библиотекой DLL вызовите FreeLibrary.

В приведенном ниже примере функции вызывается LoadLibrary для загрузки библиотеки MyDLL, затем вызывается GetProcAddress для получения указателя на функцию DLLFunc1, далее вызывается эта функция и сохраняется результат, после чего вызывается FreeLibrary для выгрузки библиотеки DLL.

В отличие от этого примера, в большинстве случаев LoadLibrary и FreeLibrary следует вызывать в приложении только один раз для нужной библиотеки DLL. Это особенно важно, если вы планируете многократно вызывать функции в библиотеке DLL.

FoggyFinder

Кстати судя по сигнатуре можно пропустить шаг выгрузки на диск и загружать прямо из памяти.

FoggyFinder

Молзв Реках, не сталкивался. Но опять таки ILMerge использовал всего пару раз.

Соеденить все managed (!) dll в одну dll/exe можно с помощью ILRepack.
ILMerge мертв, его заменил ILRepack.
Сборку можно делать Post Build Event проекта вызовом ILRepack.exe на результатам сборки.

Конечно надо всё настраивать.

FoggyFinder

Foggy Finder, он годами не обновлялся, а еще в году 2016 авторы в бложике писали что не будут поддерживать новые платформы. Похоже ожил, но всё равно я уже сижу на ILRepack c его фичами

MvcBox

SpacePurr

5dbed55dc1005875033495.jpg

Не все dll можно вместить в .exe.
Однако, попробуйте вот что. Если работаете в студии, то в Обозревателе Решений выберете ваш проект, перейдите в Ссылки. Нажмите на нужную вам ссылку и в свойствах переключите параметр "Внедрить типы взаимодействия" в True.

FoggyFinder

Какие, например, нельзя?

SpacePurr

Foggy Finder, когда я писал программу для интеграции с TDMS (строительная система учета, документооборота и т.д.), то при помещении api.dll в .exe моей программы, исполняемый файл не запускался. Решилось все помещением dll рядом с .exe, но, после вашего вопроса я задумался о том, что мог сделать что-то неверно)

FoggyFinder

Space Purr, а как вшивали? Для нативных обычно требуется отдельная настройка, вот, на примере, SQLite и Costura.Fody:

Здравствуйте, при попытки сборки вылезла такая ошибка:

SpacePurr

Молзв Реках, значит этот способ не подходит

SpacePurr

Foggy Finder, каким то образом я вспомнил про это диалог с dll.

Есть у меня библиотека с ActiveX контролами одной системы, допустим ControlsLib.

Когда я добавляю контрол из списка предложенного Visual Studio при добавлении новых элементов управления, то студия сама формирует новую библиотеку по типа Ax и добавляет и ее и оригинальную библиотеку ControlsLib в ссылки проекта.
После этого, при попытке выставить параметр "внедрить типы взаимодействия" в true, студия выдает ошибку.
Таким образом, если я использую ActiveX элемент управления, то обе библиотеки должны находится рядом с моим исполняемым файлом.

У меня есть два DLL-файла, которые я хотел бы включить в свой EXE-файл, чтобы облегчить его распространение. Я прочитал немного здесь и там, как это сделать, даже нашел хорошую нить здесь и здесь, но это слишком сложно для меня и мне нужны реальные основные инструкции, как это сделать.

  1. откройте CMD и cd в свой каталог. Скажем: cd C:\test
  2. вставьте приведенный выше код.
  3. /out:finish.exe заменить finish.exe С любым именем вы хотите.
  4. за /out:finish.exe вы должны дать файлы, которые вы хотите быть комбинированный.

скачать ilmerge и ilmergre gui . делает присоединение к файлам так легко ive использовал их и отлично работает

ссылайтесь на библиотеки DLL на свои ресурсы и используйте AssemblyResolve-Event для возврата DLL-ресурса.

вы просто установить NuGet для а затем сделайте сборку. Окончательный исполняемый файл будет автономной.

Установить ILMerge как другие потоки говорят вам

затем заходим в папку установки, по умолчанию C:\Program Files (x86)\Microsoft\ILMerge

перетащите Dll и Exes в эту папку

Shift-Rightclick в этой папке и выберите Открыть командную строку

обратите внимание, что вы должны написать свой. exe первых.

там вы получили свой объединенный exe. Это может быть не лучшим способом, если вы собираетесь сделайте это несколько раз, но самый простой для одноразового использования, я бы порекомендуйте положить Ilmerge к вашему пути.

Сначала добавьте библиотеки DLL в ресурсы проекта. Добавить папку "Resources"

также вы можете использовать ilmergertool в codeplex с интерфейсом GUI.

если вы хотите ссылаться на него во время разработки, просто добавить нормальной DLL ссылка на ваш проект.

здесь официальная документация. Это также автоматически загружается на Шаге 2.

установите пакет ILMerge nuget через gui или командную строку:

enter image description here

убедитесь, что вы скачали его. Теперь Установите (не уверен, что команда для этого, но просто перейдите к пакетам nuget): Примечание: Вы, вероятно, нужно только установить для одного из ваших решений, если у вас несколько

перейдите к папке решения и в папке packages вы должны увидеть ILMerge с исполняемым:

enter image description here

теперь вот исполняемый файл, который вы можете скопировать в свой \bin\Debug (или где бы ни было построено ваше приложение), а затем в командной строке / powershell do что-то вроде ниже:

теперь у вас будет новый исполняемый файл со всеми вашими библиотеками в одном!

Вам даже не нужно включать библиотеки DLL в качестве встроенных ресурсов, просто используйте Fody .Costura, и он разрешит указанные сборки и автоматически включит их.

Если вам нужен простой инструмент для объединения сборок, не беспокоясь о выполнении ЛЮБОЙ работы, тогда Fody.Costura - лучший выбор, который у вас есть, так как все, что вам нужно сделать, это просто включить библиотеки DLL и изменить их действие сборки на встроенный ресурс, и он сразу же заработает.

1 - создайте папку, содержащую все Dll, или разместите их отдельно, как вам нравится

2 - Щелкните каждую DLL в «Обозревателе решений» и убедитесь, что у них есть эти свойства.

Действие сборки = встроенные ресурсы

Копировать в выходной каталог = Не копировать

change their Build Action

3 - Перейдите в: Проект> Свойства> Ссылки и убедитесь, что каждая добавляемая вами Dll имеет то же имя, что и сборка, например:

Reference name = Dll name

В обозревателе решений: -

Reference name = Dll name

Лучше сделать копию local = True в ссылках, так как она будет давать вам обновленную DLL каждый раз, когда вы публикуете проект.

Теперь, когда ваши библиотеки DLL добавлены в EXE, осталось только указать программе, как читать эти библиотеки DLL из EXE (поэтому мы сделали действие сборки = встроенные ресурсы)

Теперь на этой странице мы собираемся обработать самое первое событие приложения (событие Construction), чтобы сообщить программе, как обрабатывать сборки, которые мы добавляем как библиотеки DLL, перед их загрузкой / чтением с помощью события AssemblyResolve .

5 - Теперь к части кода:
прежде всего Импортируйте это пространство имен

В конструкторе ([Sub New] в vb) добавьте этот код

6. Теперь опубликуйте приложение или соберите его, и все ваши DLL будут встроены в один EXE-файл (с некоторой дополнительной задержкой в ​​миллисекундах для их загрузки)

1. Просто перетащите новую dll в обозреватель решений в ту же папку, что и старая dll, затем примите переопределение (убедитесь, что вы установили [Build Action = Embedded Resources] AND [Copy To Output Directory = Do not copy])

change their Build Action

Просто повторите шаг 1 => 3

* Не стесняйтесь спрашивать, были ли у вас проблемы

Не удалось получить ответ bigworld12, который работал у меня, но я нашел это link, и у меня он отлично сработал.

В основном суть страницы заключается в том, чтобы выгрузить ваш проект и добавить следующий код в ваш файл csproj

Под этой строкой кода.

Как только это будет сделано, перезагрузите проект и добавьте к нему новый класс, а также добавьте следующий код в свой новый класс.

Сохраните свой класс, откройте меню свойств вашего проекта, выберите запускаемый объект combobox и выберите имя только что созданного вами класса из списка.

Мы добавим в консольный проект 2 exe, а именно в ресусры, это может быть 1 полезная прога и 2 ваша малварь, это не суть, суть в том что бы склеить 2 любых exe и запустить их из 1 exe при том не палясь перед АВ.

Нам понадобится:

Запускаем Visual Studio 2019 и создаем консольный проект:


3. Справа жмем по Program.cs


Начнем писать код.

Удаляем все в редакторе и вставляем мой код, в коде смотрите комментарии что можно изменить, название файлов, архивов, все что я комментил все можно изменить на ваши имена, поехали:

Учтите если вы назвали проект не как уменя: ViJoy


Для примера я буду использовать 2 программы:

Их мы и будем склеивать, вы можете представить это так:

Теперь надо 2 эти программы добавить в наш exe билд который мы написали.

Для начала будем использовать 7zip и запакуем их в 1 архив под паролем.

Выделяем эти 2 файла, жмем правой кнопкой мыши и жмем: 7-zip > добавить к архиву

Пароль любой, ваш, только в коде выше его не забудьте поменять в строке примерно 21й.

В моем случаи пароль будет 123

ahiv.zip, его давайте переименуем в другой формат и название:


Теперь этот архив надо добавить в наш exe который мы кодили в Visual Studio 2019 (Далее буду назвать это VS).

Открываем снова VS:

1. Жмем по проекту правой кнопкой мыши:


Уже готово! Но. Теперь давайте скроем окно консоли. Опять правой кнопкой про проекту, скрин выше > свойства > слева в меню: Приложение > Тип выходных данных выбираем: приложение Windows

Теперь нам надо все собрать/скомпилить, ура!

Выбираем в окне VS вместо Debug > Release

Теперь соберем наши exe и весь проект в 1 exe!

Идем в папку bin > Release и видим наш exe файл. Запускаем. и Оп:


Вы так же можете добавить по этой технологии сколько угодно exe! хоть 100шт и запускать все разом, данный код не ограничен только двумя exe файлами.

Исходники проекта который мы с вами разобрали в статье можете скачать тут

Читайте также: