Перегруженные функции в файле определения C++ DLL
Вопрос
Я пишу DLL C/C++ и хочу экспортировать определенные функции, которые я сделал перед использованием такого файла .def.
LIBRARY "MyLib"
EXPORTS
Foo
Bar
с кодом, определенным следующим образом, например:
int Foo(int a);
void Bar(int foo);
Однако что, если я хочу объявить перегруженный метод Foo(), например:
int Foo(int a, int b);
Поскольку файл def содержит только имя функции, а не полный прототип, я не понимаю, как он будет обрабатывать перегруженные функции.Вы просто используете одну запись, а затем указываете, какую перегруженную версию вы хотите, при передаче правильно прототипированного указателя функции в LoadLibrary() ?
Редактировать:Чтобы внести ясность, это в Windows с использованием Visual Studio 2005.
Редактировать:В качестве ответа отмечен метод без определения (__declspec)... Я знаю, что на самом деле это не решает проблему с использованием файлов def, как я хотел, но похоже, что (официального) решения с использованием файлов def, скорее всего, не существует.Однако оставим вопрос открытым, если кто-то что-то знает, у нас нет перегруженных функций и файлов def.
Решение
В самом коде отметьте функции, которые хотите экспортировать, с помощью __declspec(dllexport).Например:
#define DllExport __declspec(dllexport)
int DllExport Foo( int a ) {
// implementation
}
int DllExport Foo( int a, int b ) {
// implementation
}
Если вы сделаете это, вам не нужно будет перечислять функции в файле .def.
Альтернативно вы можете использовать значение параметра по умолчанию, например:
int Foo( int a, int b = -1 )
Предполагается, что существует значение для b, которое можно использовать, чтобы указать, что оно не используется.Если -1 является допустимым значением для b или значение по умолчанию отсутствует или не должно быть, это не сработает.
Редактировать (Адам Хейл):Исправлено использование __declspec, поскольку __dllspec было неправильным, поэтому я мог пометить это как официальный ответ... это было достаточно близко.
Редактировать (Грэм):Ой, спасибо, что исправили мою опечатку!
Другие советы
Перегрузка функций — это функция C++, основанная на искажении имен (загадочных именах функций в сообщениях об ошибках компоновщика).
Записав искаженные имена в файл def, я могу подключить и запустить свой тестовый проект:
LIBRARY "TestDLL"
EXPORTS
?Foo@@YAXH@Z
?Foo@@YAXHH@Z
кажется, работает на
void Foo( int x );
void Foo( int x, int y );
Поэтому скопируйте имена функций C++ из сообщения об ошибке и запишите их в свой файл def.Однако реальный вопрос заключается в следующем:Почему вы хотите использовать файл def, а не использовать __declspec(dllexport)?
Искаженные имена непереносимы, я тестировал их с помощью VC++ 2008.
У меня была похожая проблема, поэтому я тоже хотел написать об этом.
Обычно используют
extern "C" __declspec(dllexport) void Foo();
экспортировать имя функции — это нормально.Это будет обычно Экспортируйте имя без необходимости в файле .def.Однако есть некоторые исключения, такие как функции __stdcall и перегруженные имена функций.
Если вы объявите функцию использования соглашения __stdcall (как это сделано для многих функций API), тогда
extern "C" __declspec(dllexport) void __stdcall Foo();
Экспортируется изуродованным именем, как _foo@4.В этом случае вам может потребоваться явно отобразить экспортированное имя во внутреннее изуродованное имя.
А.Как экспортировать неискаженное имя.В файле .def добавьте
----
EXPORTS
; Explicit exports can go here
Foo
-----
Это попытается найти «лучшее соответствие» для внутренней функции Foo и экспортировать ее.В приведенном выше случае, где есть только один Foo, это создаст картирование
Фу = _Foo@4
как можно увидеть через dumpbin/EXPORTS
Если вы перегрузили имя функции, вам, возможно, потребуется явно сказать, какую функцию вы хотите в файле .def, указав искаженное имя, используя синтаксис InternalName].например
----
EXPORTS
; Explicit exports can go here
Foo=_Foo@4
-----
Б.Альтернативой файлам .def является то, что вы можете экспортировать имена «на месте», используя #pragma.
#pragma comment(linker, "/export:Foo=_Foo@4")
С.Третий вариант — объявить только одну версию Foo как extern «C» для экспорта в неизмененном виде.Видеть здесь для получения подробной информации.
Официального способа сделать то, что вы хотите, не существует, поскольку интерфейс dll — это C API.
Сам компилятор использует искаженные имена в качестве обходного пути, поэтому вам следует использовать искажение имен, если вы не хотите слишком много менять в своем коде.
Не существует независимого от языка или версии способа экспорта перегруженной функции, поскольку соглашение об изменении может меняться с каждой версией компилятора.
Это одна из причин, почему большинство функций WinXX имеют забавные имена, например *Ex или *2.
Определение Systax для ЭКСПОРТА:
entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]
имя записи — это имя функции или переменной, которую вы хотите экспортировать.Это необходимо.Если имя, которое вы экспортируете, отличается от имени в DLL, укажите имя экспорта в DLL с внутренним именем.
Например, если ваша DLL экспортирует функцию func1() и вы хотите, чтобы она использовалась как func2(), вы должны указать:
EXPORTS
func2=func1
Просто просмотрите искаженные имена (с помощью Dependency Walker) и укажите собственное имя функции.
Источник: http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx
Редактировать:Это работает для динамических DLL, где нам нужно использовать GetProcAddress() для явного получения функций из Dll.