У меня есть приложение C ++, которое связано с некоторыми сторонними динамическими библиотеками. Некоторые из моих основных классов наследуются от этих библиотек и выполняют вызовы функций для этих библиотек и т. Д. Мое приложение работает без включения этих библиотек в теории (т. Е. Если бы я вручную удалил весь код и ссылки, относящиеся к этим библиотекам, он бы все еще работает), это было бы просто более ограниченным в функциональности. Если бы я смог создать аналогию, представьте, что я создал клон Windows Notepad и включил стороннюю библиотеку, которая позволяет пользователям вставлять изображения и видео в документ.

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

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

2
Tyson 4 Сен 2017 в 22:19

6 ответов

Лучший ответ

Есть такая опция "задержка загрузки dll"

  1. Для dll xxx.dll вы настраиваете компоновщик для использования «delayload»
  2. Пока вы не вызовете какую-либо функцию из dll, она не будет загружена, и ваше приложение запустится успешно, даже если dll отсутствует
  3. Вы используете LoadLibrary, чтобы проверить, доступен ли xxx.dll.
  4. Если LoadLibrary не удалось - вы отключите модуль с помощью xxx.dll
  5. Если LoadLibrary успешна - вы выгружаете ее (вам не нужна динамическая загрузка - она используется только для проверки наличия dll) и используете библиотеку, как если бы она регулярно связывалась - не нужно изменять код с использованием какой-либо функциональности, связанной с xxx.dll
2
Artemy Vysotsky 4 Сен 2017 в 19:26

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

Но если у вас есть возможность построить приложение на клиентской системе, вы можете использовать CMake и установить флаги компиляции, если он не может найти нужную вам библиотеку. Тогда ваш код может вести себя в соответствии со значением этого флага (то есть таким образом у вас есть информация о том, существует эта библиотека или нет в вашем коде)

0
Sinapse 4 Сен 2017 в 19:29

Загрузка динамической библиотеки или внедрение в процесс или ... можно использовать после этого вы можете:

    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
    inj_hModule = hModule;
    DisableThreadLibraryCalls(hModule); // Disable DllMain calls for DLL_THREAD_*

    HANDLE hThreadProc = CreateThread(nullptr, NULL, LPTHREAD_START_ROUTINE(ThreadProc), hModule, NULL, nullptr);
    CloseHandle(hThreadProc);
    Beep(2000, 500);
}

if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
    Beep(2000, 500);
    FreeLibraryAndExitThread(hModule, 0);
    // exit this thread
    ExitThread(0);
}
0
user8556290user8556290 4 Сен 2017 в 19:37

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

Теперь эта DLL может зависеть от сторонней DLL, как обычно. Ваш основной код вызывает вашу «оборачивающую» DLL, загружая ее вручную, и корректно обрабатывает сбой загрузки.

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

0
Yakk - Adam Nevraumont 4 Сен 2017 в 20:37

Смотрите этот ответ здесь: Динамически загружать функцию из DLL

  1. Вы в основном используете LoadLibrary для загрузки DLL, результат будет ноль или нет, если загружен.

  2. Затем вы используете GetProcAddress для получения функций.

2
Wayne 4 Сен 2017 в 19:30

Что ж, вам следует пересмотреть архитектуру своего программного обеспечения и перейти к Шаблону разработки плагинов как представил Мартин Фаулер.
Вам не нужна динамическая связь для такого случая, хотя она очень похожа.

Что касается реализаций в C ++, это означает, что вы сначала вводите абстрактный интерфейс.

 struct Foo {
     virtual void Bar() = 0;
     virtual ~Foo() {}
 };

1

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

Вы можете использовать Factory для этого поиска, загружая общую библиотеку и создать экземпляр реализации.

Вот еще немного информации о том, какие функции ОС участвуют в динамической загрузке и привязать плагин.


1) Обратите внимание, что разделяемым библиотекам не нужно иметь расширение .dll или .so, если вы их активно загружаете.

0
user0042 4 Сен 2017 в 20:10