Packed Record из делфи в Java

Рейтинг: -1Ответов: 1Опубликовано: 29.03.2023

Всем привет! Столкнулся с проблемой вызова запакованной записи из DLL, написанной на делфи. Есть функция в делфи, которая использует как аргумент запакованную запись:

type
  {информация о счёте}
  TAccountInfo = packed record
    Size      : Word;    // SizeOf( TAccountInfo )
    Account   : Integer; // номер счёта
    Card      : Int64;   // номер карты
    Holder    : Array[0..40] of Char; //ФИО
    Scheme    : Byte;    {тип счёта:  0 - ручное пополнение без ограничения оплат 1 - автоматическое пополнение без ограничения оплат
                          2 - автоматическое пополнение с лимитом оплат на один день
                          3 - автоматическое пополнение с лимитом оплат на неделю
                          4 - автоматическое пополнение с лимитом оплат на месяц
                          5 - ручное пополнение с лимитом оплат на один день
                          6 - ручное пополнение с лимитом оплат на неделю
                          7 - ручное пополнение с лимитом оплат на месяц
                          }
    Offered   : Integer; // дата выдачи (0 -> 30/12/1899)
    Expired   : Integer; // срок действия
    Birthday  : Integer; // день рождения
    Deleted   : BOOL;    // счёт удален?
    Locked    : BOOL;    // карта заблокирована?
    Seize     : BOOL;    // карту изъять?
    WhyLocked : Array[0..255] of Char; // причина блокировки - asciiz
    Discount  : Word;    // номер скидки
    Bonus     : Word;    // номер бонуса
    PayLimit  : Comp;    // лимит оплат для счетов c лимитом
    Female    : BOOL;    // пол
    Folder    : Word;    // идентификатор отдела
    Unpay     : Integer; // номер неплательщика
    Tel1      : Array[0..15] of Char; //телефон 1
    Tel2      : Array[0..15] of Char; //телефон 2
    Email     : Array[0..255] of Char;
    Address   : Array[0..255] of Char;
    DopInfo   : Array[0..255] of Char; //произвольная информация - asciiz
    Balance   : Comp;    // для карт с ручным пополнением - текущий остаток
  end;

{получить информацию о счёте}
Function GetAccountInfo( Account: Integer; var Info: TAccountInfo ): BOOL; stdcall;

При вызове функции GetAccountInfo указывается номер счёта, а затем требуется разметка для получения записи. Пробовал использовать структуру, но в ответ получаю сообщение из функции получения сообщения от DLL:

Invalid record size

либо ошибку чтения памяти. При выводе из структуры записи имеют значение 0.

Ниже прикладываю свой код на Java:

//Вызов в интерфейсе CscLink
@Structure.FieldOrder({
"account", "adress", "balance", "birthday", "bonus", "card",
 "deleted", "discount", "dopInfo", "email", "expired", "folder",
 "holder", "locked", "offered", "payLimit", "scheme", "seize", "sex",
 "size", "tel1", "tel2", "unpay", "whyLocked"})
       public class TAccountInfo extends Structure{
           public char size;
        public int account;
        public long card;
        public char[] holder = new char[40];
        public byte scheme;
        public int offered;
        public int expired;
        public int birthday;
        public boolean deleted;
        public boolean locked;
        public boolean seize;
        public char[] whyLocked = new char[255];
        public char discount;
        public char bonus;
        public long payLimit;
        public boolean sex;
        public char folder;
        public int unpay;
        public char[] tel1 = new char[15];
        public char[] tel2 = new char[15];
        public char[] email = new char[255];
        public char[] adress = new char[255];
        public char[] dopInfo = new char[255];
        public long balance;
    }
    
//Вызов в Main
CscLink.TAccountInfo taco = new CscLink.TAccountInfo();
myLib.GetAccountInfo(getAccNumb.getValue(), taco);
System.out.println(taco.card);

Ответы

▲ 1Принят

Вывод packed record через JNA в Java производится следующим образом. Вывод производится с помощью структуры. В запакованной записи первый аргумент (Size, в конкретном случае) отвечает за размерность всей структуры, туда мы и передаём размер из delphi (sizeof всей структуры packed record).

@Structure.FieldOrder({"Size", "Account", "Card", "Holder", "Scheme", "Offered", "Expired", "Birthday", "Deleted","Locked", "Seize", "WhyLocked", "Discount", "Bonus", "PayLimit", "Female", "Folder", "Unpay", "Tel1", "Tel2", "Email", "Address", "DopInfo", "Balance"})
public class TAccountInfo extends Structure{
    //В конкретном случае 1166 байт
    public char Size = 1166;
    public int Account;
    public byte[] Card = new byte[32];
    public byte[] Holder = new byte[50];
    public byte Scheme;
    public int Offered;
    public int Expired;
    public int Birthday;
    public boolean Deleted;
    public boolean Locked;
    public boolean Seize;
    public byte[] WhyLocked = new byte[255];
    public char Discount;
    public char Bonus;
    public long PayLimit;
    public boolean Female;
    public short Folder;
    public int Unpay;
    public byte[] Tel1 = new byte[15];
    public byte[] Tel2 = new byte[15];
    public byte[] Email = new byte[255];
    public byte[] Address = new byte[255];
    public byte[] DopInfo = new byte[255];
    public long Balance;
}

Далее мы выполняем соответствия типов и инициализируем массивы. Ниже приведу использованные значения для маппинга.

+---------------------+---------------------------+
|       Delphi        |           Java            |
+---------------------+---------------------------+
| Word                | char или short            |
| Int64               | long                      |
| Array[0..n] of Char | byte[] name = new byte[n] |
| BOOL                | boolean                   |
| Comp                | long                      |
| Byte                | byte                      |
+---------------------+---------------------------+

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

Огромная благодарность за помощь MBo и Kromster!