Конвертировать код из C в Delphi (работа с DLL) - PullRequest
0 голосов
/ 13 апреля 2020

Мне нужна твоя помощь;). Попробуйте поработать с SDR-приемником (блейд RF). У меня есть dll (bladeRF.dll). У меня есть код на C (struct, enum и function). Код на C:

  typedef enum {
    BLADERF_BACKEND_ANY, 
    BLADERF_BACKEND_LINUX, 
    BLADERF_BACKEND_LIBUSB, 
    BLADERF_BACKEND_CYPRESS, 
    BLADERF_BACKEND_DUMMY = 100, 
   } bladerf_backend;

#define BLADERF_DESCRIPTION_LENGTH 33
#define BLADERF_SERIAL_LENGTH 33

struct bladerf_devinfo {
  bladerf_backend backend; 
  char serial[BLADERF_SERIAL_LENGTH]; 
  uint8_t usb_bus; 
  uint8_t usb_addr; 
  unsigned int instance; 
  char manufacturer[BLADERF_DESCRIPTION_LENGTH];
  char product[BLADERF_DESCRIPTION_LENGTH]; 
};

int CALL_CONV bladerf_get_device_list(struct bladerf_devinfo **devices);

Мне нужно преобразовать этот код на Delphi (Embarcadero 10.3). Вы можете помочь мне? Мой код на Delphi:

Bladerf_Backend = (BLADERF_BACKEND_ANY,  BLADERF_BACKEND_LINUX,  BLADERF_BACKEND_LIBUSB,  BLADERF_BACKEND_CYPRESS,  BLADERF_BACKEND_DUMMY = 100);

PDevices = ^TDevices;
TDevices = record
  backend  : Bladerf_Backend;
  serial   : PAnsiChar;
  usb_bus  : Byte;
  usb_addr : Byte;
  instance : Integer;
  manufacturer :PAnsiChar;
  product :PAnsiChar;
end;

bladerf_get_device_list: function(point: PDevices): integer; cdecl;

//Try to execute
procedure TForm1.Button1Click(Sender: TObject);
var
  myblade : TDevices;
  pointer : PDevices;
begin
  pointer := @myblade;
  dongle_count:= bladerf_get_device_list(pointer);
  myblade := pointer^;
  Memo1.Lines.Add(myblade.serial);
  Memo1.Lines.Add(myblade.manufacturer);
  Memo1.Lines.Add(myblade.product);
end;

Возвращаемое значение функции (1). Но запись имеет ошибочные значения. Нужна ваша помощь. Спасибо.

Ответы [ 2 ]

2 голосов
/ 13 апреля 2020

Ваш перевод массивов char[] неверен. Они должны быть объявлены как array[0..high] of AnsiChar фиксированные массивы, а не как PAnsiChar указатели.

Кроме того, ваше объявление bladerf_get_device_list() неверно. Параметр devices является выходным параметром, он возвращает вам указатель на массив устройств, поэтому функция должна иметь возможность изменять указатель, который вы ему задаете, что означает, что параметр должен быть объявлен как var или out типа указателя. Без этого вы вместо этого объявляете devices в качестве входного параметра, и, таким образом, функция не может изменить ваш указатель.

Кроме того, не забудьте вызвать bladerf_free_device_list(), когда вы закончите, используя список .

A буквальный перевод кода C будет выглядеть так:

type
  bladerf_backend = (
    BLADERF_BACKEND_ANY, 
    BLADERF_BACKEND_LINUX, 
    BLADERF_BACKEND_LIBUSB, 
    BLADERF_BACKEND_CYPRESS, 
    BLADERF_BACKEND_DUMMY = 100, 
  );

const
  BLADERF_DESCRIPTION_LENGTH = 33;
  BLADERF_SERIAL_LENGTH = 33;

type
  pbladerf_devinfo = ^bladerf_devinfo;
  bladerf_devinfo = record
    backend: bladerf_backend; 
    serial: array[0..BLADERF_SERIAL_LENGTH-1] of AnsiChar; 
    usb_bus: UInt8;
    usb_addr: UInt8; 
    instance: UInt32; 
    manufacturer: array[0..BLADERF_DESCRIPTION_LENGTH-1] of AnsiChar;
    product: array[0..BLADERF_DESCRIPTION_LENGTH-1] of AnsiChar; 
  end;

const
  libbladeRF = 'libbladeRF.dll'; // or whatever the actual DLL filename is...

function bladerf_get_device_list(out devices: pbladerf_devinfo): Int32; cdecl; external libbladeRF;

procedure bladerf_free_device_list(devices: pbladerf_devinfo); cdecl; external libbladeRF;

И тогда вы можете использовать его так:

{$POINTERMATH ON}
procedure TForm1.Button1Click(Sender: TObject);
var
  devices: pbladerf_devinfo;
  dongle_count, i: Int32;
begin
  dongle_count := bladerf_get_device_list(devices);
  if dongle_count < 0 then
    // error handling ...
  try
    for i := 0 to dongle_count-1 do
    begin
      Memo1.Lines.Add(String(devices[i].serial));
      Memo1.Lines.Add(String(devices[i].manufacturer));
      Memo1.Lines.Add(String(devices[i].product));
    end;
  finally
    bladerf_free_device_list(devices);
  end;
end;

В качестве альтернативы:

procedure TForm1.Button1Click(Sender: TObject);
var
  devices, device: pbladerf_devinfo;
  dongle_count, i: Int32;
begin
  dongle_count := bladerf_get_device_list(devices);
  if dongle_count < 0 then
    // error handling ...
  try
    device := devices;
    for i := 0 to dongle_count-1 do
    begin
      Memo1.Lines.Add(String(device^.serial));
      Memo1.Lines.Add(String(device^.manufacturer));
      Memo1.Lines.Add(String(device^.product));
      Inc(device);
    end;
  finally
    bladerf_free_device_list(devices);
  end;
end;
2 голосов
/ 13 апреля 2020

Я не буду давать полный ответ здесь, но некоторые элементы, чтобы помочь вам. Есть несколько проблем с кодом.

Запись должна называться TDevice (не TDevices), потому что она представляет одно устройство. Должны быть встроены буферы для строк (serial, manufacturer, product) с правильными размерами; установка указателей вместо (PAnsiChar) не сработает.

bladerf_get_device_list() принимает указатель на указатель на TDevice. Это не то, что вы даете.

bladerf_get_device_list() выделяет массив TDevice и возвращает его размер. Вы должны проверить возвращаемое значение. После того, как вы закончите использовать массив, вы должны использовать bladerf_free_device_list(), чтобы освободить его.

...