|
|
Знаете ли Вы, что ... | |
...инструкция по установке аватара описана в Правилах форума. | |
<< Предыдущий совет - Случайный совет - Следующий совет >> |
Другие языки программирования Здесь обсуждаются все, что касается JAVA, проблемы и задачи 1С, |
Ответить |
|
Опции темы | Опции просмотра |
27.06.2007 02:30 | #1 | ||
none
none
Сообщений: 51
+ 3
4/3
– 0
0/0
|
Всем привет.есть проблема:я не знаю как сделать так чтобы можно было бы вызвать функцию из длл подключённую при выполнении:
pointerOnFunction=GetProcAdress(hInstDll,"MyFuncti on");//не работает //потому что присутствует мод CALLBACK //который убирать нежелательно, нужен для использования //в программах на других языках, приходиться делать так pointerOnFunction=GetProcAdress(hInstDll,"_MyFunct ion@14"); вот эта собачка и знак подчёркивания и мозолят глаза.как убать их? использовать порядковые числа тоже нехорошо. спрашивал на других форумах ..что то молчат. подскажите а?если можно киньте кодом, я не обижусь))) |
||
|
Ответить |
05.07.2007 01:37 | #3 |
none
none
Сообщений: 51
+ 3
4/3
– 0
0/0
|
Ну ты орёл Все 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); } |
|
Ответить |
05.07.2007 15:32 | #6 | ||
Сообщений: 23
+ 0
5/5
– 0
0/0
|
раз уж ты пишеш на с++ не лучшели использовать неявное подключение 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 | ||
none
none
Сообщений: 51
+ 3
4/3
– 0
0/0
|
Цитата:
Цитата:
pFunc=GetProcAdress(hInstDll,"MyFunction"); //вполне работоспособно ну да ладно....что такое def файлы?и как поступить с ними в моём случае? |
||
|
Ответить |
Реклама и уведомления | |
06.07.2007 12:27 | #8 | |
Цитата:
Раннее связывание (во время компиляции программы) При таком методе связывания операционная система автоматически загружает 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 23:14 | #10 | ||
Сообщений: 21
+ 0
2/2
– 0
0/0
|
По моему ты хотел спросить как правильно создавать DLL. Думю из ответа
Акрома Обидова ты нашёл решение(там действительно полезные вещи), если поленился то вкратце: в проект своей DLL добавь новый *.DEF файл. в этот файл припиши следующие строки: LIBRARY /название длл/ EXPORTS MyFunction и компилируеш. Но вобще есть мнение что DEF файлы прописывают только изв-цы . Удачного кодинга! 8-)
__________________
everything is possible |
||
|
Ответить |
|