Перегруженные функции в C ++ DLL-файле определения - PullRequest
9 голосов
/ 25 августа 2008

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

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

Ответы [ 6 ]

11 голосов
/ 25 августа 2008

Перегрузка функций - это функция 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.

9 голосов
/ 25 августа 2008

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

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

8 голосов
/ 05 декабря 2008

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

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

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

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

  2. Если вы объявляете функцию для использования __stdcall соглашение (как это делается для многих функций API) затем

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

    будет экспортировать искаженное имя как _Foo @ 4. В этом случае вам может понадобиться явно отобразить экспортированное имя на внутреннее искаженное имя.

A. Как экспортировать незаписанное имя. В файле .def добавьте

----
EXPORTS
    ; Explicit exports can go here

    Foo
-----

Это попытается найти «лучшее соответствие» для внутренней функции Foo и экспортировать ее. В случае выше, где есть только один фу это создаст отображение

Foo = _Foo @ 4

как можно увидеть на свалке / EXPORTS

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

----
EXPORTS
    ; Explicit exports can go here

    Foo=_Foo@4
-----

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

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

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

3 голосов
/ 27 августа 2008

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

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

2 голосов
/ 21 марта 2013

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 голосов
/ 25 августа 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...