Создание DLL для использования с другими средствами разработки (отличными от Visual C++)
Если Вы используете Visual С++ для сборки как DLL, так и обращающегося к ней EXE-файла, то все сказанное ранее справедливо, и Вы можете спокойно пропустить этот раздел. Но если Вы создаете DLL на Visual С++, а ЕХЕ-файл — с помощью средств разработки от других поставщиков, Вам не миновать дополнительной работы.
Я уже упоминал о том, как применять модификатор extern при "смешанном" программировании на С и С++. Кроме того, я говорил, что из-за искажения имен нужно применять один и тот же компилятор. Даже при программировании на стандартном С инструментальные средства от разных поставщиков создают проблемы. Дело в том, что компилятор Microsoft С, экспортируя С-функцию, искажает eе имя, даже если Вы вообще не пользуетесь С++. Это происходит, только когда Ваша функция экспортируется по соглашению __stdcall. (Увы, это самое популярное соглашение.) Тогда компилятор Microsoft искажает имя С-функции. впереди ставит знак подчеркивания, а к концу добавляет суффикс, состоящий из символа @ и числа байтов, передаваемых функции в качестве параметров. Например, следующая функция экспортируется в таблицу экспорта DLL как _MyFunc@8:
__declspec(dllexport) LONG __stdcall MyFunc(int a, int b);
Если Вы решите создать ЕХЕ-файл с помощью средств разработки от другого поставщика, то компоновщик попытается скомпоновать функцию MyFunc, которой нет в файле DLL, созданном компилятором Microsoft, и, естественно, произойдет ошибка.
Чтобы средствами Microsoft собрать DLL, способную работать с инструментарием от другого поставщика, нужно указать компилятору Microsoft экспортировать имя функции без искажений. Сделать это можно двумя способами. Первый — создать DEF-файл для Вашего проекта и включить в него раздел EXPORTS так:
EXPORTS MyFunc
Компоновщик от Microsoft, анализируя этот DEF-файл, увидит, что экспортировать надо обе функции: __MyFunc@8 и MyFunc. Поскольку их имена идентичны (не считая вышеописанных искажений), компоновщик на основе информации из DEF-файла экспортирует только функцию с именем MyFunc, а функцию _MуFипс@8 не экспортирует вообще.
Может, Вы подумали, что при сборке ЕХЕ-файла с такой DLL компоновщик от Microsoft, ожидая имя _MyFunc8, не найдет Вашу функцию? В таком случае Вам будет приятно узнать, что компоновщик все сделает правильно и корректно скомпонует ЕХЕ-файл с функцией MyFunc.
Если Вам не по душе DEF-файлы, можете экспортировать неискаженное имя функции еще одним способом. Добавьте в один из файлов исходного кода DLL такую строку:
#pragma comment(linker, "/export:MyFunc=_MyFunc@8")
Тогда компилятор потребует от компоновщика экспортировать функцию MyFunc с той же точкой входа, что и _MyFunc@8. Этот способ менее удобен, чем первый, так как здесь приходится самостоятельно вставлять дополнительную директиву с искаженным именем функции. И еще один минус этого способа в том, что из DLL экспортируется два идентификатора одной и той же функции MyFunc и _МуFипс@8, тогда как при первом способе — только идентификатор MyFunc. По сути, второй способ не имеет особых преимуществ перед первым — он просто избавляет от DEF-файла.