Перегруженные функции в файле определения C++ DLL

StackOverflow https://stackoverflow.com/questions/26098

  •  09-06-2019
  •  | 
  •  

Вопрос

Я пишу 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.

У меня была похожая проблема, поэтому я тоже хотел написать об этом.

  1. Обычно используют

    extern "C" __declspec(dllexport) void Foo();
    

    экспортировать имя функции — это нормально.Это будет обычно Экспортируйте имя без необходимости в файле .def.Однако есть некоторые исключения, такие как функции __stdcall и перегруженные имена функций.

  2. Если вы объявите функцию использования соглашения __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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top