Я читал много учебников / статей о неуправляемых библиотеках DLL в C++. Однако, хоть убей, я не могу понять эту концепцию. Меня легко сбивает с толку кажущееся разногласие по поводу того, нужен ли ему файл заголовка, как его экспортировать, нужен ли мне файл .lib и что есть у вас.
Итак, предположим, что у меня есть только такая функция:
public int calculateSquare(int num)
{
return num*num;
}
Игнорируя фактический код, что мне нужно, чтобы эта простая функция сама по себе превратилась в DLL, которую я затем могу вызвать? Я просто добавляю __dllexport или что-то еще в первую строку или мне нужен заголовок? Меня все это озадачивает.





Я не могу это подчеркнуть, компилятор C++ не видит файлы заголовков, после того, как препроцессор готов, остается только один большой исходный файл (также называемый блоком компиляции). Строго говоря, вам не нужен заголовок для экспорта этой функции из dll. Что вам действительно нужно, так это некоторая форма условной компиляции для экспорта функции в dll, которую вы компилируете, и для импорта ее в клиентский код.
Обычно это делается с помощью комбинации макросов и файлов заголовков. Вы создаете макрос с именем MYIMPORTEXPORT и с помощью условных операторов макроса заставляете его работать как __declspec (dllexport) в dll и __declspec (dllimport) в клиентском коде.
в файле MYIMPORTEXPORT.h
#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif
в файле MyHeader.h
#include <MyImportExport.h>
MYIMPORTEXPORT public int calculateSquare(int num)
{
return num*num;
}
в файле dll .cpp
#define SOME_CONDITION
#include <MyHeader.h>
в файле клиентского кода .cpp
#include <MyHeader.h>
Конечно, вам также необходимо сообщить компоновщику, что вы создаете dll с Параметр / DLL.
В процессе сборки также создается файл .lib, это статическая библиотека, в данном случае называемая заглушкой, на которую клиентский код должен ссылаться, как если бы он ссылался на настоящую статическую библиотеку. Автоматически dll загружается при запуске клиентского кода. Конечно, dll должна быть найдена ОС через механизм поиска, что означает, что вы не можете разместить dll где угодно, а только в определенном месте. Здесь больше об этом.
мусорная корзина - очень удобный инструмент для проверки того, правильно ли вы экспортировали функцию из dll и правильно ли импортирует код клиента. Запустите его с помощью / EXPORTS и / IMPORTS соответственно.
Вам необходимо экспортировать функцию, используя __declspec( dllexport ) или добавив функцию в файл определения модуля (.def). Затем скомпилируйте проект как DLL.
На стороне клиента у вас есть два варианта. Либо используйте библиотеку импорта (.lib), которая создается при компиляции DLL. Простое связывание с вашим клиентским проектом с помощью этой библиотеки предоставит вам доступ к функциям, экспортированным из DLL. И вам нужен файл заголовка, потому что компилятор должен знать сигнатуру вашей функции - что она возвращает int и принимает int. Напомним, вам нужно связать с библиотекой импорта (.lib) и файлом заголовка, который содержит заголовок вашей функции.
Другой способ - динамически загрузить DLL с помощью вызова WinAPILoadLibrary, а затем GetProcAddress для получения указателя на функцию. Указатель на функцию должен иметь правильный тип, чтобы компилятор мог дать ему правильные параметры и использовать правильное соглашение о вызовах.
Ответ QBziZ достаточно правильный. См. Неуправляемые библиотеки DLL в C++
Для его завершения: В C++, если вам нужно использовать символ, вы должны сообщить компилятору, что он существует, и часто его прототип.
На других языках компилятор просто исследует библиотеку самостоятельно и найдет символ и вуаля.
В C++ вы должны сообщить об этом компилятору.
Лучше всего разместить необходимый код в каком-нибудь общем месте. «Интерфейс», если хотите. Обычно это делается в файле заголовка, который называется заголовком, потому что обычно это не независимый исходный файл. Заголовок - это только файл, цель которого - включить (т.е. скопировать / вставить препроцессором) в настоящие исходные файлы.
По сути, кажется, что вам нужно дважды объявлять символ (функцию, класс и т. д.). Это почти ересь по сравнению с другими языками.
Вы должны увидеть его как книгу со сводной таблицей или указателем. В таблице у вас есть все главы. В тексте у вас есть главы и их содержание.
А иногда вы просто счастливы, что у вас есть список глав.
В C++ это заголовок.
Итак, вернемся к проблеме DLL: цель DLL - экспортировать символы, которые будет использовать ваш код.
Таким образом, для C++ вы должны как экспортировать код при компиляции (например, в Windows, использовать __declspec), так и «публиковать» таблицу экспортируемых данных (т.е. иметь «общедоступные» заголовки, содержащие экспортированные объявления). .
Контрольный список для экспорта функций:
На MSVC:
__stdcall (который является паскальским соглашением о вызовах) - это типичное соглашение о вызовах для экспортируемых символов, которое, я думаю, поддерживается большинством клиентов.__declspec(dllexport), чтобы отметить символ, который нужно экспортировать, или свяжите отдельный файл .def, в котором перечислены экспортируемые символы. С файлом .def вы также можете экспортировать только по порядковому номеру (не по имени) и изменить имя экспортируемого символа.