Как правильно создавать DLL на C++

Как видно из названия, в этом посте я расскажу о том, как создать DLL на C++ наиболее удобным и практичным способом, чтобы функции, помещенные туда, можно было легко и свободно использовать в других программах.

Как наверное многим известно, чтобы после компиляции создалась DLL, а не exe-файл, достаточно указать в настройках компиляции, что мы хотим получить именно Dynamic Link Library. Однако, не все так просто. По крайней мере, при использовании языка C/C++ и если нам нужно, чтобы потом нашим творением (нашей DLL) могли спокойно пользоваться другие разработчики, которые, ко всему прочему, могут использовать и другие компиляторы для сборки exe-файла.

Для этого функцию надо объявить как экспортируемую из DLL. Делается это с помощью добавления слева от функции модификатора extern «C». В итоге, функция будет выглядеть примерно так:

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, если таковой кому-либо потребуется, будет дан в одной из следующих статей.

Полезная статья? Их будет больше, если вы поддержите меня!

https://money.yandex.ru/embed/small.xml?account=410011399843532&quickpay=small&yamoney-payment-type=on&button-text=06&button-size=l&button-color=orange&targets=%D0%9F%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D0%B2%D0%B0%D1%8E+%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82+lexpenz.com&default-sum=50&successURL=