Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в эту темуОткрыть новую тему
> вопрос по ffi и типы данных
trico
сообщение 27.3.2020, 9:25
Сообщение #1


**

Neophyte
Сообщений: 31
Регистрация: 23.12.2012
Группа: Пользователи
Наличность: 0
Пользователь №: 15.593
Возраст: 26



Пишу плагин на делфи, с integer разобрался:
Код
local ffi = require("ffi")
local lib = ffi.load("getpix.dll")

ffi.cdef[[
   __cdecl int getpix(int h, int x, int y);
]]


а вот если у меня boolean либо string?? Ну или же своя структура. Как указать это в синтаксисе луа в пилоте?
на __cdecl bool getf(string patch); ругается "declaration specifier expected near 'string'"

нужно обмениваться с длл типами данных string, bollean, array[a,b]. как это должно выглядеть?
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
Cockney
сообщение 27.3.2020, 12:12
Сообщение #2


********

Master
Сообщений: 1.394
Регистрация: 22.6.2013
Группа: Пользователи
Наличность: 20893
Пользователь №: 16.156



Код

ffi.cdef[[

   //custom struct
   struct my_struct{
      int x;
      int y;
   };

   //boolean
   __cdecl bool getbool();
  
  
   //string
  __cdecl const char* getstr();

  //struct
  __cdecl const struct my_struct* getstruct();

]]
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
trico
сообщение 28.3.2020, 8:54
Сообщение #3


**

Neophyte
Сообщений: 31
Регистрация: 23.12.2012
Группа: Пользователи
Наличность: 0
Пользователь №: 15.593
Возраст: 26



спасибо большое.

Если не трудно, почему не могу добиться простого ответа от плагина:

подключаю длл и функцию:
Код
local ffi = require("ffi")
local file = ffi.load("files.dll")
ffi.cdef[[
    __cdecl const char* fexists(const char* patch);
]]


функция в длл для теста:
Код
function fexists(patch:string):string; cdecl;
begin
fexists := patch;
end;


вызываю в пилоте
Код
local patch = 'abc'
local t = file.writef(patch)
log(t)

в логах пусто. Хотя если поставить в длл Cardinal а в пилоте int то данные идут в плагин и нормально возвращаются.
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
Cockney
сообщение 28.3.2020, 12:20
Сообщение #4


********

Master
Сообщений: 1.394
Регистрация: 22.6.2013
Группа: Пользователи
Наличность: 20893
Пользователь №: 16.156



Не вижу вызова fexists()
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
trico
сообщение 2.4.2020, 8:33
Сообщение #5


**

Neophyte
Сообщений: 31
Регистрация: 23.12.2012
Группа: Пользователи
Наличность: 0
Пользователь №: 15.593
Возраст: 26



Цитата(Cockney @ 28.3.2020, 11:20) *

Не вижу вызова fexists()


опечатка. функция вызывается.
Так работает:
пилот

Код

--lua
log("clear")
local ffi = require("ffi")
local file = ffi.load("files.dll")
ffi.cdef[[
    __cdecl int fexists(int patch);
]]
local patch = 55
local t = file.fexists(patch)
log(t)


длл:

Код

library files;

uses
  windows,
  Classes,
  SysUtils;

type
  tInitStruct = packed record
    FunctionCount : Cardinal;
    FunctionNames : Array of Pchar;
  end;

  tParamStruct = packed record
    WindowHandle : Cardinal; // Handle of workWindow
    WindowPID    : Cardinal; // pid of process of workWindow
    Reserved     : Cardinal;
    ParamString     : Pchar; // string of parameters with substituted variables
    ParamStringOrig : Pchar; // original string of parameters
    Result : array [0..32767] of char // array for returned values
  end;

var
  ParamStruct: ^tParamStruct;  // init by UOPilot
  InitStruct :  tInitStruct;   // init by plugin, free on unload

function InitPlugin(App, Scr: integer; Var Version: Real):Pointer; stdcall;
// App: Application.Handle of UOPilot
// Scr: reserved
begin
  // check UOPilot version, if it needed
  if Version >= 2.18 then begin
    // exported function count, for UOPilot
    InitStruct.FunctionCount := 1;
    setlength (InitStruct.FunctionNames, InitStruct.FunctionCount);
    // exported function names
    InitStruct.FunctionNames[0] := 'fexists'
  end else
    InitStruct.FunctionCount := 0;
  // if exported function count = 0, then plugin will be unloaded
  Result := @InitStruct;
end;

function fexists(patch:integer):integer; cdecl;
begin
fexists := patch;
end;

procedure DonePlugin; stdcall;
begin
  // free memory
  setlength (InitStruct.FunctionNames, 0);
end;

// exported function example
Exports
  InitPlugin,
  DonePlugin,
  fexists;
begin
end.




Со строками не работает. Что не так не догляжу
Пилот:

Код

--lua
log("clear")
local ffi = require("ffi")
local file = ffi.load("files.dll")
ffi.cdef[[
    __cdecl const char* fexists(const char* patch);
]]
local patch = "55"
local t = file.fexists(patch)
log(t)


длл:

Код

library files;

uses
  windows,
  Classes,
  SysUtils;

type
  tInitStruct = packed record
    FunctionCount : Cardinal;
    FunctionNames : Array of Pchar;
  end;

  tParamStruct = packed record
    WindowHandle : Cardinal; // Handle of workWindow
    WindowPID    : Cardinal; // pid of process of workWindow
    Reserved     : Cardinal;
    ParamString     : Pchar; // string of parameters with substituted variables
    ParamStringOrig : Pchar; // original string of parameters
    Result : array [0..32767] of char // array for returned values
  end;

var
  ParamStruct: ^tParamStruct;  // init by UOPilot
  InitStruct :  tInitStruct;   // init by plugin, free on unload

function InitPlugin(App, Scr: integer; Var Version: Real):Pointer; stdcall;
// App: Application.Handle of UOPilot
// Scr: reserved
begin
  // check UOPilot version, if it needed
  if Version >= 2.18 then begin
    // exported function count, for UOPilot
    InitStruct.FunctionCount := 1;
    setlength (InitStruct.FunctionNames, InitStruct.FunctionCount);
    // exported function names
    InitStruct.FunctionNames[0] := 'fexists'
  end else
    InitStruct.FunctionCount := 1;
  // if exported function count = 0, then plugin will be unloaded
  Result := @InitStruct;
end;

function fexists(patch:string):string; cdecl;
begin
fexists := patch;
end;

procedure DonePlugin; stdcall;
begin
  // free memory
  setlength (InitStruct.FunctionNames, 0);
end;

// exported function example
Exports
  InitPlugin,
  DonePlugin,
  fexists;
begin
end.



Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
Cockney
сообщение 2.4.2020, 12:21
Сообщение #6


********

Master
Сообщений: 1.394
Регистрация: 22.6.2013
Группа: Пользователи
Наличность: 20893
Пользователь №: 16.156



1) Если не планируется поддержка системы плагинов пилота (т.е. не ffi), то можно оставить только fexists(). InitPlugin, DonePlugin и структуры убрать.

2) Момент со строками:

Код
function fexists(patch:string):string; cdecl;
begin
fexists := patch;
end;


заменить на

Код
function fexists(patch:PChar):PChar; cdecl;
begin
fexists := patch;
end;


И сделаю замечание которое убережет от вопросов в дальнейшем.

Код
function fexists(patch:PChar):PChar; cdecl;
var
   plugin_str: string;
begin
plugin_str := 'plugin string';
fexists := Addr(plugin_str[1]);
end;


В общем случае это работать не будет. При работе с возвращаемой строкой из пилота будет в лучшем случае падение, в худшем - не правильно работать, т.к. строка будет перезаписана другими функциями и т.п. Если коротко - так делать не надо. Нельзя возвращать строки из dll.


Решение этой проблемы такое:

Добавляем дополнительную функцию, назовем ее getfilesize(), которая вернет размер файла. Далее в пилоте через ffi создаем строку buff размера, который вернула функция выше + 1. И это строку передаем в функцию dll, например, readfile(path: PChar, buff: PChar):integer; cdecl; В ffi - __cdecl int readfile(const char* path, char* buff);. Которая прочитает нужный файл, а вернет код операции (т.е. 0 - успешно, 1 - файл не найден и т.д. ). Далее, когда buff уже не нужен его нужно освободить так же через ffi.
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
cirus
сообщение 2.4.2020, 13:51
Сообщение #7


**********

Elder
Сообщений: 3.480
Регистрация: 18.8.2014
Группа: Пользователи
Наличность: 26540
Пользователь №: 16.971
Возраст: 29



Цитата
Решение этой проблемы такое:

А файлы зачем нужны, если передается указатель на строку? Читай/записывай сколько влезет.
Код
--lua
local ffi = require("ffi")
log "clear" log "mode compact"

local buf = ffi.new('char[999]')  -- выделить 999 байт
log(tostring(buf))
log('Размер в байтах: ' .. ffi.sizeof(buf))
ffi.copy(buf, 'Текст')   -- записать нужный текст

-- в длл передаём buf и его размер, читаем/пишем, делаем что надо
log(ffi.string(buf))
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
Cockney
сообщение 2.4.2020, 14:59
Сообщение #8


********

Master
Сообщений: 1.394
Регистрация: 22.6.2013
Группа: Пользователи
Наличность: 20893
Пользователь №: 16.156



Файлы как пример. Смысл в том, что плагин пишет(в моем примере читает файл) в уже выделенный кусок через ffi, а не возвращает сам.
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
trico
сообщение 1.7.2020, 9:51
Сообщение #9


**

Neophyte
Сообщений: 31
Регистрация: 23.12.2012
Группа: Пользователи
Наличность: 0
Пользователь №: 15.593
Возраст: 26



не раз возвращаюсь к этому топику, и не могу добиться результата. вот к примету со структурой (возврат более 2 и более значений из функции.) допустим, необходимо вернуть не одно число, а координаты:

пилот

--lua
local ffi = require("ffi")
local lib = ffi.load("findimg.dll")

ffi.cdef[[
struct my_struct{
int x;
int y;
};
__cdecl const struct my_struct* testf(int x, int y);
]]

local result = lib.testf(10,20)
log(result.x, result.y)



dll

type
FRes3 = record
x,y: integer;
end;

{....}

function testf (a,b:integer):FRes3; cdecl;
var
r:FRes3;
begin
r.x := a;
r.y := b;
testf := r;
end;


данные не возвращаются в таком исполнении. что не так?
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
cirus
сообщение 1.7.2020, 11:23
Сообщение #10


**********

Elder
Сообщений: 3.480
Регистрация: 18.8.2014
Группа: Пользователи
Наличность: 26540
Пользователь №: 16.971
Возраст: 29



Нужно в скрипте объявить структуру и передать в функцию её адрес. В функции записывать данные.
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
trico
сообщение 1.7.2020, 13:28
Сообщение #11


**

Neophyte
Сообщений: 31
Регистрация: 23.12.2012
Группа: Пользователи
Наличность: 0
Пользователь №: 15.593
Возраст: 26



Цитата(cirus @ 1.7.2020, 11:23) *

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


ка это правильно записать?
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
cirus
сообщение 1.7.2020, 21:09
Сообщение #12


**********

Elder
Сообщений: 3.480
Регистрация: 18.8.2014
Группа: Пользователи
Наличность: 26540
Пользователь №: 16.971
Возраст: 29



Цитата
ка это правильно записать?

Delphi вообще не знаю, пример на C++: Прикрепленный файл  PilotDLL.zip ( 39,71 килобайт ) Кол-во скачиваний: 487

Пилот
Код
--lua
local ffi = require('ffi')
local lib = ffi.load('PilotDLL.dll')  -- длл должна быть в папке с пилотом

ffi.cdef[[
    typedef struct { int a; int b; } MyStruct;
    __declspec(dllexport)void testf( MyStruct *result, int a, int b );
]]

log 'clear' log 'mode compact'

local result = ffi.new('MyStruct')   -- объявили структуру
lib.testf( result, 100, 20 )           -- вызов функции
log(result.a)   -- вернёт 2000 (100 * 20)
log(result.b)   -- вернёт 5 (100 / 20)

dll c++
Код
#include "pch.h"

struct my_struct {
    int x;
    int y;
};

extern "C" __declspec(dllexport)void testf(struct my_struct *r, int a, int b)
{
    r->x = a * b;
    r->y = a / b;
}
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
trico
сообщение 2.7.2020, 23:32
Сообщение #13


**

Neophyte
Сообщений: 31
Регистрация: 23.12.2012
Группа: Пользователи
Наличность: 0
Пользователь №: 15.593
Возраст: 26



ура, работает и с делфи)

pilot

Код

--lua
local ffi = require('ffi')
local lib = ffi.load('Project1.dll')  -- длл должна быть в папке с пилотом

ffi.cdef[[
    typedef struct { int a; int b; } MyStruct;
    __cdecl void testf( MyStruct *result, int a, int b );
]]

log 'clear' log 'mode compact'

local result = ffi.new('MyStruct')   -- объявили структуру
lib.testf( result, 100, 20 )           -- вызов функции
log(result.a)   -- вернёт 2000 (100 * 20)
log(result.b)   -- вернёт 5 (100 / 20)



dll delphi

Код
Library project1;

uses
  SysUtils,
  Classes;

Type
    TMyStruct = Record
        x: Integer;
        y: Integer;
    End;

procedure testf(Var r: TMyStruct; a: Integer; b: Integer); Cdecl;
Begin
r.x := a * b;
r.y := a div b;
End;

Exports
testf;

Begin
End.


всем спасибо (IMG:style_emoticons/default/smile.gif)
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

- Текстовая версия | Версия для КПК Сейчас: 28.3.2024, 19:36
Designed by Nickostyle