Перегруженные функции в файле определения 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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
0
13 284
6
Перейти к ответу Данный вопрос помечен как решенный

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

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

что, если мы используем GetProcAddress () с динамической DLL?

null 21.03.2013 10:07

Затем вам нужно использовать искаженные имена или переименовать одну из функций и сделать их обе extern "C", предполагая, что ни одна из них не принимает или не возвращает объекты C++.

Graeme Perrow 21.03.2013 23:17

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

Интересный подход. Под непереносимым вы имеете в виду разные версии Visual Studio? Что может подсказать, что они, возможно, меняют свои схемы искажения названия между версиями?

jxramos 21.10.2015 01:03

@jxramos Я не уверен, действительно ли они могут изменить схему искажения имен. Но я сомневаюсь, что это будет работать таким же образом при переключении на другой компилятор, если только этот компилятор не попытается имитировать поведение VC.

Timbo 21.10.2015 10:31

Это, конечно, только VC++, поскольку я не думаю, что другие компиляторы используют файлы def. Кроме того, если я помню, что кто-то однажды сказал мне, это то, что у Microsoft есть идея интерфейса dll, в которой элементы, выбранные пользователем, открываются публично через файл def или __declspec, тогда как в Unix с их файлами * .so все с общедоступным API отображается. У них нет разницы между логическим публичным API и публичным API библиотеки.

jxramos 21.10.2015 22:42

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

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

интересный фон с комментарием WinXX!

jxramos 21.10.2015 01:06

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

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

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

  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 и экспортировать его. В случае выше, когда есть только one foo это создаст отображение

Foo = _Foo @ 4

как видно через dumpbin / 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», которая будет экспортироваться без перепутывания. Подробнее см. здесь.

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

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.

Другие вопросы по теме