Моё меню Общее меню Пользователи Правила форума Все прочитано
Вернуться   uForum.uz > ИКТ и телеком > IT-индустрия > Софт > Программирование > Другие языки программирования
Знаете ли Вы, что ...
...инструкция по установке аватара описана в Правилах форума.
<< Предыдущий совет - Случайный совет - Следующий совет >>

Другие языки программирования Здесь обсуждаются все, что касается JAVA, проблемы и задачи 1С,


Ответить

 
Опции темы Опции просмотра
Старый 27.06.2007 02:30   #1  
Аватар для cascada
Оффлайн
none
none
Сообщений: 51
+ 3  4/3
– 0  0/0

Uzbekistan
Экспорт функций из Dll

Всем привет.есть проблема:я не знаю как сделать так чтобы можно было бы вызвать функцию из длл подключённую при выполнении:

pointerOnFunction=GetProcAdress(hInstDll,"MyFuncti on");//не работает
//потому что присутствует мод CALLBACK
//который убирать нежелательно, нужен для использования
//в программах на других языках, приходиться делать так
pointerOnFunction=GetProcAdress(hInstDll,"_MyFunct ion@14");

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

спрашивал на других форумах ..что то молчат. подскажите а?если можно
киньте кодом, я не обижусь)))
Ответить 
Старый 04.07.2007 18:32   #2  
Real ID Group
Аватар для Aleksandr Vishinskiy
Оффлайн
Сообщений: 57
+ 3  9/6
– 0  0/0

Uzbekistan
GetProcAddress чувствительна к регистру, проверь правильно ли ты пишешь название своей функции.Выложи весь код с начала.
И на будующее пишите язык программирования по которому вопрос.
Ответить 
Старый 05.07.2007 01:37   #3  
Аватар для cascada
Оффлайн
none
none
Сообщений: 51
+ 3  4/3
– 0  0/0

Uzbekistan
Ну ты орёл Все Win32 функции чувствительны к регистру,за исключением функций предназначенных для приведения символов к верхнему регистру,например UpperChar(вроде бы она).
Показывать весь код не имеет смысла...дело не в нём.Хотя....

Код:
#include<windows.h>

int WINAPI DllMain(HINSTANCE hInst,DWORD fdwReason,PVOID pvReserved)
{
	return TRUE;
}
EXPORT BOOL CALLBACK MyFunction(HANDLE hThread)
{
TerminateThread(hThread);
Sleep(0);

if(CloseHandle(hThread))
return FALSE;

return TRUE;
}
В вызывающем модуле..

Код:
//инициализация окна и другие процедуры опущены,
//только оконная процедура

LRESULT CALLBACK WndProc   (HWND, UINT, WPARAM, LPARAM)
{
//только переменные по сути вопроса
HFUNC hFunc;
HANDLE hProc,hThread,hProcChild,hInstDll;

switch(iMsg)
{
//остальные кейсы опущены
case WM_COMMAND:
switch(LOWORD(wParam))
{
//остальные кейсы опущены
case IDM_CLOSETHREAD:
hInstDll=LoadLibrary("CloseThread.dll");    //отсюда и начинается      
                                                        //вопрос:а как сделать,чтобы 
                                                        //было 
                                    //pFunc=GetProcAdress(hInstDll,"MyFunction");
                                    //а не это :
pFunc=GetProcAdress(hInstDll,"_MyFunction@4");
if(!pFunc(hThread))
MessageBox(hwnd,"try again",szApp, MB_ICONEXCLAMATION|MB_OK);
return 0;
//остальные кейсы опущены
}
//остальные кейсы опущены
}
DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Подсказали использовать def файлы,но я понятия не имею что это такое и как их использовать.
Ответить 
Старый 05.07.2007 01:45   #4  
Аватар для cascada
Оффлайн
none
none
Сообщений: 51
+ 3  4/3
– 0  0/0

Uzbekistan
ой.....я забыл указать код завершения потока......но понятное дело, что это не имеет значения
Ответить 
Старый 05.07.2007 08:43   #5  
Real ID Group uParty Member
Аватар для Akmal Bafoev
Оффлайн
Сообщений: 1,521
+ 2,213  1,251/585
– 37  12/9

UzbekistanLiveJournal
сто лет ничего не писал под win32, но насколько я помню, _ всегда приписывается к имени функции написанной на чистом С перед помещением ее в .obj файл, это как смерть и налоги
Ответить 
Старый 05.07.2007 15:32   #6  
Real ID Group
Аватар для Mamurjon Jaloliddinov
Оффлайн
Сообщений: 23
+ 0  5/5
– 0  0/0

Uzbekistan
Post

раз уж ты пишеш на с++ не лучшели использовать неявное подключение dll и спользовать *.lib и *.h что на много удобнее, но раз решил подключать динамически то по науке делается так:


/////////////объявление в начале;
typedef BOOL (WINAPI *PFN_MyFunction) (HANDLE);
//------------------------------------------------------

/// загружаем библиотеку;
HINSTANCE hMyDll;
if((hMyDll=LoadLibrary(“MyDLL”))==NULL) return 1;
//если загрузка прошла успешно;
PFN_MyFunction pfnMyFunction;
pfnMyFunction=(PFN_MyFunction) GetProcAddress(hMyDll,”MyFunction”);
BOOL Code=(*pfnMyFunction)(hThread);
//освобождаем библиотеку;
FreeLibrary(hMyDll);


Если чё скину полный работоспособный исходник
Ответить 
Старый 06.07.2007 10:44   #7  
Аватар для cascada
Оффлайн
none
none
Сообщений: 51
+ 3  4/3
– 0  0/0

Uzbekistan
Цитата:
Сообщение от Mamurjon Jaloliddinov Посмотреть сообщение
раз уж ты пишеш на с++ не лучшели использовать неявное подключение dll и спользовать *.lib и *.h что на много удобнее, но раз решил подключать динамически то по науке делается так:


/////////////объявление в начале;
typedef BOOL (WINAPI *PFN_MyFunction) (HANDLE);
//------------------------------------------------------

/// загружаем библиотеку;
HINSTANCE hMyDll;
if((hMyDll=LoadLibrary(“MyDLL”))==NULL) return 1;
//если загрузка прошла успешно;
PFN_MyFunction pfnMyFunction;
pfnMyFunction=(PFN_MyFunction) GetProcAddress(hMyDll,”MyFunction”);
BOOL Code=(*pfnMyFunction)(hThread);
//освобождаем библиотеку;
FreeLibrary(hMyDll);


Если чё скину полный работоспособный исходник
Скинь исходник,очень интересно было бы посмотреть.......


Цитата:
Сообщение от Akmal Bafoev Посмотреть сообщение
сто лет ничего не писал под win32, но насколько я помню, _ всегда приписывается к имени функции написанной на чистом С перед помещением ее в .obj файл, это как смерть и налоги
............а вот и неправдабез мода _stdcall знак подчёркивания не приписывается к имени

pFunc=GetProcAdress(hInstDll,"MyFunction"); //вполне работоспособно

ну да ладно....что такое def файлы?и как поступить с ними в моём случае?
Ответить 
Реклама и уведомления
Старый 06.07.2007 12:27   #8  
Real ID Group
Аватар для Akrom Obidov
Оффлайн
AKA:Hitman
Сообщений: 102
+ 30  20/19
– 1  0/0

UzbekistanОтправить сообщение для Akrom Obidov с помощью ICQ
Цитата:
Сообщение от cascada Посмотреть сообщение
Скинь исходник,очень интересно было бы посмотреть.......



............а вот и неправдабез мода _stdcall знак подчёркивания не приписывается к имени

pFunc=GetProcAdress(hInstDll,"MyFunction"); //вполне работоспособно

ну да ладно....что такое def файлы?и как поступить с ними в моём случае?
Может целый урок провести по С++?


Раннее связывание (во время компиляции программы)


При таком методе связывания операционная система автоматически загружает DLL во время запуска программы. Однако требуется, чтобы в разрабатываемый проект был включен .lib файл (библиотечный файл), соответствующий данной DLL. Этот файл определяет все экспортируемые объекты DLL. Объявления могут содержать обычные функции C или классы. Все, что нужно клиенту - использовать этот .lib файл и включить заголовочный файл DLL - и ОС автоматически загрузит эту DLL. Как видно, этот метод выглядит очень простым в использовании, т.к. все прозрачно. Однако вы должны были заметить, что код клиента нуждается в перекомпиляции всякий раз, когда изменяется код DLL и, соответственно, генерируется новый .lib файл. Удобно ли это для вашего приложения - решать вам. DLL может объявить функции, которые она хочет экспортировать, двумя методами. Стандартный метод - использование .def файлов. Такой .def файл - это просто листинг функций, экспортируемых из DLL.
//================================================== ==========
// .def файл
LIBRARY myfirstdll.dll
DESCRIPTION 'My first DLL'
EXPORTS MyFunction
//================================================== ==========
// заголовок DLL, который будет включен в код клиента
bool MyFunction(int parms);
//================================================== ==========
// реализация функции в DLL
bool MyFunction(int parms)
{
// делаем все, что нужно
............
}
Я думаю, можно не говорить, что в данном примере экспортируется только одна функция MyFunction. Второй метод объявления экспортируемых объектов специфичен, но намного мощнее: вы можете экспортировать не только функции, но также классы и переменные. Давайте посмотрим на на фрагмент кода, сгенерированный при создании DLL AppWizard'ом VisualC++. Комментариев, включенных в листинг, вполне хватает, чтобы понять , как все это работает.
//================================================== ==========
// Заголовок DLL, который должен быть включен в код клиента
/*
Следующий блок ifdef - стандартный метод создания макроса,
который далает экспорт из DLL проще. Все файлы этой DLL
компилируются с определенным ключом MYFIRSTDLL_EXPORTS.
Этот ключ не определяется для любого из проектов, использующих эту DLL.
Таким образом, любой проект, в который включен это файл, видит функции
MYFIRSTDLL_API как импортируемые из DLL, тогда как сама DLL
эти же функции видит как экспортируемые.
*/
#ifdef MYFIRSTDLL_EXPORTS
#define MYFIRSTDLL_API __declspec(dllexport)
#else
#define MYFIRSTDLL_API __declspec(dllimport)
#endif
// Класс экспортируется из test2.dll
class MYFIRSTDLL_API CMyFirstDll {
public:
CMyFirstDll(void);
// TODO: здесь можно добавить свои методы.
};
extern MYFIRSTDLL_API int nMyFirstDll;
MYFIRSTDLL_API int fnMyFunction(void);
Во время компиляции DLL определен ключ MYFIRSTDLL_EXPORTS, поэтому перед объявлениями экспортируемых объектов подставляется ключевое слово __declspec(dllexport). А когда компилируется код клиента, этот ключ неопределен и перед объектами появляется префикс __declspec(dllimport), так что клиент знает, какие объекты импортируются из DLL.
В обоих случаях все, что нужно сделать клиенту - добавить файл myfirstdll.lib в проект и включить заголовочный файл, который объявляет импортируемые из DLL объекты, а затем использовать эти объекты (функции, классы и переменные) точно так же, как будто они были определены и реализованы локально в проекте. А теперь давайте разберем другой метод использования DLL, который чаще бывает удобнее и мощнее.



Позднее связывание (во время работы программы)

Когда используется позднее связывание, DLL загружается не автоматически, при запуске программы, а напрямую в коде, там, где это нужно. Не нужно использовать никакие .lib файлы, так что клиентское приложение не требует перекомпиляции при изменении DLL. Такое связывание обладает мощными возможностями именно потому, что ВЫ решаете, когда и какую DLL загрузить. Например, вы пишете игру, в которой используется DirectX и OpenGL. Вы можете просто включить весь необходимый код в исполняемый файл, но тогда разобраться в чем-нибудь будет просто невозможно. Или можно поместить код DirectX в одну DLL, а код OpenGL - в другую и статически подключить их к проекту. Но теперь весь код взаимнозависим, так что если вы написали новую DLL, содержащую код DirectX, то перекомпилировать придется и исполняемый файл. Единственным удобством будет то, что вам не нужно заботиться о загрузке (хотя неизвестно, удобство ли это, если вы загружаете обе DLL, занимая память, а в действительности нужна лишь одна из них). И наконец, на мой взгляд, лучшая идея состоит в том, чтобы позволить исполняемому файлу решить, какую DLL загрузить при запуске. Например, если программа определила, что система не поддерживает акселерацию OpenGL, то лучше загрузить DLL с кодом DirectX, иначе загрузить OpenGL. Поэтому позднее связывание экономит память и уменьшает зависимость между DLL и исполняемым файлом. Однако в этом случае накладывается ограничение на экспортируемые объекты - экспортироваться могут лишь C-style функции. Классы и переменные не могут быть загружены, если программа использует позднее связывание. Давайте посмотрим, как обойти это ограничение с помощью интерфейсов.


DLL, спроектированная для позднего связывания обычно использует .def файл для определения тех объектов, которые она хочет экспортировать. Если вы не хотите использовать .def файл, можно просто использовать префикс __declspec(dllexport) перед экспортируемыми функциями. Оба метода делают одно и то же. Клиент загружает DLL, передавая имя файла DLL в функцию Win32 LoadLibrary().Эта функция возвращает хэндл HINSTANCE, который используется для работы с DLL и который необходим для выгрузки DLL из памяти, когда она становится не нужна. После загрузки DLL клиент может получить указатель на любую функцию при помощи функции GetProcAddress(), используя в качестве параметра имя требуемой функции.
//================================================== ==========
// .def файл
LIBRARY myfirstdll.dll
DESCRIPTION 'My first DLL'
EXPORTS
MyFunction
//================================================== ==========
/*
Реализация функции в DLL
*/
bool MyFunction(int parms)
{
//делаем что-нибудь
............
}
//================================================== ==========
//Код клиента
/*
Объявление функции в действительности необходимо только для того,
чтобы опредедлить параметры. Объявления функций обычно содержаться в
заголовочном файле, поставляемом вместе с DLL.
Ключевое слово extern C в объявлении функции сообщает компилятору,
что нужно использовать соглашения об именовании переменных языка C.
*/
extern "C" bool MyFunction(int parms);
typedef bool (*MYFUNCTION)(int parms);
MYFUNCTION pfnMyFunc=0; //указатель на MyFunction
HINSTANCE hMyDll = ::LoadLibrary("myfirstdll.dll");
if(hMyDll != NULL)
{
//Определяем адрес функции
pfnMyFunc= (MYFUNCTION)::GetProcAddress(hMyDll, "MyFunction");
//Если неудачно - выгружаем DLL
if(pfnMyFunc== 0)
{
::FreeLibrary(hMyDll);
return;
}
//Вызываем функцию
bool result = pfnMyFunc(parms);
//Выгружаем DLL, если она больше нам не нужна
::FreeLibrary(hMyDll);
}
Как вы видите, код довольно прямолинеен. А теперь давайте посмотрим, как может быть реализована работа с "классами". Как было указано ранее, если используется позднее связывание, нет прямого способа импортировать из DLL классы, так что нам нужно реализовать "функциональность" класса с помощью интерфейса, содержащего все открытые (public) функции, исключая конструктор и деструктор. Интерфейс будет обычной C/C++ структурой, содержащей только виртуальные абстрактные функции-члены. Фактический класс в DLL будет наследоваться от этой структуры и будет реализовывать все функции, определенные в интерфейсе. Теперь, чтобы получить доступ к этому классу из приложения - клиента, все, что нужно сделать - это экспортировать C-style функции, соответствующие экземпляру класса и связать их с определенным нами интерфейсом для того, чтобы клиент мог их использовать. Для реализации такого метода нужна еще две функции, одна из которых создаст интерфейс, а вторая удалит интерфейс после того, как с ним закончили работать. Пример реализации этой идеи приведен ниже.
//================================================== ==========
// .def файл
LIBRARY myinterface.dll
DESCRIPTION 'реализует интерфейс I_MyInterface
EXPORTS
GetMyInterface
FreeMyInterface
//================================================== ==========
// Заголовочный фал, используемый в Dll и клиенте,
// который объявляет инетрфейс
// I_MyInterface.h
struct I_MyInterface
{
virtual bool Init(int parms)=0;
virtual bool Release()=0;
virtual void DoStuff() =0;
};
/*
Объявления экспортируемых функций Dll и определения типов указателей
на функции для простой загрузки и работы с функциями. Обратите
внимание на префикс extern "C", который сообщает компилятору о том,
что используются С-style функции
*/
extern "C"
{
HRESULT GetMyInterface(I_MyInterface ** pInterface);
typedef HRESULT (*GETINTERFACE)(I_MyInterface ** pInterface);
HRESULT FreeMyInterface(I_MyInterface ** pInterface);
typedef HRESULT (*FREEINTERFACE)(I_MyInterface ** pInterface);
}
//================================================== ==========
//Реализация интерфейса в Dll
// MyInterface.h
class CMyClass: public I_MyInterface
{
public:
bool Init(int parms);
bool Release();
void DoStuff();
CMyClass();
~CMyClass();
//любые другие члены класса
............
private:
//любые члены класса
............
};
//================================================== ==========
// Экспортируемые функции, которые создают и уничтожают интерфейс
// Dllmain.h
HRESULT GetMyInterface(I_MyInterface ** pInterface)
{
if(!*pInterface)
{
*pInterface= new CMyClass;
return S_OK;
}
return E_FAIL;
}
HRESULT FreeMyInterface(I_MyInterface ** pInterface)
{
if(!*pInterface)
return E_FAIL;
delete *pInterface;
*pInterface= 0;
return S_OK;
}
//================================================== ==========
// Код клиента
//Объявления интерфейса и вызов функций
GETINTERFACE pfnInterface=0;//указатель на функцию GetMyInterface
I_MyInterface * pInterface =0;//указатель на структуру MyInterface
HINSTANCE hMyDll = ::LoadLibrary("myinterface.dll");
if(hMyDll != NULL)
{
//Определяем адрес функции
pfnInterface= (GETINTERFACE)::GetProcAddress(hMyDll,
"GetMyInterface");
//Выгружаем DLL, если предыдущая операция окончилась неудачей
if(pfnInterface == 0)
{
::FreeLibrary(hMyDll);
return;
}
//Вызываем функцию
HRESULT hr = pfnInterface(&pInterface);
//Выгружаем, если неудачно
if(FAILED(hr))
{
::FreeLibrary(hMyDll);
return;
}
//Интерфейс загружен, можно вызывать функции
pInterface->Init(1);
pInterface->DoStuff();
pInterface->Release();
//Освобождаем интерфейс
FREEINTERFACE pfnFree =
(FREEINTERFACE )::GetProcAddress(hMyDll,"FreeMyInterface");
if(pfnFree != 0)
pfnFree(&hMyDll);
//Выгружаем DLL
::FreeLibrary(hMyDll);
}
Этой информации вполне достаточно, чтобы почувствовать все удобство использования интерфейсов. И если все равно не понятно спроси....
Удачного программирования!
Ответить 
Старый 06.07.2007 16:01   #9  
Real ID Group
Аватар для Aleksandr Vishinskiy
Оффлайн
Сообщений: 57
+ 3  9/6
– 0  0/0

Uzbekistan
Цитата:
Сообщение от cascada Посмотреть сообщение
Ну ты орёл
Я то может и орел, но не знаю что у тя со зрением и поэтому дал совет.
Ответить 
Старый 06.07.2007 23:14   #10  
Real ID Group
Аватар для Botir Axmedov
Оффлайн
Сообщений: 21
+ 0  2/2
– 0  0/0

Uzbekistan
Post

По моему ты хотел спросить как правильно создавать DLL. Думю из ответа
Акрома Обидова ты нашёл решение(там действительно полезные вещи), если поленился то вкратце:

в проект своей DLL добавь новый *.DEF файл.
в этот файл припиши следующие строки:

LIBRARY /название длл/
EXPORTS MyFunction

и компилируеш.

Но вобще есть мнение что DEF файлы прописывают только изв-цы .
Удачного кодинга! 8-)
__________________
everything is possible
Ответить 
Ответить
Опции темы
Опции просмотра




Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Advertisement System V2.5 By Branden
OOO «Единый интегратор UZINFOCOM»


Новые 24 часа Кто на форуме Новички Поиск Кабинет Все прочитано Вверх