Как подключить dll к qt

Обновлено: 05.07.2024

На форуме поднимался вопрос, как создать динамическую библиотеку и правильно подключить ее к стороннему проекту. Периодически такие вопросы возникают, поэтому рассмотрим один из вариантов создания динамической dll для Windows с помощью стандартных мастеров в Qt Creator.

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

Создайте два проекта:

  1. QuiLib — это будет внешняя динамическая библиотека, которая будет содержать одно диалоговое окно. Это диалоговое окно откроется в основном проекте.
  2. WithDynamicLibrary — проект, который будет использоваться для подключения этой динамической библиотеки.

Шаг 1

Выбираем создание проекта в меню Qt Creator и выбираем тип нашего проекта. Это будет библиотека C++.


Шаг 2

Запишем название проекта и его местоположение


Шаг 3

Выберите комплекты для проекта сборки.

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

Я компилирую эту библиотеку с помощью компилятора MSVC2017.


Шаг 4

Выберите необходимые модули. Для нашей библиотеки достаточно базового функционала.


Шаг 5

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


Шаг 6

Используете ли вы систему контроля версий? Поэтому добавьте проект под контроль версий. Если нет, ничего не делайте. И просто завершите создание библиотеки.


Шаг 7

Давайте посмотрим на файлы проекта и немного изменим их.

Структура проекта


QuiLib.pro

В этом файле есть информация, что это библиотека. Вот в этой строке.

Вот полный код файла pro.

quilib_global.h

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

QuiLib.h

Давайте немного подправим заголовочный файл диалогового окна, нам действительно нужен диалог, а значит, нам нужно наследовать класс в этом заголовочном файле от QDialog.

QuiLib.cpp

Мы также напишем реализацию дизайнера диалоговых окон, чтобы он сообщал нам с помощью QLabel, что это диалоговое окно из внешней библиотеки.

Шаг 8

Скомпилируем проект в версиях Debug и Release.

Вот, например, что будет в каталоге выпуска сборки библиотеки. Из этих файлов нам нужны только файлы QuiLib.dll и QuiLib.lib. Помимо этих файлов вам также потребуются заголовочные файлы из самого проекта, но об этом позже.


Шаг 9

Создайте проект, который будет использовать эту динамическую библиотеку. Процесс создания будет стандартным, через мастера в Qt Creator. Вам нужно будет выбрать приложение Qt.

Добавить название и местоположение проекта


Шаг 10

Укажите сборочный комплект.


Шаг 11

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


Шаг 12

Опять выбор системы контроля версий и завершение процесса создания проекта.


Шаг 13

Структура проекта


В директории этого проекта создаем директорию QuiLib, в которой размещаем директории debug, release, include.

Эти каталоги будут содержать скомпилированные библиотеки QuiLib.dll и QuiLib.lib, соответственно, отладочной версии и версии выпуска. Каталог include будет содержать заголовочные файлы QuiLib.h и quilib_global.h.

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

Шаг 14

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


Шаг 15

Мы знаем, что библиотека является внешней


Шаг 16

А также, что мы будем использовать его только для Windows. Здесь настроено, что версии Debug и Release находятся в разных каталогах без каких-либо префиксов отладочных библиотек. Я их просто не ставил. Достаточно указать одну из библиотек .lib * либо в каталоге отладки, либо в каталоге выпуска. Путь к другой версии будет добавлен автоматически. Также необходимо указать каталог, в котором находятся заголовочные файлы. Традиционно это включает** каталог.


Шаг 17


Шаг 18

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

Теперь давайте посмотрим на pro-файл нашего проекта, в котором будет использоваться динамическая библиотека.

С помощью DynamicLibrary.pro

Это самые последние строки в этом файле.

Виджет.пользовательский интерфейс

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


Виджет.h

Давайте напишем слот для обработки нажатия кнопки.

Виджет.cpp

А теперь обработаем нажатие кнопки и вызовем диалоговое окно из внешней библиотеки.

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

Заключение


Мы рекомендуем хостинг TIMEWEB
< /p>

Мы рекомендуем размещать TIMEWEB

Стабильный хостинг, на котором находится социальная сеть EVILEG. Для проектов на Django мы рекомендуем хостинг VDS.

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

У меня есть файл .dll, а также соответствующий файл .lib с таким же именем. Я хочу использовать некоторые функции из них с моим приложением Qt. У меня есть список функций, доступных мне в библиотеке, а также список прототипов C++ для этих функций (они написаны с использованием extern "C").

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

Теперь мой первый вопрос: правильно ли я думаю об этих двух вещах?

Если да, есть ли предпочтительный выход из этого?

Если я ошибаюсь, кто-нибудь сможет мягко подтолкнуть меня в правильном направлении?

Я думаю, что ваше понимание в целом правильное. Обычно я предпочитаю использовать заголовки, объявляющие прототипы, а не динамическую загрузку во время выполнения (например, через QLibrary).Это, конечно, проще всего, если у вас есть файлы заголовков, предоставленные автором библиотеки, которую вы хотите использовать.

Да, я подумал, что поскольку у меня есть прототипы C++, мне не нужно беспокоиться о динамической загрузке во время выполнения. Скажите - вы просто включаете библиотеку в .pro файл?

Что-то вроде - win32:LIBS += путь/к/myLib.lib

Попробую. Лучше экспериментируйте и учитесь!

У вас по-прежнему есть выбор между динамической и статической привязкой к вашему приложению (статическая — это файл .lib, динамическая — файл .dll). Если вы используете статическое связывание, файл будет частью вашего приложения, и вам не нужно развертывать дополнительные файлы, как в случае с динамической библиотекой (хотя вы, вероятно, в любом случае связываете Qt динамически, так что вы, вероятно, знакомы с этим). Если это популярная библиотека или есть проблемы с лицензией (например, библиотека принадлежит LGPL), я бы посоветовал вам использовать динамическую компоновку, в противном случае статическая подойдет.

  1. добавить в файл *.pro нечто подобное
    @LIBS += d:/test/lib/somelib.lib@
  2. добавить в *.cpp
    @QLibrary library("somelib");
    library.load();@

Файл .lib является статической библиотекой, вы не можете использовать QLibrary для доступа к нему.

Я бы использовал обычное связывание вместо QLibrary. Это намного проще, так как ваша ОС будет обрабатывать все случаи ошибок еще до запуска вашего приложения. Я думаю, что QLibrary имеет смысл только в том случае, если вам нужна необязательная зависимость от какой-либо библиотеки.

Кроме того, ваш pro-файл уже должен быть связан с какой-то библиотекой со строкой LIBS, поэтому вам фактически не нужно загружать его снова с помощью QLibrary. Используйте файл depend.exe (доступный где-то на веб-сайте Microsoft), чтобы проверить исполняемый файл:-)

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

  1. Добавьте библиотеку в переменную LIBS в файле .pro:
    @LIBS += -llibrary@
  2. Добавьте путь библиотеки к переменным LIBS в файле .pro:
    @LIBS += -LC:/path/to/library@
  3. Добавьте путь включения к переменной INCLUDEPATH в файле .pro:
    @INCLUDEPATH += C:/path/to/includes@

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

Я могу подключить lib и os libs, но не могу подключить dll
подскажите как правильно это сделать?
и как включать в код?

Если вы имеете в виду qmake (файл *.pro), то:

Ну, в коде просто эклогитить как обычно после этого.

С CMake проекты будут другими. Кстати, скоро Qt официально перейдет на CMake.

это не работает с использованием libs, потому что он говорит что-то вроде не может открыть файл '..\my_library.lib'

как искать не .lib файл, а .dll? - прокомментировал bertram_Reiche 31 марта 20 в 16:09

@brianne_McKenzie Если вы покажете полный код, будет идеально. - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:12

@Oleta_Stiedemann, на самом деле я просто хочу запустить этот проект с библиотекой openbabel, но не могу заставить его подключиться/правильно скомпилироваться, поэтому я взял dll отсюда 0.3.0-windows-dynamic.zip - bertram_Reiche прокомментировал 31 марта 20 в 16:15

Система сборки проекта не qmake, а CMake. Вам нужно где-то в системе установить CMake.

После этого система сборки должна найти его сама. - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:18

@Oleta_Stiedemann, мне не удалось использовать его для сборки, потому что он требует qt4, а у меня походу qt5:

- прокомментировал bertram_Reiche 31 марта 20 в 16:21

@brianne_McKenzie, поэтому необходимо установить Qt4. Что прямо написано в логе:
"этот код требует Qt 4.x". Т.е. с Qt5 код просто не сойдется, либо будет работать некорректно.

Всегда читайте логи, там много полезной информации. - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:24

@Oleta_Stiedemann, ну вот поэтому я и хотел qtcreqtor, что делать, потому что у меня есть исправленные функции, которые не поддерживаются qt4 qt5

Просто измените:
find_package(ТРЕБУЕТСЯ Qt4) на find_package(ТРЕБУЕТСЯ Qt5)
Ну, может быть, больше: set(QT_MIN_VERSION "4.5.0")

И поверьте, это будет быстрее и проще, чем переписывать все в qmake. - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:30

@brianne_McKenzie, В общем, если вы не хотите тратить очень много времени, проще собрать с Qt4. - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:33

@Oleta_Stiedemann, я скачал установленный qt4 qt-win-opensource-4.8.5-vs2010.exe и добавил путь в Path, но CMake все равно пытается sbility использовать qt5

@brianne_McKenzie, нужно явно указать, как qt'ом собирать:
-DCMAKE_PREFIX_PATH="path_to_qt\lib\cmake"

Не уверен, что это работает с qt4, но все же попробуйте. Только убедитесь сначала, есть ли у вас в системе что-то вроде path_to_qt\lib\cmake. - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:39

@Oleta_Stiedemann, что нужно сделать в файле cmake, чтобы найти openbabel2?
- прокомментировал bertram_Reiche 31 марта 20 в 16:42

@brianne_McKenzie, На самом деле ничего. Все уже есть. Он должен быть установлен в вашей системе и быть во всех отношениях. - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:45

@Oleta_Stiedemann , я установил разные версии openbabel в разные папки, скачал рабаривола это github и вроде бы все сделал но все равно не работает

5da5e3aaa6db7351425514.jpg

@Oleta_Stiedemann , - прокомментировал bertram_Reiche 31 марта 20 в 16:51

5da5e3f3df98b662849012.jpg

@Oleta_Stiedemann , - прокомментировал bertram_Reiche 31 марта 20 в 16:54

@brianne_McKenzie, пробовали ли вы полностью очистить каталог сборки и снова вызывать cmake? - прокомментировал rodolfo_Wehner55 31 марта 20 в 16:57

ну в итоге получилось culdrose
но я не очень понимаю как подключиться к проекту openbabel в qtcreator ?? - прокомментировал bertram_Reiche 31 марта 20 в 17:03

@Oleta_Stiedemann, я spildra и скомпилировал openbabel и bildil molsketch, но это все равно не помогает мне подключиться к проекту openbabel, потому что нет даже файла lib или чего-то, что я мог бы подключить — прокомментировал bertram_Reiche 31 марта 20 в 17:06

@brianne_McKenzie Если у вас все есть, и все работает и работает, то это здорово!

Можно просто открыть CMakeLists.txt Qt Creator ом. Если все зависимости определены правильно, то IDE автоматически найдет их и покажет. - прокомментировал rodolfo_Wehner55 31 марта 20 в 17:09

5dae3c5b14b88313893974.jpg

@Oleta_Stiedemann, не совсем понял, как открыть cmakelist?
что я делаю не так?

5dae3c75a277d377446302.jpg

в наборах есть все вроде:
- прокомментировал bertram_Reiche 31st 20 марта в 17:12

@Oleta_Stiedemann, не понял какой комплект подходит в итоге - прокомментировал bertram_Reiche 31st 20 марта в 17:15

Для подключения библиотеки DLL *.pro к файлу добавьте:
LIBS += полный путь к файлу .lib

Или системные библиотеки:
LIBS += -lUser32

Библиотека DLL состоит из файлов .lib, .h и .dll. Для сборки .exe нужны .lib .h. Тогда при запуске .exe где-то рядом должна лежать .dll.

После изменения файла pro вам нужно щелкнуть правой кнопкой мыши проект и запустить Qmake.

Создание dll кажется простой задачей в Qt. В создателе Qt нажмите «Файл/Новый файл» или «Проект/Проекты/Библиотека/Библиотека C++», затем просто выберите имя, и вы создадите проект dll. Нажмите «сборка», вы увидите .dll, сгенерированный в каталоге отладки или выпуска. После создания .dll вы можете использовать его в своем основном приложении. Ваше основное приложение может явно загружать dll во время выполнения или неявно ссылаться на dll во время компиляции. В любом случае, процесс прост. В явном методе вы можете использовать QLibrary::load для загрузки dll, использовать QLibrary::resolve для получения адреса экспортируемой функции, а затем вызвать эту функцию. Если вы знакомы с Windows API, вы должны знать, что эти функции являются упаковкой API LoadLibrary и GetProcAddress. В неявном методе вам нужно импортировать библиотеку dll в ваше основное приложение, после чего вы можете использовать функции/классы в dll, как если бы они были определены в вашей основной программе. Если вы копнете дальше, вы найдете более мощные библиотеки для загрузки dll и плагинов, таких как QPluginLoader.

К сожалению, за всей простотой скрывается заговор. Если вы посмотрите на файлы, которые создает Qt Creator для проекта dll, вы найдете два заголовочных файла: dllclass.h и dllclass_global.h. Файл cpp (dllclass.cpp) включает файл dllclass.h. dllclass.h также должен быть включен в другие файлы (например, ваше основное приложение), которые используют dll.Обычно проект dll имеет только один заголовочный файл, который включается как в файл реализации проекта dll, так и в связанные файлы в других проектах, использующих dll. Почему Qt генерирует дополнительный заголовочный файл: dllclass_global.h? Откройте этот файл, и вы обнаружите, что он содержит два специальных символа Qt: Q_DECL_EXPORT и Q_DECL_IMPORT. Более того, он также включает в себя еще один внутренний заголовочный файл Qt. Обратите внимание, что dllclass.h включает dllclass_global.h, а dllclass.h будет использоваться как производителем, так и потребителем dll, что означает, что все стороны, связанные с dll, должны будут использовать Qt в качестве инструмента разработки. Это смешно.

Мы должны понять, зачем нам нужна dll. Некоторым ребятам нравится разделять свою программу на несколько компонентов, и каждый компонент помещается в независимую dll. Это не типичные сценарии, для которых используется dll. Типичный сценарий dll используется в следующем: если вы хотите, чтобы другие расширили функциональность вашего приложения, но не хотите раскрывать им свой исходный код, другие, которые расширяют ваше приложение, могут также не захотеть, чтобы вы получили их исходный код. В этом случае вы и он/она можете использовать dll для взаимодействия друг с другом. Разработчику dll нужно только доставить файл dll, чтобы расширенное приложение заработало. Никакого раскрытия или обмена исходным кодом, даже заголовочным файлом. Но вы и разработчик dll должны иметь соглашение о функциональности dll, которая называется интерфейсом. Интерфейс обычно представлен в заголовочном файле, но не всегда. Он также может быть представлен в документе или любом тексте. Лучшая часть dll — это изоляция основной программы и dll. Основная программа и dll могут быть даже разработаны с использованием разных языков программирования. Вот почему я называю решение Qt для dll заговором, потому что оно требует, чтобы обе стороны использовали один и тот же язык программирования (C) и даже одну и ту же среду программирования (Qt). Это скорее маркетинговое поведение, чем техническое решение.

Нам нужно немного изменить заголовочный файл, чтобы разработчикам dll и основного приложения больше не требовался Qt.

Чтобы использовать DllClass в основном приложении, не следует использовать «новый DllClass», поскольку вы не реализовали DllClass в основном приложении, несмотря на то, что включили заголовочный файл. Таким образом, создание экземпляра объекта DllClass непосредственно в основном приложении приведет к ошибке, например:

ошибка: LNK2019: неразрешенный внешний символ «__declspec(dllimport) public: bool __thiscall DllClass::fun(char *)» (__imp_?fun@DllClass@@QAE_NPAD@Z), на который ссылается функция …

Однако никакая реализация класса не мешает вызывать функцию-член с помощью указателя на класс:

Именно здесь ключевое слово virtual перед функциями-членами играет свою роль. Без ключевого слова virtual вызов функции-члена компилируется в вызов адреса функции. Поскольку функция-член не определена (не реализована), ее адрес не может быть определен, и привязка завершится ошибкой с «неразрешенным внешним символом». С ключевым словом virtual вызов функции будет скомпилирован как «(*(p+offset of fun in vtable))(…)». Смещения виртуальных функций определяются во время компиляции исключительно с помощью заголовочного файла (объявления класса), поэтому код для вызова функции может быть успешно сгенерирован. Единственная проблема заключается в том, что p теперь является диким указателем. Мы должны создать объект DllClass в dll и передать его указатель основному приложению. Мы можем создать экземпляр объекта DllClass в dll, потому что мы реализуем класс в этой dll. Вот почему мы реализуем и экспортируем функцию getDllClass() в dll. Эта функция отвечает за создание объекта DllClass (новый DllClass). В основной программе мы используем QLibrary::load и QLibrary::resolve для получения и вызова этой функции для получения указателя на реальный объект DllClass. Мы будем использовать этот указатель для вызова функций-членов DllClass.

Чтобы сохранить адрес getGetDllClass, мы также определяем тип GetDllClass в заголовочном файле.

<р>2. Поскольку формы и другие библиотеки пользовательского интерфейса по умолчанию не вводятся, сначала добавьте ссылку в ссылку System.Windows.Forms, чтобы ее можно было использовать в тестовом MessageBox и т. д.

<р>4. Отпустите сборку проекта и сгенерируйте CSharpDll.dll (для использования позже).

Вначале я использовал vs2019. Кажется, что vs2019 не может создать новый класс проекта библиотеки типа C++ CLR, поэтому мы должны быть осторожны, изучая технологию Microsoft, изучая основные технологии, которые поддерживаются в течение длительного времени, и стараться не изучать новые технологии. Если нам нужно изучить новую технологию, мы должны серьезно подумать об этом. Мы не должны изучать какие-то маргинальные технологии. Возможно, однажды Microsoft перестанет его поддерживать.

<р>6. Выберите проект > свойства cppdll. На всплывающей странице свойств выберите «добавить новую ссылку..», нажмите «обзор». а затем выберите «добавить новую ссылку..» в каталоге выпуска проекта csharpdll CSharpDll.dll 。

<р>7. Выбор CSharpDll.dll После этого вы можете увидеть, что библиотека csharpdll появляется в ссылках свойств проекта.

<р>8. Используйте в cppdll. H в проекте cppdll _declspec(dllexport) Экспортируйте соответствующие три функции интерфейса add, substract и showbox。 Вам необходимо использовать систему пространства имен::reflection. Для showbox здесь нельзя использовать строковый тип параметра showbox в csharpdll, а тип const char *.

Основные коды следующие:

<р>9. Выберите режим выпуска для сборки проекта cppdll и создайте файл CppDll.dll, вы можете увидеть CSharpDll.dll. Он также скопирован в папку выпуска.

<р>10. Затем вызовите QT, создайте новый проект графического интерфейса testcsharpdll в qtcreator и выберите MinGW в качестве компилятора. Вы можете просмотреть его с помощью инструмента dumpbin в инструменте командной строки vs CppDll.dll Интерфейс экспортированной функции.

В проекте testcsharpdll указатель на функцию определяется typedef, а библиотека qlibrary используется для динамической загрузки и разрешения функции.

Здесь путь. DLL установлена ​​в «в текущем каталоге»/ CppDllMingW.dll »То есть DLL в том же каталоге скомпилированной программы exe может быть экспортирована интерфейсом обычного режима экспорта, т.е. «? Добавить”@@ [email protected] ”。

Основные коды следующие:

Скомпилируйте проект testcsharpdll, а CppDll.dll и CSharpDll.dll Скопируйте в тот же каталог и запустите TestCSharpDll.exe. Видно, что после нажатия кнопки динамическое разрешение через qlibrary вызывается нормально.

Вызвать функцию добавления

Вызов подфункции

Вызов функции showbox

Лучше запускать соответствующую DLL в том же каталоге, иначе появится исключение «не удалось загрузить файл или сборку». Для. Режим ссылки на библиотеку, она должна быть размещена в том же каталоге. Для qlibrary первоначальная идея может заключаться в том, что CppDll.dll и CSharpDll.dll помещаются в другой каталог из программы. Программа использует qlibrary для указания CppDll.dll Загрузите таким же образом и CppDll.dll и CSharpDll.dll Итак, программа вызывает CppDll.dll Функция в CppDll.dll Мы найдем способ связаться с вами CppDll .dll Csharpdll в том же каталоге. DLL, однако CppDll.dll При загрузке программой наследует переменные окружения программы, поэтому будет искать из текущего каталога программы, поэтому CppDll.dll и CSharpDll.dll лучше положить в один и тот же каталог программы, и qlibrary загружает CppDll.dll 。 Конечно, при развертывании на другом компьютере целевая машина все равно должна быть установлена. Net framework, и его версия не должна быть ниже текущей версии CSharpDll.dll Используемая версия.

резюме

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