Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2 3 4   вперед  Ctrl      все
 DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
Возникла необходимость на Delphi написать DLL в которой функция должна возвращать массив записей типа :
TMyRecord = record
   Id: Integer;
   Name: string;
   DateCreate: TDateTime;
end;

TMyArray array of TMyRecord;

function MyFunc: TMyArray;


Пример предельно упрощенный,

Фишка в том, что эту DLL предполагается использовать из программ написанных на разных языках и средах, типа C++, PowerBuilder, Java, Delphi

Мне приходилось писать несложные DLL для своих же нужд (для использования из программ написанных на Delphi же)
Но как я понимаю, для этой задачи нужно, видимо как-то особенно организовать данные, которые вернет функция. Чтобы у тех кто ее будет использовать не возникло проблем.
Как минимум потому, что типы в Delphi и в том же C++ это разные вещи.

У кого был такой опыт подскажите как тут быть, с какой стороны подойти...
20 май 19, 16:55    [21889035]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 25999
SQL-Talker
TMyRecord = record
   Id: Integer;
   Name: pchar/pansichar/pwidechar;
   DateCreate: longint/int64; // unix-time
end;

Примерно так. Эти типы совместимы.

https://stackoverflow.com/questions/4420188/how-to-format-a-unix-timestamp-in-delphi
20 май 19, 17:00    [21889039]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
ёёёёё
Member

Откуда:
Сообщений: 1071
SQL-Talker,

не, нельзя управляемые типы (string, объекты).
Можно, если использовать COM(OLE), вебсервисы и проч.
Можно упаковывать в портабельные форматы (json, xml).
20 май 19, 17:34    [21889074]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
ziv-2014
Member

Откуда:
Сообщений: 462
SQL-Talker,
Используй интерфейсы.
Строки передавай в widestring, pansichar, pchar, pwidechar.
Не используй управляемые типы.
Используй метод передачи параметров safecall или stdcall, cdecl (для java).
Не возвращай записи в результате функции. В функции возвращаешь результат работы функции или код ошибки.
20 май 19, 17:46    [21889084]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
ziv-2014
Member

Откуда:
Сообщений: 462
SQL-Talker,
В какой DLL выделил память в той и удаляешь.
20 май 19, 17:48    [21889086]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
Василий 2
Member

Откуда:
Сообщений: 761
И делай структуры packed, чтобы не налететь на разницу в выравнивании. Либо явно задавай размер выравнивания
20 май 19, 17:57    [21889094]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
Василий 2
Member

Откуда:
Сообщений: 761
ziv-2014
Используй интерфейсы.

Вовсе не обязательно. Большой оверхед во многих случаях
Не возвращай записи в результате функции. В функции возвращаешь результат работы функции или код ошибки.

Можно, но не обязательно
20 май 19, 17:59    [21889096]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
ziv-2014
Member

Откуда:
Сообщений: 462
Василий 2
Не возвращай записи в результате функции. В функции возвращаешь результат работы функции или код ошибки.

Можно, но не обязательно

Разные языки программирования по разному возвращают структуры, как результат функции.
С# и Delphi не совместимы и будет эксепшен.
20 май 19, 21:01    [21889223]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5252
SQL-Talker,

  • От managed-типов придётся отказаться, либо "выводить" функции для управления ими
  • К дельфи-специфичным типам вроде TDateTime тоже лучше не прибегать. Возьми аналоги, например Linux Time
  • С масивом всё просто, смотри похожие функции в WinAPI, там везде функция имеет два логичесикх варианта вызова: определение необходимого размера и собственно сама работа. Т.е. необходимую память выделяет вызывающая сторона.
  • 21 май 19, 08:52    [21889391]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    Пытаюсь вернуть строку из DLL.
    Пишу в таком духе:

    // процедура в DLL
    procedure GetStringFromDLL(Buffer: LPWSTR; var dwSize: DWORD);
    var
      OutStr: String;
    begin
      OutStr := 'йцукен qwerty'; // как-то получили эту строку
    
      dwSize := Length(OutStr) * 2;
    
      if Buffer <> nil then
        Buffer := StrNew(PChar(OutStr));
    end;
    


    вот так пытаюсь ее прочитать из внешней программы:
    procedure ReadString;
    var
      MyStr: String;
      Size: DWORD;
      Buffer: PChar;
    begin
      Size := 0;
    
      GetStringFromDLL(nil, Size);
    
      if Size > 0 then
      begin
        Buffer := GetMemory(Size * 2);
        GetStringFromDLL(PChar(Buffer), Size);
        MyStr := PChar(Buffer);
        FreeMemory(Buffer);
    
        ShowMessage(MyStr);
      end;
    end;
    

    В MyStr в итоге оказывается мусор из иероглифов

    В чем ошибка?
    28 май 19, 15:07    [21895830]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    cptngrb
    Member

    Откуда:
    Сообщений: 385
    SQL-Talker,
    зачем
    GetMemory(Size * 2);
    

    если
    dwSize := Length(OutStr) * 2;
    
    28 май 19, 15:36    [21895874]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    cptngrb,

    Вы правы, промашка. Но это не решает проблему.
    28 май 19, 15:48    [21895889]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    Александр Спелицин
    Member

    Откуда: Из ближайшего подмосковья.
    Сообщений: 2477
    SQL-Talker
    В чем ошибка?

    Например в том, что несколько вызовов PChar(Buffer) не гарантируют одного и того же результата.
    Убирайте Ваш PChar() и передавайте уже саму переменную Buffer, как ссылку на выделенный участок памяти.
    28 май 19, 15:52    [21895892]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    cptngrb
    Member

    Откуда:
    Сообщений: 385
    SQL-Talker, а
    Buffer: LPWSTR
    
    и
    Pchar(PChar)
    
    одно и тоже?
    28 май 19, 16:23    [21895911]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11200
    SQL-Talker
    В чем ошибка?
    Во всем. Начиная с записи в пустоту
    SQL-Talker
    Buffer := StrNew(PChar(OutStr));
    

    // процедура в DLL
    function GetStringFromDLLW(Buffer: PWideChar; var dwSize: DWORD): Integer;
    var
      OutStr: WideString;
      size: DWORD;
    begin
      try
        OutStr := 'йцукен qwerty'; // как-то получили эту строку
        size := (Length(OutStr) + 1) * SizeOf(OutStr[1]);  // +1 for \0 symbol
    
        if size = 0 then
          Result := S_FALSE
        else if (Buffer = nil) or (dwSize < size) then
          Result := ERROR_NOT_ENOUGHT_MEMORY;
        else begin
          Move(OutStr[1], Buffer^, size);
          Result := S_OK;
        end;
        dwSize := size;
      except
        Result := E_FAIL;
      end;
    end;
    
    procedure ReadString;
    var
      MyStr: String;
      Size: DWORD;
      Res: Integer;
    begin
      Size := 0;
      MyStr := '';
      Res := GetStringFromDLLW(nil, Size);
      if Res = ERROR_NOT_ENOUGHT_MEMORY then begin
        SetLength(MyStr, (Size div SizeOf(WideChar)) - 1);
        Res := GetStringFromDLLW(PChar(MyStr), Size);
      end;
      if (Res = S_OK) or (Res = S_FALSE) then
        ShowMessage(MyStr)
      else
        ShowMessageFmt('Error %d', [Res]);
    end;
    
    28 май 19, 16:31    [21895918]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    // процедура в DLL
    procedure GetStringFromDLL(Buffer: PAnsiChar; var dwSize: DWORD);
    var
      OutStr: String;
    begin
      OutStr := 'йцукен qwerty'; // как-то получили эту строку
    
      dwSize := Length(OutStr);
    
      if Buffer <> nil then
        Buffer := StrNew(PAnsiChar(OutStr));
    end;
    


    // внешняя программа
    procedure GetStringFromDLL(Buffer: PAnsiChar; var dwSize: DWORD);
    ...
    procedure ReadString;
    var
      MyStr: String;
      Size: DWORD;
      Buffer: PAnsiChar;
    begin
      Size := 0;
    
      GetStringFromDLL(nil, Size);
    
      if Size > 0 then
      begin
        Buffer := GetMemory(Size);
        GetStringFromDLL(@Buffer, Size);
        MyStr := Buffer;
        FreeMemory(Buffer);
    
        ShowMessage(MyStr);
      end;
    end;
    

    Все равно не получаю то что надо...
    28 май 19, 16:32    [21895919]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11200
    В моем примере заменить
    _Vasilisk_
    MyStr: String;
    
    на
    MyStr: WideString;
    
    28 май 19, 16:36    [21895922]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    cptngrb
    Member

    Откуда:
    Сообщений: 385
    SQL-Talker,
    var
      MyStr: String;
       Buffer: PChar;
    MyStr := Buffer;
    


    и вы будете менять pchar, pansichar, widestring, string то ничего не получиться. подбором может только случайно получиться
    28 май 19, 16:38    [21895924]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    _Vasilisk_,

    Ваш пример работает на ура.
    Спасибо

    Буду разбирать, чего я в этой технологии не понимаю.
    28 май 19, 16:45    [21895927]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    _Vasilisk_,

    А зачем в DLL длина буфера берется на 1 больше, если потом во внешней программе все равно идет уменьшение на эту же единицу?
    28 май 19, 17:17    [21895951]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11200
    SQL-Talker
    А зачем в DLL длина буфера берется на 1 больше, если потом во внешней программе все равно идет уменьшение на эту же единицу?
    Мы передаем абстрактный PChar. Он заканчивается \0. Поэтому мы добавляем 1 в dll

    Память мы выделяем функцией SetLength. В Делфи все строки заканчиваются \0, поэтому SetLength автоматически выделит память под этот \0. Отсюда -1
    28 май 19, 17:24    [21895962]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    makhaon
    Member

    Откуда: A galaxy far far away
    Сообщений: 3377
    _Vasilisk_,

    автор
    В Делфи все строки заканчиваются \0

    это где так?
    28 май 19, 17:51    [21895979]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11200
    makhaon
    автор
    В Делфи все строки заканчиваются \0
    это где так?
    Везде
    Str: string;
    begin
      Str := 'abc';
      ShowMessage(IntToStr(Ord(
        Str[Length(Str)] + 1
      )));
    end;
    
    28 май 19, 17:56    [21895981]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11200
    makhaon,

    А как, по твоему, работает привидение к PChar?
    28 май 19, 17:57    [21895984]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    makhaon
    Member

    Откуда: A galaxy far far away
    Сообщений: 3377
    _Vasilisk_,

    автор
    А как, по твоему, работает привидение к PChar?

    чудом, не иначе
    включи range check, узнаешь много нового. никакого нуля сзади строки нет. ну и посмотри как приведение работает. подсказка: UStrToPWChar.
    28 май 19, 19:41    [21896024]     Ответить | Цитировать Сообщить модератору
    Топик располагается на нескольких страницах: [1] 2 3 4   вперед  Ctrl      все
    Все форумы / Delphi Ответить