Как вызвать функцию из dll
Перейти к содержимому

Как вызвать функцию из dll

Вызов функций библиотек DLL из приложений Visual Basic

Для вызова функций на C или C++ из библиотеки DLL в приложениях на Visual Basic (или других языках, таких как Pascal или Fortran) эти функции необходимо экспортировать с использованием правильного соглашения о вызовах без какого-либо декорирования имен компилятором.

__stdcall создает правильное соглашение о вызове для функции (вызываемая функция очищает стек, а параметры передаются справа налево), но декорирует ее имя. Поэтому если для экспортированной функции в библиотеке DLL используется __declspec(dllexport) , экспортируется декорированное имя.

Префикс __stdcall украшения имени символа с символом подчеркивания ( _ ) и добавляет символ с символом знака (@), за которым следует число байтов в списке аргументов (требуемое пространство стека). В результате функция, объявленная как:

int __stdcall func (int a, double b) 

декорируется как _func@12 в выходных данных.

Соглашение о вызовах C ( __cdecl ) декорирует имя как _func .

Чтобы получить декорированное имя, используйте /MAP. Использование __declspec(dllexport) приводит к следующим результатам:

  • Если функция экспортируется с помощью соглашения О вызове C, она удаляет ведущий символ подчеркивания ( __cdecl_ ) при экспорте имени.
  • Если экспортируемая функция не использует соглашение о вызовах C (например, __stdcall ), экспортируется декорированное имя.

Так как переопределить место, где происходит очистка стека, невозможно, необходимо использовать __stdcall . Чтобы отменить декорирование имен при использовании __stdcall , необходимо указать их в виде псевдонимов в разделе EXPORTS файла DEF. Вот пример для следующего объявления функции:

int __stdcall MyFunc (int a, double b); void __stdcall InitCode (void); 
EXPORTS MYFUNC=_MyFunc@12 INITCODE=_InitCode@0 

Для вызова библиотек DLL программам, написанными на Visual Basic, необходимо использовать прием с файлом DEF, описанный в этой статье. Если псевдоним задается в программе Visual Basic, использовать псевдонимы в файле DEF необязательно. Это можно сделать в программе Visual Basic, добавив предложение alias в оператор Declare.

Дополнительные сведения

  • Экспорт из библиотеки DLL
  • Экспорт из библиотеки DLL с использованием DEF-файлов
  • Экспорт из библиотеки DLL с использованием __declspec(dllexport)
  • Экспорт функций на языке C++ для использования в исполняемых модулях, исходный код которых написан на языке C
  • Определение подходящего способа экспорта
  • Внутренние имена

Как вызвать функцию из dll

Импортирование, или ‘обертка’ вызовов функций DLL

Существует два метода для импорта и загрузки функций из Dynamic Link Library (DLL). Первый метод (который широко обсуждается в данном документе), называется «неявной» (Implicit) загрузкой. Неявная загрузка включает в себя статическую загрузку DLL при запуске программы, и получение доступа к функциям через интерфейс объектного Паскаля. Данный метод должен использоваться в случае, если приложение полностью зависит от загрузки DLL для соответствующего функционирования. Другой метод доступа называется «явной» загрузкой, поскольку DLL загружается динамически по требованию. Этот метод требует дополнительного кодирования и должен использоваться, если приложению нужно работать в случае, даже если DLL не смогла правильно загрузиться.

Что такое «обертка» функциональных вызовов?

Обертка функции, или набора функций, состоит из объявлений в секции interface и кода в секции implementation (вместе со связанными константами или типами), которые соответствуют функции, или набору функций, импортируемых из DLL. Обертка является простой декларацией в паскалевском модуле, которая обеспечивает точку входа в DLL. В Delphi обертка представляет собой файл модуля, содержащий код объектного паскаля. Группа разработчиков Delphi уже создала для вас обертку функций и стандартных элементов управления Windows. Но иногда возникает необходимость создания обертки для вызовов функций dll, но это в Delphi не обернуто по случаю сугубой индивидуальности каждой DLL и входящих в нее функций.

Первым, и самым сложным шагом в данном процессе является получение информации о функциях. Один из лучших источников для получения документации об имеющихся (доступных) в DLL функций является World Wide Web. Начать поиск можно с MSDN, а если и там нет информации, то можно обратиться к многочисленным поисковым серверам, которые частенько находят нужную вам информацию. Для получения структуры вызовов функций ищите залоговочные файлы C++ в продуктах типа Borland C++ или MS Visual C++. Соглашения об вызовах и преобразованиях типов обычно способны разрешить конфликты и несовместимость вызовов между C++ и PASCAL. Хороший ресурс по вопросам совместимости между Delphi и C++ расположен на сайте Borland по адресу: http://www.borland.com/delphi/papers/brick.html.

После того, как вы нашли необходимый пример, или документацию об экспортируемых DLL функциях, то следующим шагом будет создание нового модуля. Интерфейс модуля будет содержать константы и типы, необходимые для вызова отдельных функций DLL, и заголовки самих функций. Данные заголовки функций являются объектно-паскалевским интерфейсом, позволяющим другим приложениям Delphi вызывать функции рассматриваемой DLL. Как только секция модуля interface будет завершена, следующей секцией будет implementation. Секция модуля implementation содержит объявления импортируемых внешних функций. Эти заголовки не идентичны тем, которые расположены в секции модуля interface (которые содержат реальные идентификаторы функций плюс другую важную информацию для реализации). Для получения дополнительной информации по этой теме обратитесь к топику «DLLs:accessing procedures and functions» справки помощи по Delphi 3.

  1. Поиск информации по Интернету показал, что функция BOB должна возвращать логическое значение и требует в качестве аргументов значения типа word и boolean.
  2. Создайте в Delphi новый файл модуля с именем ‘UseBob.pas’ (File|New и выберите unit)
  3. Следующая строка кода должна располагаться в секции interface нового модуля:

function BOB(Fire: Word; Dances: Boolean): Boolean; stdcall;
function BOB; external 'BLODGE';

Ниже приведен модуль с реализацией вызова функции BOB, инициализируемый при нажатии на кнопку:

unit UDLLTest; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private  public  end;  TBOB = function(Fire: Word; Dances: Boolean): Boolean; stdcall; var Form1: TForm1; implementation  procedure TForm1.Button1Click(Sender: TObject); var BOB: TBOB; hDLLInst: THandle; IsAlive, IsDancing: Boolean; Years: Word; begin  hDLLInst := LoadLibrary('BLODGE.DLL');  if (hDLLInst then raise exception.create('[Неудачный вызов LoadLibrary]');  try @BOB := GetProcAddress(hDLLInst, 'BOB'); if not assigned(BOB) then raise exception.Create('[Неудачный вызов GetProcAddress]'); Years := 25; IsDancing := True;  IsAlive := BOB(Years, IsDancing); finally  FreeLibrary(hDLLInst); end; end; end.

Вызов пользовательских функций из библиотек DLL

Вызов определяемых пользователем функций (UDF) с листа так же прост, как и вызов встроенных функций. Вы вводите функцию с помощью формулы ячейки. Однако в API C не существует предопределенных кодов функций для использования с обратными вызовами. Чтобы разрешить вызов определяемых пользователем функций, API C экспортирует функцию только XLL, функцию xlUDF . Первый аргумент функции — это имя функции в виде строки, а последующие аргументы — это те, которые обычно ожидает определяемая пользователем функция.

Список зарегистрированных функций надстроек XLL и команд можно получить с помощью функции xlfGetWorkspace с аргументом 44. Возвращается массив из трех столбцов, в котором столбцы представляют следующее:

  • Полный путь и имя XLL
  • Имя UDF или команды, экспортированных из XLL.
  • Строка кода возвращаемого значения и аргумента

Имя, экспортируемого из XLL, может не совпадать с зарегистрированным именем, по которому Excel знает определяемую пользователем функцию или команду.

Начиная с Excel 2007 функции средства анализа (ATP) полностью интегрированы, а API C имеет собственные перечисления для таких функций, как PRICE, xlfPrice. В более ранних версиях для вызова этих функций приходилось использовать xlUDF . Если надстройка должна работать с Excel 2003 и Excel 2007 или более поздними версиями и использует эти функции, следует определить текущую версию и вызвать функцию соответствующим образом.

Примеры

В следующем примере показана функция xlUDF , используемая для вызова функции ATP PRICE , если запущенная версия Excel — 2003 или более ранняя. Сведения о настройке глобальной переменной версии, например gExcelVersion12plus в этом примере, см. в разделе Обратная совместимость.

В этом примере используются функции Платформы TempNum, TempStrConst для настройки аргументов и Excel для вызова API C.

LPXLOPER TempNum(double d); LPXLOPER TempStrConst(const LPSTR lpstr); int cdecl Excel(int xlfn, LPXLOPER pxResult, int count, . ); double call_ATP_example(void) < XLOPER xPrice; int xl_ret_val; if(gExcelVersion12plus) // Starting in Excel 2007 < xl_ret_val = Excel(xlfPrice, &xPrice, 7, TempNum(39084.0), // settlement date 2-Jan-2007 TempNum(46706.0), // maturity date 15-Nov-2027 TempNum(0.04), // Coupon TempNum(0.05), // Yield TempNum(1.0), // redemption value: 100% of face TempNum(1.0), // Annual coupons TempNum(1.0)); // Rate basis Act/Act >else // Excel 2003- < xl_ret_val = Excel(xlUDF, &xPrice, 8, TempStrConst("PRICE"), TempNum(39084.0), // settlement date 2-Jan-2007 TempNum(46706.0), // maturity date 15-Nov-2027 TempNum(0.04), // Coupon TempNum(0.05), // Yield TempNum(1.0), // redepmtion value: 100% of face TempNum(1.0), // Annual coupons TempNum(1.0)); // Rate basis Act/Act >if(xl_ret_val != xlretSuccess || xPrice.xltype != xltypeNum) < // Even though PRICE is not expected to return a string, there // is no harm in freeing the XLOPER to be safe Excel(xlFree, 0, 1, &xPrice); return -1.0; // an error value >return xPrice.val.num; > 

Если вы вызываете функцию XLL, которая возвращает значение путем изменения аргумента на месте, функция xlUDF по-прежнему возвращает значение через адрес результата XLOPER/XLOPER12. Иными словами, результат возвращается как бы через обычную инструкцию return. Значение XLOPER/XLOPER12, соответствующее аргументу, используемому для возвращаемого значения, не изменено. Например, рассмотрим следующие две определяемые пользователем функции.

// Registered as "1E". Returns its argument incremented by 1. void WINAPI UDF_1(double *pArg) < *pArg += 1.0; >// Registered as "QQ". Returns its argument unmodified // unless it is a number, in which case it increments it // by calling UDF_1. LPXLOPER12 WINAPI UDF_2(LPXLOPER12 pxArg) < static XLOPER12 xRetVal; // Not thread-safe XLOPER12 xFn; xFn.xltype = xltypeStr; xFn.val.str = L"\005UDF_1"; Excel12(xlUDF, &xRetVal, 2, &xFn, pxArg); xRetVal.xltype |= xlbitXLFree; return &xRetVal; >

Когда UDF_2 вызывает UDF_1, значение pxArg остается неизменным после вызова Excel12, а значение, возвращаемое UDF_1 , содержится в xRetVal.

При выполнении большого количества вызовов к определяемой пользователем функции можно сначала оценить имя функции с помощью функции xlfEvaluate. Результирующее число, которое совпадает с идентификатором регистрации, возвращаемым функцией xlfRegister , можно передать вместо имени функции в качестве первого аргумента функции xlUDF . Это позволяет Excel быстрее находить и вызывать функцию, чем если ей приходится искать имя функции каждый раз.

См. также

  • Разрешение прерывания длительных операций пользователем
  • Функции API C, которые можно вызывать только из библиотеки DLL или XLL
  • Начало работы с пакетом SDK XLL для Excel

Как вызвать нужную функцию из DLL?

Здравствуйте! Осваиваю работу с dll , по вот этому полезному материалу: Как подключить к своей программе DLL -библиотеку Проблема вот какая: Есть несколько методов и все они находятся в dll . Как можно вызвать интересующий нас метод? Может к GetProcAddress прибавить смещение какое-то? Спасибо.

Отслеживать
371 1 1 золотой знак 5 5 серебряных знаков 13 13 бронзовых знаков
задан 29 авг 2013 в 16:52
2,596 8 8 золотых знаков 52 52 серебряных знака 104 104 бронзовых знака
Каких ещё методов? Пример — в студию!
29 авг 2013 в 17:51

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

29 авг 2013 в 18:01
@alexlz: слово «метод» позволяет подозревать, что ТС хочет работать с классом, описанным в DLL’ке.
29 авг 2013 в 18:20

progzdeveloper, а можно простой пример? Просто имя функции в dll и имя указателя на нее в исполняемом файле должны совпадать?

29 авг 2013 в 19:21

@Alerr: если функция написана и скомпилирована как чистый C — имена должны совпадать, кроме этого, функция должна быть экспортирована ( __declspec(dllexport) ). Почитайте тут. По поводу работы с классами через границы DLL — старшие товарищи не рекомендуют. (Это всё, конечно, относится к динамической загрузке DLL через LoadLibrary .)

29 авг 2013 в 22:27

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

При создании проекта в компиляторе укажите библиотека DLL. (в visual studio создать->проект->win32(или консоль) -> далее -> библиотека dll + пустой проект) далее вставить код

#include #include extern "C" __declspec(dllexport) void dll_function(int arg); extern "C" __declspec(dllexport) void dll_function(int arg) < std::cout LPCSTR func_name = "dll_function"; // название загружаемой функции FARPROC adresse_la_func = GetProcAddress(le_module, func_name); if(adresse_la_func!=0) < std::cout FreeLibrary(le_module); std::cout

Отслеживать
ответ дан 30 авг 2013 в 11:17
6,363 7 7 золотых знаков 49 49 серебряных знаков 102 102 бронзовых знака

C подключением и вызовом функций из dll разобрался, хотя что вот это GetModuleFileName(NULL, (LPTSTR)mod_name, size__); в вашем примере(извлекает путь к исполняемому файлу текущего процесса), что она сделает? Сейчас вопрос возник с листингом DUMPBIN. Содержание листинга не совсем понтно?

30 авг 2013 в 11:31

1)Это ничего, можно убрать. 2) Зачем вам этот листинг? Вы функцию получили? Вот и все что необходимо знать. Остальное уже не относится к вопросу.

30 авг 2013 в 12:59
Но а все же, если знаете. Или просто новый вопрос задать?
30 авг 2013 в 18:36

Продолжил разбираться и наткнулся на программу DUMPBIN, которая:

The Microsoft COFF Binary File Dumper (DUMPBIN.EXE) displays information about Common Object File Format (COFF) binary files. You can use DUMPBIN to examine COFF object files, standard libraries of COFF objects, executable files, and dynamic-link libraries (DLLs). Это отсюда: http://msdn.microsoft.com/en-us/library/c1h23y6c.aspx

alt text

Итак, я захотел посмотреть таблицу импорта библиотеки которую сам же и собрал. Вот что я увидел:

Где тут таблица импорта? Кроме имени функции, содержащейся в dll ничего не смог разобрать. Сколько переменных и какого типа она принимает, что возвращает функция, если вообще что-то возвращает? На эти вопросы можно по этой картинке ответить? Что такое Summary, что за цифры? Цифры 0 00011005-это смещение в памяти по которому будет расположен указатель на функцию, по которому вызывается функция? Что за характеристики и 00000000? И прочие цифры типа 1 ordinal base что означают? Что за порядок? Расшифруйте кто может)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *