Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

MyDC.ru _ Разработчикам [PtokaX] _ Создание Dll

Автор: Setuper 1.7.2008, 22:00

Принципы построения, создания и использования 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 килобайт ) : 124

"Заголовочные файлы"  lua.zip ( 13 килобайт ) : 112

Автор: Svyat 1.7.2008, 22:36

Отличная работа. просто замечательно что ты уделил время и занялся этим.

Код
DLL может содержать функции, классы и ресурсы.

по-поводу ресурсов. что кроме чистого кода может содержать dll билеотека?

Автор: Setuper 1.7.2008, 22:49

это не относится к lua. Ресурсы в lua использовать можно но бесполезно. Ресурсами могут быть например картинки в бинарном коде или иконки или например загнать в длл в качестве ресурсов некоторую таблицу переменных и использовать эти переменные в программе (переменным присваиваются некие строковые значения) - таким образом можно осуществять перевод программы на другие языки не переписывая всю программу, а переписав только длл файл. Ресурсы обычно используются прикладными программами (программами, написанными на с++), а не lua скриптами. Ресурсы при создании хранятся в специальном файле с расширением .rc или .res

Автор: Svyat 1.7.2008, 23:03

ну про ресурсы я чисто из интереса спросил. понятное дело что они не применимы в данном случае.

Автор: Nickolya 2.7.2008, 12:46

^_^ Ееее! Начало положено, спасибо 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. Всё по инструкции, расположенной выше. big_smile.gif
Кстати 0.3.6 уже не актуальна, так что думаю лучше будет сразу рассматривать это дело для 0.4.*.*

Автор: Setuper 10.7.2008, 20:00

данная ошибка возникает из-за того, что в новой библиотеке PXLua.dll убрали символ "_" перед функцией (так называемый name mangling).
библиотека ищет в библиотеке PXLua.dll функцию "_lua_pushstring" и не находит, поскольку там функция "lua_pushstring".

Автор: Setuper 11.7.2008, 23:46

Более сложный пример использования 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 библиотека

Автор: Nickolya 13.7.2008, 23:18

Цитата(Setuper @ 10.7.2008, 20:00) *
данная ошибка возникает из-за того, что в новой библиотеке PXLua.dll убрали символ "_" перед функцией (так называемый name mangling).
библиотека ищет в библиотеке PXLua.dll функцию "_lua_pushstring" и не находит, поскольку там функция "lua_pushstring".

И как добиться того чтобы небыло этого злощастного подчеркивания при компиляции??

Автор: fixx 31.8.2008, 16:23

Код
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

lauxlib.h - это очепятка или так и должно быть? напрашивается luaxlib.h

Автор: Setuper 31.8.2008, 17:31

нет! это не опечатка!
но разницы нет!
в исходниках lua есть как файл lauxlib.h так и файл luaxlib.h - они полностью идентичны для того чтобы народ не перепутал вдруг))))))

а исходное имя заголовочного файла конечно же было: lauxlib.h
имя файла расшифровывается как: Lua Auxiliary for libraries
переводится как: Lua помошник для построения библиотек
big_smile.gif

Автор: Wariner 13.10.2008, 16:50

Цитата(Nickolya @ 2.7.2008, 13:46) *
^_^ Ееее! Начало положено, спасибо 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. Всё по инструкции, расположенной выше. big_smile.gif
Кстати 0.3.6 уже не актуальна, так что думаю лучше будет сразу рассматривать это дело для 0.4.*.*


у меня такой же результат!!! Что с этим делать? beat_brick.gif

Автор: Setuper 16.11.2008, 1:29

 calling_conventions.pdf ( 321.04 килобайт ) : 21

mangling name убирается, если использовать calling convention передачи параметров через стек: __stdcall

Автор: Setuper 16.11.2008, 19:29

Построение 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 (http://mydc.ru/r/?http://www.ptokax.ch) PtokaX 0.4.x.x Libs Package. Скачается архив: PtokaX_API2_Extensions.rar, распаковываем его, далее, используя утилиту 7Zip (http://mydc.ru/r/?http://www.7-zip.org), распаковываем архив: PXLua-5.1.3-src.7z, копируем в нашу папку src из их папки src следующие файлы: lauxlib.h, lua.h, luaconf.h, lualib.h. Сразу же открываем файл luaconf.h (например, с помощью NotePad++), находим строчки:

Код
#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")
DLL_API int (hello_world) (lua_State *L)
{
    lua_pushstring(L,"Hello world!");
    return 1;
}
Строчка #pragma comment(lib,"PXLua.lib") подключает статическую библиотеку, которая, в принципе, есть в скаченных исходниках архива PXLua-5.1.3-src.7z, копируем эту PXLua.lib в нашу папку obj.
Далее, в 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 !

Автор: alex82 25.1.2009, 7:39

Цитата
Как быть? Как убрать mangling name?

А почему бы не использовать Fastcall? Тогда библиотека соберётся (во всяком случае у меня собралась). boss.gif

Автор: Setuper 25.1.2009, 12:57

А возможно ли её подключить из скриптов? Собраться то она соберётся, но не подключиться.

Автор: alex82 25.1.2009, 14:00

Подключится, если поплясать с бубном. bad_smile.gif.

Во-первых:

Цитата(PPK)
Initializing in lua 5.1.1 like

Код
require "lalalalib"


И если в LUA 5.1.1 старый способ ещё работал, то в 5.1.3 - уже нет. А отсюда следует что имя библиотеки(без расширения) и имя вызываемой функции (а точнее то, что следует после luaopen_) должны совпадать. А иначе как - аргумент-то один.

PS. Я тоже долго бился головой ап стену пытаясь понять, почему библиотека подгружается нормально, а функция вызываться никак не хочет.

Автор: Setuper 25.1.2009, 18:56

ок. Как время будет покопаюсь, посмотрю.

Может скомпилишь тогда либу для работы с бд, раз у тебя получилось?

Автор: alex82 26.1.2009, 0:18

Цитата(Setuper @ 25.1.2009, 17:56) *
Может скомпилишь тогда либу для работы с бд, раз у тебя получилось?

Сомневаюсь что у меня получится. Я си практически не знаю.

Автор: alex82 22.2.2009, 16:51

Setuper

У тебя есть исходники PXSqlite (той самой, которая нормально работает под птокой 0.3.6.0)? Если да - выложи плиз.

Автор: Setuper 24.2.2009, 17:05

Где-то тут на форуме уже выкладывал, ну да ладно, видимо затерялись где-то. Выложу ещё раз, не сложно)))

 SQLite.rar ( 2.3 мегабайт ) : 39

Автор: alex82 24.2.2009, 21:06

Как будто собралась. victory.gif И вроде даже работает. Во всяком случае тестовый скрипт выполняется нормально.
 PXSqlite3.rar ( 159.33 килобайт ) : 21

Автор: Setuper 24.2.2009, 21:17

Круто!!! Браво alex82! Несколько таблиц в базе создаётся. Буду тестить дальше.
Как у тебя получилось не расскажешь? Горю от нетерпения узнать.

Автор: alex82 24.2.2009, 21:30

Цитата(Setuper @ 24.2.2009, 20:17) *
Круто!!! Браво alex82! Несколько таблиц в базе создаётся. Буду тестить дальше.
Как у тебя получилось не расскажешь? Горю от нетерпения узнать.

 PXSqlite3_src.rar ( 372.89 килобайт ) : 14

Подозреваю что всё дело в собаке (имеется ввиду не животное bad_smile.gif )

Автор: Setuper 24.2.2009, 21:32

Не понял о чём ты?
С помощью чего компилил?

Автор: alex82 24.2.2009, 21:38

Цитата(Setuper @ 24.2.2009, 20:32) *
Не понял о чём ты?
С помощью чего компилил?

Об этом.
Код
    luaopen_pxsqlite3 = @luaopen_sqlite3         @0  ; luaopen_sqlite3(lua_State *)

Цитата(Setuper @ 24.2.2009, 20:32) *
С помощью чего компилил?

С++ Builder

Автор: Setuper 24.2.2009, 21:49

BDS? Borland Developer Studio?

Автор: alex82 24.2.2009, 23:11

Setuper

CodeGear (читай Borland) C++ Builder. Но это не суть важно - C++ Builder прекрасно хавает проекты созданные в BDS, и, я так думаю, BDS схавает проект C++ Builder'а.

Автор: Setuper 24.2.2009, 23:42

Просто у меня BDS нету, есть только Builder C++ 6 и Visual studio 6, Visual studio 2005, Visual studio 2008.
C++ Builder 6 не открывает ни проект cbproj, ни bdsproj

Я пытался компилить только на том, что у меня есть, а вообще я приверженец VS.

Автор: alex82 24.2.2009, 23:54

Если не лень качать 800 с лишним метров, тогда вот - http://mydc.ru/r/?http://torrents.ru/forum/viewtopic.php?t=365896

Автор: Setuper 24.2.2009, 23:58

Спасибо. Скачаю и попробую скомпилить.

Автор: Setuper 7.3.2009, 14:00

Создание простейшей либы под API 2 (by Builder C++ 6).

Создаём dll проект (обязательно язык С). Пишем код:

Код
#include "lua.h"
#include "lauxlib.h"
#pragma link "PXLua.lib"

int lua_hello(lua_State *L)
{
  lua_pushstring(L, "Hello World!");
  return 1;
}


Создаём в папке проекта def файл (Define.def)
В созданный файл записываем:
Код
LIBRARY     Project1.dll
DESCRIPTION "Project1"

EXPORTS
    lua_hello = @lua_hello         @1 ; lua_hello(lua_State *)

Сохраняем и добавляем в проект этот самый файл Define.def

Сохраняем проект. Залезаем в настройки компилятора, и ставим calling convention: Register (J)

Строи проект.

После этого пишем lua скрипт:
Код
local Msg = package.loadlib("Project1", "lua_hello")

if Msg then
  Core.SendToAll(Msg())
end


Все необходимые заголовочные файлы прикладываю:  files.rar ( 13.27 килобайт ) : 17

Автор: alex82 7.3.2009, 16:08

Если библиотека не создаёт ни одной функции, которую можно вызвать из скрипта, то при чём здесть вообще API2? Это обычная DLL-библиотека. confuse.gif

Автор: Setuper 7.3.2009, 16:13

А смысл тогда создавать библиотеку?
Библиотеку нужно создавать для того, чтобы взаимодействовали функции СИ с функциями LUA (в контексте данного форума).

Автор: alex82 7.3.2009, 18:18

Ну ладно.

Тады продолжим в том же духе.

Создание библиотеки под API2
Урок второй: Вызов WinAPI функции из Lua-скрипта.
Необходимые инструменты:
* PtokaX 0.4.x.x
* Borland C++ Builder
* Текстовый редактор с подсветкой кода C (в принципе, можно использовать редактор встроенный в C++ Builder, но лично мне он не очень нравится)
* А также клавиатура, мышь, и немного мозга big_smile.gif


1. Создаём проект DLL-библиотеки (на языке C), и сразу же лезем в его настройки (Project -> Options). Здесь выбираем Build configuration - Base, переходим на вкладку C++ Compiler -> General compilation, и меняем опцию Calling convention на Fastcall (Register). Далее переходим на на вкладку Linker -> Linking, и отключаем пункт Dynamic RTL. Ну вот, с настройками вроде разобрались. Теперь переименуем проект. Назовём его, ну, скажем, PXHello. big_smile.gif

2. Пишем код:

Код
#include <windows.h>    //Это необходимо для использования функций WinAPI
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#pragma comment(lib, "PXLua.lib")

//Собственно, это и есть функция, которую мы будем вызывать из Lua-скрипта:
static int msgbox (lua_State *L) {    //Функциям, вызываемым из Lua-скриптов, всегда передаётся только один аргумент - адрес массива lua_State, который содержит информацию о состоянии Lua
//При вызове функции из скрипта, её аргументы помещаются в стек.
    const char *header = luaL_checkstring (L, 1);    //Забираем из стека первый аргумент функции
    const char *text = luaL_checkstring (L, 2);    //Забираем из стека второй аргумент функции
    MessageBox(0,text,header,0);    //Вызываем функцию WinAPI MessageBox
    return 0;    
}

//Массив luaL_reg, содержащий список функций, которые можно будет вызвать  из скрипта. В нашем случае функция всего одна.
static const struct luaL_reg functions[] = {
    {"MessageBox", msgbox},
    {NULL, NULL},    //Так всегда должен выглядеть последний элемент массива luaL_reg
};

//Функция, вызываемая при инициализации библиотеки:
int libinit (lua_State *L)
{
    luaL_register (L, "Win", functions);    //Второй аргумент - имя таблицы, в которую будут помещены функции, доступные из скриптов, третий аргумент - адрес массива luaL_reg (См. выше)
    return 1;
}

Далее создаём в папке проекта файл с расширением .def (имя файла может быть любым), и добавляем в него следующее:
Код
LIBRARY     PXHello.dll

EXPORTS
    luaopen_pxhello =@libinit         @0  ; libinit(lua_State *)

После чего добавляем файл в проект.

3. Сохраняем проект и компилируем библиотеку.

4. Пишем скрипт:
Код
require "pxhello"

function OnStartup()
    Win.MessageBox("Hello World!!!", "Фигасе!!! Это работает!")    --Первый аргумент - заголовок окна сообщения, второй - текст, отображаемый в окне
end

Если Вы всё сделали правильно, то при запуске скрипта появится сообщение:

Ну, вроде бы всё. Во всяком случае на сегодня. big_smile.gif

Да, чуть не забыл.

 PXHello.rar ( 46.26 килобайт ) : 24
 PXHello_source.rar ( 14.23 килобайт ) : 24

Автор: Setuper 7.3.2009, 18:28

Ага. Хорошо. Знакомая шняга (где-то я уже об этом же писал))).

Потихоньку может народ начнёт после прочтения данных статей писать нечто путнее.

Автор: alex82 7.3.2009, 18:42

Цитата(Setuper @ 7.3.2009, 17:28) *
Знакомая шняга
И вовсе не шняга, а динамическая библиотека. А шняга - это, как мне подсказывает интуиция, нечто статическое. bad_smile.gif
Цитата(Setuper @ 7.3.2009, 17:28) *
где-то я уже об этом же писал
Где?

Автор: Setuper 7.3.2009, 18:46

Шняга - это общее понятие, никакая это на библиотека)))

Автор: Jonathan 31.12.2010, 5:32

а как создать dll в delphi? cdecl меня убивает
в инете нарыл хидеры для delphi, но они для старых версий lua

Автор: Jonathan 17.2.2011, 8:47

попытался перевести второй код под Delphi
но выходит ошибка, не понимаю в чем дело
помогите плиз!!!

PtokaX 0.4.1.2 (lua версии 5.1.4?)

Код
library PXHello2;

uses
  Windows;

type
  lua_State = record
  end;
  Plua_State = ^lua_State;
  
  size_t = Integer;
  Psize_t = ^size_t;
  
  PLuaFunc = ^TLuaFunc;
  TLuaFunc = function (L: Plua_State): Integer; cdecl;

  PluaL_reg = ^TluaL_reg;
  TluaL_reg = packed record
    Name: PChar;
    Func: PLuaFunc;
  end;

const
  pxlib = 'pxlua.dll';
  
function luaL_checklstring(L: Plua_State; numArg: Integer; s: Psize_t): PChar; cdecl external pxlib name '@luaL_checklstring';
procedure luaL_register(L: Plua_State; libname: PChar; const R: PluaL_reg); cdecl external pxlib name '@luaL_register';
                        
function luaL_checkstring(L: Plua_State; N: Integer): PChar;
begin
  Result := luaL_checklstring(L, N, nil);
end;

//Собственно, это и есть функция, которую мы будем вызывать из Lua-скрипта:
function msgbox (L: Plua_State): Integer; cdecl;     //Функциям, вызываемым из Lua-скриптов, всегда передаётся только один аргумент - адрес массива lua_State, который содержит информацию о состоянии Lua
var
  header, text: PChar;
begin
    //При вызове функции из скрипта, её аргументы помещаются в стек.
    header := luaL_checkstring (L, 1);    //Забираем из стека первый аргумент функции
    text := luaL_checkstring (L, 2);    //Забираем из стека второй аргумент функции
    MessageBox(0, text, header, 0);    //Вызываем функцию WinAPI MessageBox
    result := 0;    
end;

//Массив luaL_reg, содержащий список функций, которые можно будет вызвать  из скрипта. В нашем случае функция всего одна.
const
  functions: array [0..1] of TluaL_reg = (
    (Name: 'MessageBox'; Func: @msgbox),
    (Name: nil; Func: nil)    //Так всегда должен выглядеть последний элемент массива luaL_reg
  );

//Функция, вызываемая при инициализации библиотеки:
function luaopen_pxhello2(L: Plua_State): Integer; cdecl;
begin
    luaL_register(L, 'Win', @functions);    //Второй аргумент - имя таблицы, в которую будут помещены функции, доступные из скриптов, третий аргумент - адрес массива luaL_reg (См. выше)
  result := 1;
end;

exports
  luaopen_pxhello2;

begin
end.


PS: и вообще существуют ли в природе хидеры под новый луа? (под delphi естественно)

Автор: Setuper 17.2.2011, 9:53

Ну и откуда у тебя компилятор узнает о том, что такое, например, TLuaFunc ?

Автор: Jonathan 17.2.2011, 10:16

Цитата(Setuper @ 17.2.2011, 15:53) *
Ну и откуда у тебя компилятор узнает о том, что такое, например, TLuaFunc ?

так есть же
Код
  PLuaFunc = ^TLuaFunc;
  TLuaFunc = function (L: Plua_State): Integer; cdecl;

проблем компиляции нет
проблема при попытке запустить скрипт
Код
require "pxhello2"

function OnStartup()
    Win.MessageBox("Hello World!!!", "Фигасе!!! Это работает!")    --Первый аргумент - заголовок окна сообщения, второй - текст, отображаемый в окне
end


я так думаю, что птока спотыкается здесь
Код
function luaopen_pxhello2(L: Plua_State): Integer; cdecl;
begin
    luaL_register(L, 'Win', @functions);    //Второй аргумент - имя таблицы, в которую будут помещены функции, доступные из скриптов, третий аргумент - адрес массива luaL_reg (См. выше)
  result := 1;
end;