Создание Dll |
Здравствуйте, гость ( Вход | Регистрация )
Создание Dll |
1.7.2008, 22:00
Сообщение
#1
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Принципы построения, создания и использования Dynamic Link Library (DLL)
Среды разработки и языки: Borland С++ Builder 6, lua 5, PtokaX 3.6.*.* Немного теории. DLL - это один или несолько участков кода, хранимых в файле с расширением .dll. Код, содержащийся в dll, может быть вызван из испольняемой программы, но сама dll не является программой. DLL может содержать функции, классы и ресурсы. Прежде чем использовать dll, её нужно загрузить в память. Существуют два вида загрузки dll: статическая и динамическая. Статическая загрузка означает, что dll автоматически загружается при запуске приложения. DLL содержит экспортируемые функции, а описания этих функций находятся в библиотеке импорта (import library). Библиотеки импорта имеют имя, совпадающее с именем соответствующей dll, и расширение .lib. Для использования статической загрузки необходимо на этапе компоновки к проекту подключить lib-файл для dll. DLL загружается при загрузке приложения и можно вызывать экспортируемые функции так же, как и любые другие функции. Это самый лёгкий подход. Недостаток его в том, что при отсутствие необходимой dll программа не будет загружаться ваобще. Второй тип загрузки - Динамическая загрузка. Означает, что DLL загружается при необходимости и выгружается по окончанию использования. Достоинством является то, что dll находится в памяти до тех пор, пока она нужна, что приводит к более эффективному использованию памяти. В lua мы используем динамический вид загрузки. Ещё немного о содержании dll библиотек. Как же прсмотреть содержимо dll библиотеки? Ведь dll файл нельзя ничем открыть. Для просмотра содержимого dll существуют специальные утилиты. Я использую Борнандовскую утилиту tdump (находится в папке bin вместе с bcb.exe). Далее писать теорию влом. Если что, то спрашивайте попробую объяснить))) Приступим к написанию. 1. Открываем Builder C++ 6 2. Закрываем автоматически созданную форму (file -> close all) 3. Создаём новый проект (file -> new -> Other -> dll wizard) указываем тип "C" (в противном случае будут необходимы некоторые манипуляции с extern "C") я уще обычно ставлю галку vc++ style dll (но это не принципиально, просто будет различаться имя основной функции dll). 4. Далее в созданном проекте видим огромный коммент -> стираем его нах (в кратце он говорит о том что для того чтобы использовать библиотеку srting необходим дополнительный гемор). 5. функцию DllMain не трогаем, а пишем выше (или ниже) следующий код (данный код является самым простейшим): Код #include <windows.h> #pragma comment(lib, "PXLua.lib") #include "lua.h" #include "lualib.h" #include "lauxlib.h" int __declspec(dllexport) lua_helloworld (lua_State *L) { lua_pushstring(L, "Hello World!"); return 1; } 6. сохраняем проект (file -> save project). вам будет сначало предложено сохранить юнит, а потом уже проект. 7. для компиляции нужны заголовочные файлы (из исходников),а именно файлы: "lua.h", "lualib.h", "lauxlib.h" и "luaconf.h". 8. все эти файлы можно найти скачав исходники lua. 9. эти файлы надо поместить в директорию проекта. 10. также нужна библиотека статической загрузки "PXLua.lib" 11. создаем dll (project -> build all) 12. копируем dll из папки проекта в папку с PtokaX (dll обычно имеет имя проекта. по умолчанию "project1.dll") 13. пишем скрипт Код libinit = package.loadlib("project1.dll", "_lua_helloworld") SendToAll(libinit()) тут функция содержит впереди символ подчеркивания - это "украшения" компилятора))) (хотя существуют способы убрать этот символ, но я их тут рассматривать не буду). Просмотреть названия функций в библиотеке можно опять же воспользовавшись утилитой tdump.exe 14. заходим на хаб и перезагружаем скрипт. должно появиться "Hello World!". p.s. для написания dll для PtokaX 0.4.*.* необходима библиотека статической загрузки "PXLua.lib" для данной версии и соответственно изменить SendToAll на Core.SendToAll p.p.s. чуть позже выложу более сложные функции (ща влом писать) "PXLua.lib" [для PtokaX 0.3.6.0] PXLua.zip ( 4.01 килобайт ) Кол-во скачиваний: 125 "Заголовочные файлы" lua.zip ( 13 килобайт ) Кол-во скачиваний: 113 |
|
|
1.7.2008, 22:36
Сообщение
#2
|
|
Активный участник Группа: Администраторы Сообщений: 77 Регистрация: 3.6.2008 Из: Тула Пользователь №: 9 Спасибо сказали: 52 раза |
Отличная работа. просто замечательно что ты уделил время и занялся этим.
Код DLL может содержать функции, классы и ресурсы. по-поводу ресурсов. что кроме чистого кода может содержать dll билеотека? |
|
|
1.7.2008, 22:49
Сообщение
#3
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
это не относится к lua. Ресурсы в lua использовать можно но бесполезно. Ресурсами могут быть например картинки в бинарном коде или иконки или например загнать в длл в качестве ресурсов некоторую таблицу переменных и использовать эти переменные в программе (переменным присваиваются некие строковые значения) - таким образом можно осуществять перевод программы на другие языки не переписывая всю программу, а переписав только длл файл. Ресурсы обычно используются прикладными программами (программами, написанными на с++), а не lua скриптами. Ресурсы при создании хранятся в специальном файле с расширением .rc или .res
|
|
|
1.7.2008, 23:03
Сообщение
#4
|
|
Активный участник Группа: Администраторы Сообщений: 77 Регистрация: 3.6.2008 Из: Тула Пользователь №: 9 Спасибо сказали: 52 раза |
ну про ресурсы я чисто из интереса спросил. понятное дело что они не применимы в данном случае.
|
|
|
2.7.2008, 12:46
Сообщение
#5
|
|
Главный ра******й тут... Группа: Главные администраторы Сообщений: 1 727 Регистрация: 18.5.2008 Из: RF, 2la Пользователь №: 1 Спасибо сказали: 776 раз |
^_^ Ееее! Начало положено, спасибо Setuper'у!
Вот короче результат: Цитата [Linker Error] Unresolved external '_lua_pushstring' referenced from E:\BORLAND CBUILDER6\PROJECTS\2ND\UNIT1.OBJ Даже получившийся код приведу, вдруг тут где-то накосячил: Код //--------------------------------------------------------------------------- #include <windows.h> #pragma comment(lib, "PXLua.lib") #include "lua.h" #include "lualib.h" #include "lauxlib.h" #pragma argsused BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved) { return 1; } int __declspec(dllexport) lua_helloworld (lua_State *L) { lua_pushstring(L, "Hello World!"); return 1; } //--------------------------------------------------------------------------- Исходники для 0.4, те что выложены сейчас на луаборде, а именно PXLua-5.1.3-src.7z. Всё по инструкции, расположенной выше. Кстати 0.3.6 уже не актуальна, так что думаю лучше будет сразу рассматривать это дело для 0.4.*.* |
|
|
10.7.2008, 20:00
Сообщение
#6
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
данная ошибка возникает из-за того, что в новой библиотеке PXLua.dll убрали символ "_" перед функцией (так называемый name mangling).
библиотека ищет в библиотеке PXLua.dll функцию "_lua_pushstring" и не находит, поскольку там функция "lua_pushstring". |
|
|
11.7.2008, 23:46
Сообщение
#7
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Более сложный пример использования dll.
Пример вызова api-функции windows: "MessageBoxA" из системной библиотеки "user32.dll". с++ код: Код #include <windows.h> #include <malloc.h> #pragma comment(lib, "PXLua.lib") #include "lua.h" #include "lualib.h" #include "lauxlib.h" typedef void* (__stdcall *func_call)(); static int api_call(lua_State *L) { int i,type; int n=lua_gettop(L); func_call fc=(func_call)lua_touserdata(L,lua_upvalueindex(2)); void *ret; do { void **arg=(void **)alloca(n*sizeof(void *)); for (i=0;i<n;i++) { type=lua_type(L,i+1); switch(type) { case LUA_TNIL: arg[i]=0; break; case LUA_TNUMBER: arg[i]=(void*)lua_tointeger(L,i+1); break; case LUA_TBOOLEAN: arg[i]=(void*)lua_toboolean(L,i+1); break; case LUA_TSTRING: arg[i]=(void *)lua_tostring(L,i+1); break; case LUA_TLIGHTUSERDATA: arg[i]=lua_touserdata(L,i+1); break; default: lua_pushstring(L,"unknown argument type"); lua_error(L); break; } } ret=fc(); } while(0); switch(lua_type(L,lua_upvalueindex(1))) { case LUA_TNIL: lua_pushlightuserdata(L,ret); break; case LUA_TNUMBER: lua_pushinteger(L,(int)ret); break; case LUA_TBOOLEAN: lua_pushboolean(L,(int)ret); break; case LUA_TSTRING: lua_pushstring(L,(const char*)ret); break; default: lua_pushstring(L,"unknown return value type"); lua_error(L); break; } return 1; } int __declspec(dllexport) msg(lua_State *L) { HMODULE hm=LoadLibrary("user32.dll"); void *func=GetProcAddress(hm,"MessageBoxA"); lua_pushvalue(L,3); lua_pushlightuserdata(L,func); lua_pushcclosure(L,api_call,2); return 1; } #pragma argsused BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved) { return 1; } lua код: Код msg = package.loadlib("PXDLL.dll", "_msg") Message=msg() Message(nil,"Приступаю к форматированию диска!","format c:",2) P.S. PXDLL.dll - вами созданная dll библиотека |
|
|
13.7.2008, 23:18
Сообщение
#8
|
|
Главный ра******й тут... Группа: Главные администраторы Сообщений: 1 727 Регистрация: 18.5.2008 Из: RF, 2la Пользователь №: 1 Спасибо сказали: 776 раз |
данная ошибка возникает из-за того, что в новой библиотеке PXLua.dll убрали символ "_" перед функцией (так называемый name mangling). библиотека ищет в библиотеке PXLua.dll функцию "_lua_pushstring" и не находит, поскольку там функция "lua_pushstring". И как добиться того чтобы небыло этого злощастного подчеркивания при компиляции?? |
|
|
31.8.2008, 16:23
Сообщение
#9
|
|
МЕДВЕД =) Группа: Пользователи Сообщений: 187 Регистрация: 6.8.2008 Пользователь №: 332 Спасибо сказали: 4 раза |
Код #include "lua.h" #include "lualib.h" #include "lauxlib.h" lauxlib.h - это очепятка или так и должно быть? напрашивается luaxlib.h |
|
|
31.8.2008, 17:31
Сообщение
#10
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
нет! это не опечатка!
но разницы нет! в исходниках lua есть как файл lauxlib.h так и файл luaxlib.h - они полностью идентичны для того чтобы народ не перепутал вдруг)))))) а исходное имя заголовочного файла конечно же было: lauxlib.h имя файла расшифровывается как: Lua Auxiliary for libraries переводится как: Lua помошник для построения библиотек |
|
|
13.10.2008, 16:50
Сообщение
#11
|
|
Самый главный активист :-D Группа: Модераторы Сообщений: 2 790 Регистрация: 29.6.2008 Из: г. Тула Пользователь №: 97 Спасибо сказали: 440 раз |
^_^ Ееее! Начало положено, спасибо Setuper'у! Вот короче результат: Даже получившийся код приведу, вдруг тут где-то накосячил: Код //--------------------------------------------------------------------------- #include <windows.h> #pragma comment(lib, "PXLua.lib") #include "lua.h" #include "lualib.h" #include "lauxlib.h" #pragma argsused BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved) { return 1; } int __declspec(dllexport) lua_helloworld (lua_State *L) { lua_pushstring(L, "Hello World!"); return 1; } //--------------------------------------------------------------------------- Исходники для 0.4, те что выложены сейчас на луаборде, а именно PXLua-5.1.3-src.7z. Всё по инструкции, расположенной выше. Кстати 0.3.6 уже не актуальна, так что думаю лучше будет сразу рассматривать это дело для 0.4.*.* у меня такой же результат!!! Что с этим делать? |
|
|
16.11.2008, 1:29
Сообщение
#12
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
calling_conventions.pdf ( 321.04 килобайт )
Кол-во скачиваний: 22
mangling name убирается, если использовать calling convention передачи параметров через стек: __stdcall |
|
|
16.11.2008, 19:29
Сообщение
#13
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Построение dll библиотек под API2. Чего я добился.
mangling name (украшение имени функции, дополнительные символы в имени функции) убирается, если использовать calling convention передачи параметров через стек, а именно, установкой параметра __stdcall во всех экспортируемых функциях. Этот параметр указывает на то, что все параметры функций будут передаваться через стек, и при этом стек будет очищаться в конце выполнения той функции, которая вызывается. Этот параметр применим только для функций, которые содержать конечное число параметров. Можем убедиться, что при использовании __stdcall, mangling name не убирается у функций lua_pushfstring и luaL_error, это объясняется тем, что эти функции содержат переменное число параметров. Однако, во всех других функциях mangling name убрался. Итак, как проверить имена функции в dll библиотеке? Я буду рассматривать всё в Borland C++ Builder. Эта среда разработки выбрана потому, что именно инструментами компании Borland пользуются разработчики PtokaX. Для проверки содержимого dll библиотеке будем использовать утилиту tdump.exe. Её можно найти в папке bin установленного Builder C++, или просто скачать: tdump.rar ( 108.4 килобайт ) Кол-во скачиваний: 38 Копируем эту утилиту, например, на рабочий стол, и сюда же копируем dll библиотеку, содержимое которой хотим просмотреть. Далее, идём Пуск-Выполнить, набираем cmd, нажимаем enter, вводим: cd рабочий стол, жмём enter, вводим: tdump имя_библиотеке.dll 1.txt. После всего этого на рабочем столе должен появиться файл 1.TXT, в котором будут описаны все функции, которые содержатся в нашей dll. Для выявления отличий в dll библиотеках разных версий api просматриваем библиотеки PXLua.dll из разных версий api и видим, что в старом апи перед всеми функциями находится символ _ - это так называемый mangling name, или его ещё называют украшением имени функций dll. В библиотеке нового апи этот символ перед функциями отсутствует везде, кроме двух функций, о которых я писал выше. Как же избавиться от этого mangling name? Создадим свою библиотеку, в которой будет единственная функция: hello_world. Открываем Borland C++ Builder (в дальнейшем я буду писать сокращённо по первым буквам BCB). У нас появилась какая-то форма. Лезем в меню File -> Close All. Далее, File -> New -> Other -> DLL Wizard. Устанавливаем переключатель в С++ и снимаем все галки, жмём ОК. Далее заходим: View -> Project Manager, щёлкаем на плюсик рядом с надписью Project1.dll, выделяем Project1.res и нажимаем Remove, выделяем Unit1.cpp и нажимаем Remove, после этого закрываем окно Project Manager, создаём на рабочем столе папку test, входим File -> Save Project As... и сохраняем в созданную папку проект с именем test.bpr, далее, в этой папке надо создать 2 папки с именами src и obj. Качаем с сайта PtokaX ( Код #if defined(LUA_CORE) || defined(LUA_LIB) заменяем их на:#define LUA_API __declspec(dllexport) #else #define LUA_API __declspec(dllimport) #endif Код #if defined(LUA_CORE) || defined(LUA_LIB) #define LUA_API extern "C" __declspec(dllexport) #else #define LUA_API extern "C" __declspec(dllimport) #endif Далее, создаём в этой папке файлы: main.h и main.cpp. Открываем их, и пишем в main.h: Код #ifndef _MAIN_H #define _MAIN_H #include <stdio.h> #include "lua.h" #include "lualib.h" #include "lauxlib.h" #if defined(BUILD_AS_DLL) #define DLL_API __declspec(dllexport) #else #define DLL_API extern #endif DLL_API int (lua_hello) (lua_State*); #endif в main.cpp: Код #include "main.h" Строчка #pragma comment(lib,"PXLua.lib") подключает статическую библиотеку, которая, в принципе, есть в скаченных исходниках архива PXLua-5.1.3-src.7z, копируем эту PXLua.lib в нашу папку obj.#pragma comment(lib,"PXLua.lib") DLL_API int (hello_world) (lua_State *L) { lua_pushstring(L,"Hello world!"); return 1; } Далее, в BCB заходим в Project -> Options -> Directories/Conditionals, устанавливаем следующие параметры: Include path: obj;src;$(BCB)\include;$(BCB)\include\vcl, Library path: obj;src;$(BCB)\lib\obj;$(BCB)\lib, Debug source path: $(BCB)\source\vcl, Intermediate output: путь_до_вашей_папки_obj, Final output: путь_до_вашей_папки_obj, далее, нажимаем на три точки напротив Conditional defines и добавляем макросы: LUA_BUILD_AS_DLL и BUILD_AS_DLL. Жмём ОК. В закладке Linker убираем галку с Use dynamic RTL, в закладке Packages убираем галку с Build with runtime packages. На этом настройка завершена. Далее, заходим в View -> Project Manager и добавляем к проекту файлы: main.h и main.cpp Строим проект: Project -> Build test. При построении проекта вылезает ошибка: [Linker Error] Unresolved external '_lua_pushstring' referenced from... Возможно, линковщиком ищется функция _lua_pushstring, но в либе PXLua.lib находится ссылка на функцию lua_pushstring. Как быть? Как убрать mangling name? Mangling name убирается следующим кодом: main.h: Код #ifndef _MAIN_H #define _MAIN_H #include <stdio.h> #include "lua.h" #include "lualib.h" #include "lauxlib.h" #if defined(BUILD_AS_DLL) #define DLL_API __declspec(dllexport) #else #define DLL_API extern #endif DLL_API int __stdcall (lua_hello) (lua_State*); #endif main.cpp: Код #include "main.h" #pragma comment(lib,"PXLua.lib") DLL_API int __stdcall (hello_world) (lua_State *L) { lua_pushstring(L,"Hello world!"); return 1; } Строим проект, и видим ошибку: [Linker Error] Unresolved external 'lua_pushstring' referenced from... Это уже не поддаётся объяснению. Вскрываем библиотеку PXLua.lib с помощью утилиты tdump и видим, что ссылки на функцию lua_pushstring в ней есть! Возможно либа PXLua.lib - битая, но если она битая, то из исходников мы можем построить свою либу с этими же функциями. Строим свою либу! Точно так же создам проект, но с названием PXLua, всё точно также делаем, но только в файле luaconf.h мы ничего не меняем (берём исходный файл из PXLua-5.1.3-src.7z), файлы main.h и main.cpp мы не создаём. Копируем в нашу папку src всё содержимое папки src архива PXLua-5.1.3-src.7z. Точно также стоим проект и получаем в папке obj файлы PXLua.lib и PXLua.dll. Но если открыть эти файлы утилитой tdump, то мы увидим там mangling name. Избавиться от него можно таким же способом, который я предлагал. Но чтобы вам не переписывать все файлы, я выложу уже переписанные файлы, вам надо только скопировать всё в папку src: src.rar ( 133.98 килобайт ) Кол-во скачиваний: 8 Строим проект и получаем опять же PXLua.lib и PXLua.dll. Помещаем в папку obj нашего первого проекта файл PXLua.lib и строим наш первый проект. DLL успешно создалась. Ура! Копируем нашу DLL в папку с PtokaX и пишем скрипт: Код libinit = package.loadlib("test.dll", "hello_world") Core.SendToAll(libinit()) И тут, при запуске скрипта, выскакивает ошибка (ну надо же, на последней стадии). Из-за чего? Я понять до сих пор не могу! Ведь вроде убрали mangling name, построили (создали) свою dll библиотеку, но ничего не пашет!!! Что за несовместимости? Из-за чего они возникают? Почему наша библиотека не находит в библиотеке PXLua.dll нужную функцию? Кто-нибудь может ответить на эти вопросы? Такая тупиковая ситуация называется DLL hell ! |
|
|
25.1.2009, 7:39
Сообщение
#14
|
|
Местный Группа: Неактивированные Сообщений: 908 Регистрация: 26.12.2008 Пользователь №: 1 574 Спасибо сказали: 1406 раз |
Цитата Как быть? Как убрать mangling name? А почему бы не использовать Fastcall? Тогда библиотека соберётся (во всяком случае у меня собралась). |
|
|
25.1.2009, 12:57
Сообщение
#15
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
А возможно ли её подключить из скриптов? Собраться то она соберётся, но не подключиться.
|
|
|
25.1.2009, 14:00
Сообщение
#16
|
|
Местный Группа: Неактивированные Сообщений: 908 Регистрация: 26.12.2008 Пользователь №: 1 574 Спасибо сказали: 1406 раз |
Подключится, если поплясать с бубном. .
Во-первых: Цитата(PPK) Initializing in lua 5.1.1 like Код require "lalalalib" И если в LUA 5.1.1 старый способ ещё работал, то в 5.1.3 - уже нет. А отсюда следует что имя библиотеки(без расширения) и имя вызываемой функции (а точнее то, что следует после luaopen_) должны совпадать. А иначе как - аргумент-то один. PS. Я тоже долго бился головой ап стену пытаясь понять, почему библиотека подгружается нормально, а функция вызываться никак не хочет. |
|
|
25.1.2009, 18:56
Сообщение
#17
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
ок. Как время будет покопаюсь, посмотрю.
Может скомпилишь тогда либу для работы с бд, раз у тебя получилось? |
|
|
26.1.2009, 0:18
Сообщение
#18
|
|
Местный Группа: Неактивированные Сообщений: 908 Регистрация: 26.12.2008 Пользователь №: 1 574 Спасибо сказали: 1406 раз |
|
|
|
22.2.2009, 16:51
Сообщение
#19
|
|
Местный Группа: Неактивированные Сообщений: 908 Регистрация: 26.12.2008 Пользователь №: 1 574 Спасибо сказали: 1406 раз |
Setuper
У тебя есть исходники PXSqlite (той самой, которая нормально работает под птокой 0.3.6.0)? Если да - выложи плиз. |
|
|
24.2.2009, 17:05
Сообщение
#20
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Где-то тут на форуме уже выкладывал, ну да ладно, видимо затерялись где-то. Выложу ещё раз, не сложно)))
SQLite.rar ( 2.3 мегабайт ) Кол-во скачиваний: 40 |
|
|
Похожие темы
|
Сейчас: 23.11.2024, 1:54 |