Как видно из названия, в этом посте я расскажу о том, как создать DLL на C++ наиболее удобным и практичным способом, чтобы функции, помещенные туда, можно было легко и свободно использовать в других программах.
Как наверное многим известно, чтобы после компиляции создалась DLL, а не exe-файл, достаточно указать в настройках компиляции, что мы хотим получить именно Dynamic Link Library. Однако, не все так просто. По крайней мере, при использовании языка C/C++ и если нам нужно, чтобы потом нашим творением (нашей DLL) могли спокойно пользоваться другие разработчики, которые, ко всему прочему, могут использовать и другие компиляторы для сборки exe-файла.
Для этого функцию надо объявить как экспортируемую из DLL. Делается это с помощью добавления слева от функции модификатора extern «C». В итоге, функция будет выглядеть примерно так:
1 2 3 4 |
extern "C" VOID CALLBACK MyFunction(HDC hdc, LPRECT prc) { } |
К слову вместо extern «C» можно (и наверное даже лучше) написать EXTERN_C. Именно так это выражение определено в WinNT.h.
Вы спросите, а в чем проблема? А проблема в том, что компилятор C++ искажает имена функций, при добавлении их в DLL, добавляя к её имени спереди символ подчеркивания и в конце – символ «@» и число байт, передаваемых функции в качестве параметра. Самое забавное, что этим же грешит Microsoft C, даже если не использовать при написании программы C++. И искажает он только имена функций, экспортирующихся по соглашению __stdcall, т.е. по тому же самому, что используется в WIN API.
Для того, чтобы гарантированно избежать проблем с искажением имен и вытекающими из нее, следует добавить к проекту *.def файл (обычный текстовый файл, но с расширением def), в котором указать примерно следующее:
LIBRARY «MyName»
EXPORTS
MyFunction
Где “dll” – имя нашей библиотеки, и после EXPORTS перечислены имена экспортируемых из нее функций.
Полный синтаксис .def файла выглядит так:
entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]
Где entryname – это имя функции или переменной, которую необходимо экспортировать. Если нужно, чтобы экспортируемое имя отличалось от имени функции, используемого в DLL, то следует указать сначала желаемое имя, а через равно – имя в DLL:
EXPORTS
func2=func1
@ordinal позволяет указать, что не номер, а имя функции попадет в таблицу экспорта библиотеки DLL.
Подробнее об остальных ключевых словах в файле .def можно прочитать в MSDN.
Там же рекомендуют использовать ключевое слово __declspec(dllexport) в коде. Однако, следует отметить, что тогда эти методы не смогут вызываться программами, написанными на чистом C, так что от extern “C” видимо не уйти.
PS: Пример кода с созданием DLL, если таковой кому-либо потребуется, будет дан в одной из следующих статей.
Полезная статья? Их будет больше, если вы поддержите меня!