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

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

  • автор:

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

Явный вызов функций DLL несколько утомителен, зато дает Вашей программе настоящий полный контроль за работой DLL. Вы можете спокойно определить есть ли DLL и вообще есть ли в ней соответствующая функция. Давайте посмотрим как это делается. Сначала нам надо получить указатель на DLL — это делает функция LoadLibrary():

HMODULE LoadLibrary ( LPCTSTR lpLibFileName // имя модуля );

Она может завершиться как успешно, так и нет. Если успешно, то вернет указатель на DLL. Что она сделает ? Она поищет DLL. Еcли найдет, то загрузит ее в память и вернет Вам указатель. Так как DLL загружается в память Вы не можете просто так ее бросить, Вам надо ее выгрузить, а для этого есть функция FreeLibrary(), которая как раз сообщит Windows, что данная программа DLL больше не использует. Вообще за загрузку и выгрузку DLL отвечает Windows, так как DLL может использоваться несколькими программами. Вы просто говорите, что программа начинает использовать DLL (LoadLibrary) и заканчивает (FreeLibrary), а OC сама разбирается надо грузить ее в память или наоборот убирать, так как никто не использует ее. Вот пример:

// TestDLL.cpp : Defines the entry point for the console application. // #include «stdafx.h» #include «windows.h» #include «iostream.h» void main() < HINSTANCE hModule=NULL; hModule=::LoadLibrary("user32.dll"); if (hModule!=NULL) < ::FreeLibrary(hModule); >else cout

Как только мы получили указатель на DLL мы можем получить адрес функции по имени функции. Естественно нам имя нужно знать. Сначала надо объявить прототип функции typedef BOOL (WINAPI MESS)(UINT);. Обратите внимание, что я явно указал тип вызова WINAPI, что означает _stdcall так как С++ использует _cdecl, который не совместим с WIN32 API. Объявив прототип я могу создать указатель на функцию, а потом воспользовавшись GetProcAddress() получить функцию и уже ее вызывать.

// TestDLL.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "windows.h" #include "iostream.h" void main() < HINSTANCE hModule=NULL; typedef BOOL (WINAPI MESS)(UINT); MESS* me=NULL; hModule=::LoadLibrary("user32.dll"); if (hModule!=NULL) < me=(MESS*)::GetProcAddress((HMODULE)hModule,"MessageBeep"); if (me!=NULL) < UINT type=1; BOOL result; result=(*me)(type); >else cout else cout 

Внимание . Тщательно следите на типом вызова функций. Win32 пользуется методом вызова функций PASCAL - _stdcall, а VC методом вызова C, а в Windows стандарт вызова функций PASCAL. Разница этих методов в помещении параметров в стек. Будет время напишу подробнее. Просто помните об этом. Свои DLL Вы можете вызывать без WINAPI, а вот чужие надо знать, если стандартный API, то WINAPI, иначе надо выяснять. Как ?? Просто получаете ошибку вызова, если ошибетесь :-)

Вызов пользовательских функций из библиотек 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 из приложений 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-ка. И есть пример на VB6.0 использования этой dll. dll- не COM-сервер.
Мне в итоге нужно используя jni вызывать эту dll из java.
Но как вызвать эту dll из c++, что бы написать jni-обертку?

  • Вопрос задан более трёх лет назад
  • 612 просмотров

1 комментарий

Оценить 1 комментарий

Александр Коробов @superbadlam Автор вопроса
Илья: Я чутка старше, но впечатление такое же.
Решения вопроса 1
C/C++ programmer

Загружаете DLL, находите нужные вам функции и вызываете их 🙂
Очень схематично как-то так:

// указатель на функцию, которая принимает параметр char* и возвращает int typedef int (__cdecl *_your_function)(char *auth_st); _your_function YourFunction; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) < HINSTANCE hLib = LoadLibrary("Path_to_DLL"); YourFunction = (_your_function)GetProcAddress((HMODULE)hLib, "Your_Function_name"); if(YourFunction == NULL) < //something wrong >int res = YourFunction ("some string"); >

Ответ написан более трёх лет назад
Нравится 3 4 комментария
Владимир Мартьянов @vilgeforce

Только загрузку DLL тоже было бы неплохо проверять и WinMain не обязателен, все эти параметры все равно не используются 😉

Владимир Мартьянов: поэтому я и написал, что все это "очень схематично"
Александр Коробов @superbadlam Автор вопроса
Спасибо. Видать это то, что нужно. Пошел читать про указатели на функции.

Таблицу экспортируемых dll функций, кстати, показывает утилита depends.exe. Также надо учесть, что если функция именно C++ (а не С), то там есть весьма своеобразное изменение (т.н. декорирование) имен.

Ответы на вопрос 1
Александр Коробов @superbadlam Автор вопроса
Единственное, что в моем случае в объявлении

typedef int (__cdecl *_your_function)(char *auth_st);

заменил __cdecl* на __stdcall*

и все заработало.

Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

java

  • Java
  • +1 ещё

Как обеспечить корректность изменения статусов для записей?

  • 1 подписчик
  • 42 минуты назад
  • 10 просмотров

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

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