logo
Лаба6

5. Создание dll модуля

При использовании 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, а функцию _MyFunc@8 не экспортирует вообще.

Если Вам не по душе DEF-файлы, можете экспортировать неискаженное имя функции еще одним способом. Добавьте в один из файлов исходного кода DLL такую строку:

#pragma comment(linker, "/export:MyFunc=_MyFunc@8")

Тогда компилятор потребует от компоновщика экспортировать функцию MyFunc с той же точкой входа, что и _MyFunc@8. Этот способ менее удобен, чем первый, так как здесь приходится самостоятельно вставлять дополнительную директиву с искаженным именем функции. И еще один минус этого способа в том, что из DLL экспортируется два идентификатора одной и той же функции MyFunc и _MyFunc@8, тогда как при первом способе — только идентификатор MyFunc. По сути, второй способ не имеет особых преимуществ перед первым — он просто избавляет от DEF-файла.