Что означает «Экспорт функции из DLL»? - PullRequest
2 голосов
/ 21 декабря 2009

Я не знаю много о DLL. Я читаю книгу по COM. В котором автор ссылается на что-то Exporting a function from a DLL. Он рассказывает, как это сделать, но не говорит, что это и зачем это нужно делать?

Метод, который он предлагает: а) пометить функцию с extern "C" (не знаете почему?) б) создать файл DEF и добавить имена функций в разделе EXPORTS этого файла DEF. опять же, понятия не имею, почему и что именно там происходит?

Еще одна вещь, которую я не понимаю, это термин symbols / symbol table.

  1. Что означает Exporting a function from a DLL?
  2. Что такое symbols / symbol table?

Буду признателен, если кто-нибудь сможет объяснить мне простые, ясные и подробные термины. Любые веб-ссылки или учебники также приветствуются.

EDIT:

Я использовал DLL в .NET. В который я просто включаю использование строки пространства имен и добавляю dll к ссылкам, и они работают. Это единственный способ, которым я знаю, как использовать dll. Я не знаю, как использование DLL в .net отличается от использования их в COM. Может ли кто-нибудь также относиться к .NET?

Ответы [ 6 ]

8 голосов
/ 21 декабря 2009

DLL в .NET довольно сильно отличаются от собственных DLL. .NET DLL содержат байт-код, называемый CIL, который содержит достаточно информации для других программ, таких как компилятор csc, для разработки классов, типов, интерфейсов и т. Д., Содержащихся в нем.

Это сильно отличается от собственных DLL. Собственные библиотеки DLL содержат двоичные инструкции и в основном неструктурированные данные, и нет (в общем) способа выяснить, что означают данные - например, где-то в библиотеке DLL могут быть два байта (в шестнадцатеричном формате) 43 23 и нет никакого способа определить, будет ли программа интерпретировать их как символы C# или как целое число 17187, или адрес памяти, или даже инструкцию для подачи в CPU.

Итак, перейдем к вашим вопросам:

  1. symbol table - это часть метаданных для DLL; он сообщает компилятору / компоновщику, как преобразовать void myDllFunc (int bar) в адрес в DLL. Это в основном справочная таблица. Экспорт функций из DLL - это то, как вы указываете , какие функции вы хотели бы получить в этой справочной таблице - это те функции, которые другой код сможет вызывать, потому что он сможет найти их. Помните - без другой информации невозможно определить , откуда начинается myDllFunc.
  2. extern C рекомендуется из-за процесса разрешения имен и, в частности, из-за того, как C ++ обрабатывает перегрузку функций. Когда у вас есть две функции:
int square (int x);
double square (double x);

компилятору нужен какой-то способ их различения - имя «квадрат» теперь неоднозначно и не может быть разрешено в один адрес кода. C ++ обрабатывает это с помощью искажения имени - компилятор берет имя вашей функции, square, а затем добавляет несколько магических строк, соответствующих типам в сигнатуре функции. Так, например, компилятор может видеть ваши две функции как:

int int+square+int (int x);
double dbl+square+dbl (double x);

и они больше не являются двусмысленными (реальные компиляторы не используют такую ​​простую схему). Здесь есть две проблемы:

  1. Вы хотите называть эту функцию "квадратом", а не "int + square + int", и, что еще хуже,
  2. Различные компиляторы C ++ используют разные правила преобразования имен.

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

Изменить для адреса комментариев: Объявление сигнатур функций extern C решает проблему искажения имени, поскольку в C нет искажения имени. C может обойтись без искажения имени, потому что объявляет две функции

int square (int x);
double square (double x);

- это ошибка ; компилятор / компоновщик не должен - и не будет - обрабатывать эту неоднозначность.

Exporting a function from a DLL - это не что иное, как добавление функции в таблицу символов. Это позволяет коду вне вашей DLL вызывать функцию, потому что теперь внешний код может искать, где запускается функция. Таким образом, функция «экспортируется», так что другие люди могут вызывать ее.

4 голосов
/ 21 декабря 2009

Правильно объявленная экспортируемая функция будет выглядеть так:

extern "C" __declspec(dllexport)
void __stdcall Foo() {
  // etc...
}

Деклараторы, по порядку, делают это:

  • extern "C" подавляет оформление имени в C ++. На 32-разрядной машине экспортируемое имя будет _Foo @ 0, маршаллер P / Invoke без проблем найдет такое имя. Без этого экспортируемое имя будет? Foo @@ YGXXZ. Маршаллер не может найти такое имя, вам нужно использовать свойство EntryPoint в атрибуте [DllImport], чтобы помочь ему. C ++ декорирует такие имена, чтобы поддерживать перегрузку методов и безопасное соединение типов.
  • __declspec(dllexport) - подсказка компоновщику о размещении функции в таблице экспорта DLL. Он делает то же самое, что и файл .DEF, без необходимости поддерживать такой файл.
  • __stdcall устанавливает соглашение о вызовах, способ передачи аргументов в функцию. 32-битный код имеет 5 возможных соглашений о вызовах (__cdecl, __stdcall, __fastcall, __thiscall, __clrcall). Почти все внешние программы используют __stdcall по умолчанию, включая маршаллер P / Invoke. Однако по умолчанию для кода C / C ++ __cdecl. DllImportAttribute.CallingConvention доступна для переопределения по умолчанию на управляемой стороне.

Ваш основной инструмент для устранения неполадок такого рода - Dumpbin.exe. Запустите его из командной строки Visual Studio в вашей DLL с параметром / exports. В нем перечислены имена функций, найденных в таблице экспорта DLL.

Вы упомянули COM, это совершенно другая история. COM-сервер не экспортирует свои функции, он использует «фабрику классов» [sic]. Внутрипроцессный сервер экспортирует только 4 функции:

  • DllRegisterServer. Используется Regsvr32.exe для регистрации сервера в реестре.
  • DllUnregisterServer. Как и выше, используется для удаления регистрации.
  • DllCanUnloadNow. Периодически вызывается системой COM для проверки того, что сервер больше не нужен и может быть выгружен из памяти.
  • DllGetClassObject. Это важный, он вызывается COM, когда клиент вызывает CoCreateObject (). COM-сервер реализует это, создав COM-класс COM и вернув указатель интерфейса на запрошенный интерфейс. Какой COM-клиент затем использует для вызова методов интерфейса. Указатель интерфейса указывает на список адресов функций, реализованных интерфейсом, так же, как интерфейс работает в .NET.

Создание этих 4 экспортируемых функций очень часто является задачей любой библиотеки классов, которую вы используете для реализации COM-сервера. Оружие выбора в C ++ - ATL.

4 голосов
/ 21 декабря 2009

Экспорт функции из DLL просто означает, что потребители DLL смогут вызывать эту функцию.

Концептуально это похоже на добавление функции к «интерфейсу», предоставляемому DLL.

Таблица символов представляет собой таблицу, содержащую эти функции экспорта, их Имя, ID и адрес.

Попробуйте это: http://msdn.microsoft.com/en-us/library/z4zxe9k8(VS.80).aspx

2 голосов
/ 21 декабря 2009
  1. DLL - это, в первом приближении, набор функций, которые делают интересные вещи. Некоторые из этих функций предназначены для пользователя DLL, другие используются внутри других функций, и автор не намеревается предоставить пользователю DLL доступ. После того, как вы решите, какие функции внутри вашей DLL должны видеть пользователи DLL, вы делаете их видимыми, экспортируя их.
  2. Символы - это имена, данные функциям и другим объектам в двоичном файле (DLL, EXE и т. Д.). Таблицы символов - это структуры данных внутри двоичных файлов, которые хранят коллекции этих имен и предоставляют компоновщикам и другим инструментам сопоставление имени с именованным BLOB-объектом.

Вы можете увидеть экспортированные функции либо с помощью утилиты dumpbin, поставляемой с VS, либо (намного проще) с помощью средства depen.exe, которое вы можете загрузить здесь .

2 голосов
/ 21 декабря 2009

Каждый файл .dll имеет зону обслуживания, в которой хранятся имена экспортируемых функций и адреса их реализаций - это называется таблицей символов. Когда приложение-потребитель хочет вызвать функцию из DLL-файла, он вызывает LoadLibrary (), а затем GetProcAddress (), чтобы найти адрес функции. Таблица символов используется для облегчения поиска. Если функция не находится в этой таблице, GetProcAddress () не найдет ее и приложение-потребитель не сможет вызвать ее.

0 голосов
/ 30 августа 2018

Просто добавьте 2с, так как мне было трудно выучить эту концепцию «Экспорт функций из DLL» как носитель английского языка.

Когда вы заявляете что-то с __declspec(dllexport) по сути, это означает, что определение функции идет в DLL, а не из нее. Я до сих пор не могу понять, почему люди используют «Экспорт функций из DLL», а не «Экспорт функций в DLL»

«Экспортировать А в Б» означает, что А собирается на Б. «Импорт A из B» означает, что A происходит из B. Но «Экспортировать А из Б» я действительно не знаю.

...