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

Я пишу C / C ++ DLL и хочу экспортировать определенные функции, которые я делал до использования файла .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

Редактировать: помеченный как не-def (__declspec) метод в качестве ответа ... Я знаю, что на самом деле это не решает проблему с использованием def-файлов, как я хотел, но, похоже, нет (официального) решения с использованием def-файлов. Однако оставим вопрос открытым, если кто-то что-то знает, у нас нет перегруженных функций и файлов def.

25.08.2008 14:22:21
6 ОТВЕТОВ
РЕШЕНИЕ

В самом коде отметьте функции, которые вы хотите экспортировать, используя __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 был неверным, поэтому я мог пометить это как официальный ответ ... он был достаточно близок.

Редактировать (Грэм): Ой - спасибо за исправление моей опечатки!

10
25.08.2008 16:53:38
Что делать, если мы используем GetProcAddress () с динамической DLL?
null 21.03.2013 06:07:13
Затем вам нужно использовать искаженные имена или переименовать одну из функций и сделать их обе extern "C", предполагая, что ни одна из них не принимает и не возвращает объекты C ++.
Graeme Perrow 21.03.2013 19:17:39

Перегрузка функций - это функция C ++, которая полагается на искажение имен (загадочные имена функций в сообщениях об ошибках компоновщика).

Записав искаженные имена в файл def, я могу заставить свой тестовый проект связать и выполнить:

LIBRARY "TestDLL"
EXPORTS
    ?Foo@@YAXH@Z
    ?Foo@@YAXHH@Z

кажется, работает на

void Foo( int x );
void Foo( int x, int y );

Поэтому скопируйте имена функций C ++ из сообщения об ошибке и запишите их в файл определения. Однако реальный вопрос заключается в следующем: почему вы хотите использовать файл def, а не использовать __declspec (dllexport)?

Искаженные имена непереносимы, я тестировал с VC ++ 2008.

11
25.08.2008 14:42:03
Интересный подход. Под непереносимым вы подразумеваете разные версии Visual Studio? Что может предложить, чтобы они изменили свои схемы искажения имени между версиями, возможно?
jxramos 20.10.2015 22:03:51
@jxramos Я не уверен, могут ли они действительно изменить схему искажения имени. Но я сомневаюсь, что это будет работать точно так же при переключении на другой компилятор, если только этот компилятор не попытается эмулировать поведение VC.
Timbo 21.10.2015 07:31:16
Это, безусловно, только вещь VC ++, так как я не думаю, что другие компиляторы используют файлы def. Также, если я помню, что кто-то однажды сказал мне, что у Microsoft есть эта идея интерфейса dll, когда выбранные пользователем элементы открыты для публичного доступа, через файл def или __declspec, тогда как в Unix с их файлами * .so все с открытым API открыто. У них нет различия между логическим публичным API и публичным API библиотеки.
jxramos 21.10.2015 19:42:18

Не существует независимого от языка или версии способа экспорта перегруженной функции, поскольку соглашение о календаре может меняться с каждым выпуском компилятора.

Это одна из причин, почему большинство функций WinXX имеют забавные имена, такие как * Ex или * 2.

2
3.07.2012 15:02:24
интересный фон с комментарием WinXX!
jxramos 20.10.2015 22:06:16

Не существует официального способа делать то, что вы хотите, потому что интерфейс dll - это C api.

Сам компилятор использует искаженные имена в качестве обходного пути, поэтому вы должны использовать искажение имен, когда вы не хотите слишком сильно менять свой код.

3
27.08.2008 11:11:20

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

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

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

    экспортировать имя функции нормально. Это , как правило , экспортировать имя unmangled без необходимости .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 = _Foo @ 4

как можно увидеть через dumpbin / EXPORTS

Если вы перегрузили имя функции, вам может потребоваться явно указать, какую функцию вы хотите в файле .def, указав искаженное имя с использованием синтаксиса entryname [= internalname]. например

----
EXPORTS
    ; Explicit exports can go here

    Foo=_Foo@4
-----

Б. Альтернативой файлам .def является то, что вы можете экспортировать имена «на месте», используя #pragma.

#pragma comment(linker, "/export:Foo=_Foo@4")

C. Третий вариант - объявить только одну версию Foo как extern «C» для экспорта без изменений. Смотрите здесь для деталей.

8
4.12.2008 21:03:01

Systax для определения EXPORTS:

entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

entryname - это имя функции или переменной, которую вы хотите экспортировать. Это обязательно. Если экспортируемое имя отличается от имени в DLL, укажите имя экспорта в DLL с внутренним именем.

Например, если ваша DLL экспортирует функцию func1 () и вы хотите, чтобы она использовалась как func2 (), вы должны указать:

EXPORTS
func2=func1

Просто посмотрите искаженные имена (с помощью обходчика зависимостей) и укажите собственное имя функции.

Источник: http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx

Редактировать: это работает для динамических DLL, где нам нужно использовать GetProcAddress () для явного извлечения функций в Dll.

2
21.03.2013 06:15:10