Как спрятать dll в exe c

Обновлено: 03.07.2024

Обновление: это то, что я получаю от ILmerge:

Это просто приложение для Windows, кстати, форма, которую нужно заполнить и распечатать в формате pdf с фотографией, сделанной с помощью веб-камеры, если таковая имеется. Спасибо всем!

ОТВЕТЫ

Ответ 1

Ответ 2

  • Добавьте файлы DLL в проект Visual Studio.
  • Для каждого файла перейдите в "Свойства" и установите для его действия по сборке значение "Встроенный ресурс"
  • На вашем коде вы можете восстановить ресурс с помощью GetManifestResourceStream ( "DLL_Name_Here" ), который возвращает поток, который может быть загружен.
  • Запишите обработчик событий "AssemblyResolve", чтобы загрузить его.

Надеюсь, что это поможет, Pablo

Ответ 3

Я немного изменил код Пабло, и это сработало для меня.
Он не получал имя ресурса DLL правильно.

Ответ 4

Ответ, который вы ищете:

Ответ 5

Добавьте этот анонимный код функции в начало нашего конструктора приложений. Это добавит dll из встроенного ресурса в тот же проект.

Ответ 6

Просмотрите AssemblyResolve событие в домене приложения.

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

Ответ 7

Я знаю, что тема старая, но я напишу ее будущим людям, которые захотят ее использовать.

i основывается на коде userSteve.

Я предлагаю изменить это.

таким образом он работал бы, даже если пространство имен отличается от имени сборки

также, если вы хотите использовать DLL из каталога, вы можете использовать его так (каталог "Ресурсы как пример" )

Ответ 8

Вы не ссылались на WPF, но если это так, это может быть причиной вашей ошибки. Если нет, ILMerge должен отлично работать для вас. Если вы используете WPF, вот решение, которое хорошо работает:

Решение

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

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

Другие решения

более сложным решением было бы создать статические библиотеки opencv из src, а затем связать вашу программу с теми, что приводит к 1 большому двоичному exe-чанку, который не использует никакие dll (кроме ffmpeg, не уверенный в этом).

чтобы создать статические библиотеки, вам нужно запустить cmake с: BUILD_SHARED_LIBS = OFF

но сделайте глубокий вдох, прежде чем сделать это. связать вашу программу будет значительно сложнее, потому что теперь вам нужно вручную связать все zlib, libpng и любые другие зависимости (которые до этого были удобно связаны с вашими dll)

Вы можете использовать Windows Dependency Walker чтобы определить, какие библиотеки DLL необходимо запустить.

На самом деле, это говорит только о том, какие DLL нужны вашей программе для успешного запуска. Если вы загружаете DLL динамически (через LoadLibrary), то вы сами по себе.

Если вы выбираете принятое решение (упакуйте DLL-файлы в EXE-файл) и не хотите искать, какие DLL-библиотеки использовать, вы можете скопировать все библиотеки OpenCV. Они не такие большие (65 МБ на OpenCV 2.43). Они расположены по адресу . \opencvXXX\build\x64\vc10\bin\

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 (загрузить ее) одним из двух способов:

Неявное связывание — операционная система загружает библиотеку 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.

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