Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: 1 2 3 4      [все]
 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

Откуда: Санкт-Петербург
Сообщений: 25944
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

Откуда:
Сообщений: 979
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

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

Откуда:
Сообщений: 755
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

Откуда: Нижневартовск
Сообщений: 5211
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

    Откуда:
    Сообщений: 384
    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

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

    Откуда: Украина, Харьков
    Сообщений: 11193
    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

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

    Откуда:
    Сообщений: 384
    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

    Откуда: Украина, Харьков
    Сообщений: 11193
    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
    Сообщений: 3356
    _Vasilisk_,

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

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

    Откуда: Украина, Харьков
    Сообщений: 11193
    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

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

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

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

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

    чудом, не иначе
    включи range check, узнаешь много нового. никакого нуля сзади строки нет. ну и посмотри как приведение работает. подсказка: UStrToPWChar.
    28 май 19, 19:41    [21896024]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    makhaon
    включи range check,
    Мы сейчас говорим о корректности обращении к символу строки за пределами ее длины или о физическом состоянии памяти?
    makhaon
    подсказка: UStrToPWChar.
    function _UStrToPWChar(const S: UnicodeString): PWideChar;
    begin
      if Pointer(S) = nil then
        Result := @(PEmptyString(@EmptyStringW[1])^.Nul)
      else
        Result := Pointer(S);
    end;
    
    и что я должен был тут увидеть? То, что просто возвращается указатель на строку? Которая, внезапно, оказывается нуль-терминатной?
    28 май 19, 19:48    [21896026]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    makhaon
    Member

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

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

    Откуда: Украина, Харьков
    Сообщений: 11193
    makhaon
    в документации описано про гарантированный ноль в конце строки?
    Например вот
    http://docwiki.embarcadero.com/RADStudio/Tokyo/en/String_Types_(Delphi)
    You can also cast a UnicodeString or AnsiString string as a null-terminated string. The following rules apply:

  • If S is a UnicodeString, PChar(S) casts S as a null-terminated string; it returns a pointer to the first character in S. Such casts are used for the Windows API. For example, if Str1 and Str2 are UnicodeString, you could call the Win32 API MessageBox function like this:
    MessageBox(0, PChar(Str1), PChar(Str2), MB_OK);
    

    Use PAnsiChar(S) if S is an AnsiString.
  • You can also use Pointer(S) to cast a string to an untyped pointer. But if S is empty, the typecast returns nil.
  • 28 май 19, 23:21    [21896123]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    cptngrb
    Member

    Откуда:
    Сообщений: 384
    а я видел строки без /0 и с /0 посередине ))
    29 май 19, 09:12    [21896306]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    RWolf
    Member

    Откуда: Казань
    Сообщений: 430
    cptngrb
    а я видел строки без /0 и с /0 посередине ))

    вот прямо string без завершающего нуля?
    это, наверно, ошибка в программе была. Delphi всегда выделяет памяти на символ больше длины строки и пишет 0 в лишний символ.
    В самой строке нулей может быть сколько угодно, конечно.
    29 май 19, 10:15    [21896382]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    cptngrb
    Member

    Откуда:
    Сообщений: 384
    RWolf, конечно ошибка, но я то думал, что такого не бывает
    29 май 19, 10:20    [21896392]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    Квейд
    Member

    Откуда: Kyiv, Ukraine
    Сообщений: 5253
    makhaon
    _Vasilisk_,

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

    чудом, не иначе
    включи range check, узнаешь много нового. никакого нуля сзади строки нет.

    Есть

    makhaon
    ну и посмотри как приведение работает. подсказка: UStrToPWChar.


    А ты сам смотрел как работает UStrToPWChar?

    function _UStrToPWChar(const S: UnicodeString): PWideChar;
    begin
      if Pointer(S) = nil then
        Result := @(PEmptyString(@EmptyStringW[1])^.Nul)
      else
        Result := Pointer(S);
    end;
    
    29 май 19, 10:22    [21896395]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    makhaon
    Member

    Откуда: A galaxy far far away
    Сообщений: 3356
    ок, уговорили, черти красноречивые
    29 май 19, 12:01    [21896544]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    cptngrb
    а я видел строки без /0 и с /0 посередине ))
    И что? Это не противоречит тому, что строка оканчивается \0

    Вот при касте к PChar такой строки она обрежется до серединного \0. Вернее, если принимающая сторона считает длину строки по завершающему \0, то она прочитает только часть строки
    29 май 19, 14:34    [21896743]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    cptngrb
    Member

    Откуда:
    Сообщений: 384
    _Vasilisk_, вы категорично заявляли, что заканчивается 0.
    29 май 19, 16:31    [21897000]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    cptngrb
    Member

    Откуда:
    Сообщений: 384
    _Vasilisk_
    Вот при касте к PChar такой строки она обрежется до серединного \0. Вернее, если принимающая сторона считает длину строки по завершающему \0, то она прочитает только часть строки


    вот и приходилось нолик игнорировать в середине
    29 май 19, 16:33    [21897004]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

    Откуда: Нижневартовск
    Сообщений: 5211
    cptngrb
    _Vasilisk_, вы категорично заявляли, что заканчивается 0.
    да, заканчивается, но это никак не исключает, что нулей может быть больше одного, завершающего

    "Те кто говорят, что у Кутозова не было одного глаза, нагло врут. Один глаз у него был!!!"
    29 май 19, 17:06    [21897080]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    GunSmoker
    Member

    Откуда:
    Сообщений: 3110
    SQL-Talker, товарищ! Не слушай некоторых тут, они давно не чистили лук на подводной лодке. Читай сюда: Разработка API (контракта) для своей DLL или: не создавайте своих DLL, не прочитав эту статью!.
    7 июн 19, 22:37    [21904965]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    shonli95
    Member

    Откуда:
    Сообщений: 85
    makhaon
    никакого нуля сзади строки нет


    +
    program Project3;
    
    {$APPTYPE CONSOLE}
    {$R *.res}
    uses
      System.SysUtils;
    
    var
      Str: string = 'Test';
    
    begin
      try
        Str := Str + ' Hello';
        Writeln(Str);
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      Readln;
    
    end.
    


    Включаем отладчик, попадаем в функцию
    procedure _UStrCat(var Dest: UnicodeString; const Source: UnicodeString);
    


    Из неё попадаем в
    +
    procedure _UStrSetLength(var Str: UnicodeString; NewLength: Integer);
    var
      P: PStrRec;
      Temp: Pointer;
      CopyCount: Integer;
    begin
      if NewLength <= 0 then
        _UStrClr(Str)
      else
      begin
        if Pointer(Str) <> nil then
        begin
          if __StringRefCnt(Str) = 1 then
          begin
            P := Pointer(PByte(Str) - Sizeof(StrRec));
            if Cardinal(NewLength) >= Cardinal(- SizeOf(StrRec) - SizeOf(WideChar)) div 2 then
              _IntOver;
            _ReallocMem(Pointer(P), (NewLength + 1) * SizeOf(WideChar) + SizeOf(StrRec));
            P.length := NewLength;
            Pointer(Str) := Pointer(PByte(P) + SizeOf(StrRec));
            PWideChar(Str)[NewLength] := #0;
            Exit;
          end;
        end;
        Temp := _NewUnicodeString(NewLength);
        if Pointer(Str) <> nil then
        begin
          CopyCount := __StringLength(Str);
          if CopyCount > NewLength then
            CopyCount := NewLength;
          Move(PWideChar(Str)^, PWideChar(Temp)^, CopyCount * SizeOf(WideChar));
          _UStrClr(Str);
        end;
        Pointer(Str) := Temp;
      end;
    end;
    


    От сюда видим
    PWideChar(Str)[NewLength] := #0;
    


    Идём дальше, и проверяем PAnsiChar И в конечном итоге попадаем на выделение строки
    +
    function _NewUnicodeString(CharLength: Integer): Pointer;
    var
      P: PStrRec;
    begin
      Result := nil;
      if CharLength > 0 then
      begin
        // Allocate a memory with record and extra wide-null terminator.
        if CharLength >= (MaxInt - SizeOf(StrRec)) div SizeOf(WideChar) then _IntOver;
        GetMem(P, SizeOf(StrRec) + (CharLength + 1) * SizeOf(WideChar));
        Result := Pointer(PByte(P) + SizeOf(StrRec));
        P.length := CharLength;
        P.refCnt := 1;
        P.elemSize := SizeOf(WideChar);
        P.codePage := Word(DefaultUnicodeCodePage);
        PWideChar(Result)[CharLength] := #0;
      end;
    end;
    


    Где опять же видим
    PWideChar(Result)[CharLength] := #0;
    


    Чудом, не иначе

    +
    AnsiString type

     _PAnsiChr(Str)[NewLength] := #0;
    


    procedure _LStrSetLength(var Str: _AnsiStr; NewLength: Integer; CodePage: Word);
    var
      P: PStrRec;
      Temp: Pointer;
      CopyCount: Integer;
    begin
      if newLength <= 0 then
      begin
        _LStrClr(Str);
        Exit;
      end
      else
      begin
        if Pointer(Str) <> nil then
        begin
          if __StringRefCnt(Str) = 1 then
          begin
            P := Pointer(PByte(Str) - Sizeof(StrRec));
            _ReallocMem(Pointer(P), NewLength + 1 + SizeOf(StrRec));
            P.length := NewLength;
            Pointer(Str) := Pointer(PByte(P) + SizeOf(StrRec));
            _PAnsiChr(Str)[NewLength] := #0;
            Exit;
          end;
        end;
        Temp := _NewAnsiString(NewLength, CodePage);
        if Pointer(Str) = nil then
        begin
          Pointer(Str) := Temp;
          Exit;
        end;
        CopyCount := __StringLength(Str);
        if CopyCount > NewLength then
          CopyCount := NewLength;
        Move(_PAnsiChr(str)^, _PAnsiChr(Temp)^, CopyCount);
        _LStrClr(Str);
        Pointer(Str) := Temp;
      end;
    end;
    

    [/SRC]
    8 июн 19, 00:38    [21905006]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    makhaon
    Member

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

    Явного нуля в конце строки нет. Текущая частная реализация. Можно, конечно, заложиться. Но внезапно поменяется завтра что-то - и всё посыпется.
    8 июн 19, 15:15    [21905156]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    Kazantsev Alexey
    Member

    Откуда:
    Сообщений: 3820
    http://docwiki.embarcadero.com/RADStudio/Rio/en/Internal_Data_Formats_(Delphi)#Long_String_Types
    8 июн 19, 15:37    [21905163]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    shonli95
    Member

    Откуда:
    Сообщений: 85
    makhaon,

    есть, это легко проверить. Когда ты пытаешься вывести строку, она конвертируется не на стадии присвоения string к PWideChar а на выводе.


    +
    program Project3;
    
    {$APPTYPE CONSOLE}
    {$R *.res}
    uses
      System.SysUtils;
    
    var
      Str: string = 'Test';
      NStr: PWideChar;
    
    begin
      try
        Str := Str + ' Hello';
        NStr := PWideChar(Str);
        Writeln(NStr);
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      Readln;
    
    end.
    



    При вызове Writeln приведёт к тому, что строка будет скопирована


    procedure _UStrFromPWCharLen(var Dest: UnicodeString; Source: PWideChar; CharLength: Integer);
    var
      Temp: Pointer;
    begin
      Temp := Pointer(Dest);
      if CharLength > 0 then
      begin
        Pointer(Dest) := _NewUnicodeString(CharLength);
        if Source <> nil then
          Move(Source^, Pointer(Dest)^, CharLength * SizeOf(WideChar));
      end
      else
        Pointer(Dest) := nil;
      _UStrClr(Temp);
    end;
    


    И при создании данной строки, будет создана новая строка _NewUnicodeString ->


    function _NewUnicodeString(CharLength: Integer): Pointer;
    var
      P: PStrRec;
    begin
      Result := nil;
      if CharLength > 0 then
      begin
        // Allocate a memory with record and extra wide-null terminator.
        if CharLength >= (MaxInt - SizeOf(StrRec)) div SizeOf(WideChar) then _IntOver;
        GetMem(P, SizeOf(StrRec) + (CharLength + 1) * SizeOf(WideChar));
        Result := Pointer(PByte(P) + SizeOf(StrRec));
        P.length := CharLength;
        P.refCnt := 1;
        P.elemSize := SizeOf(WideChar);
        P.codePage := Word(DefaultUnicodeCodePage);
        PWideChar(Result)[CharLength] := #0;
      end;
    end;
    



    Где на конце, располагается символ конца строки
    10 июн 19, 10:06    [21905714]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    alekcvp
    Member

    Откуда:
    Сообщений: 1547
    GunSmoker
    Читай сюда: Разработка API (контракта) для своей DLL или: не создавайте своих DLL, не прочитав эту статью!.


    Мне кажется, или там ошибка в разделе "Выделенные функции"?
    var
      P: array of Something;  
      Data: Pointer;
      DataSize: DWORD;
    begin
      GetDynData(0, Data, DataSize); <---
     
      SetLength(P, DataSize div SizeOf(Something));
      Move(Data^, Pointer(P)^, DataSize);
      CoTaskMemFree(Data); ??!!!
       
      // Работаем с P
    end;
    
    10 июн 19, 11:24    [21905785]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    GunSmoker
    Member

    Откуда:
    Сообщений: 3110
    alekcvp, может у меня глаз замылился, в чём там вопрос?
    10 июн 19, 12:49    [21905866]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    shonli95
    Member

    Откуда:
    Сообщений: 85
    alekcvp,

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

    Это вам не delphi с его крутым менеджером

    К примеру
    +
      IMalloc = interface(IUnknown)
        ['{00000002-0000-0000-C000-000000000046}']
        function Alloc(cb: Longint): Pointer; stdcall;
        function Realloc(pv: Pointer; cb: Longint): Pointer; stdcall;
        procedure Free(pv: Pointer); stdcall;
        function GetSize(pv: Pointer): Longint; stdcall;
        function DidAlloc(pv: Pointer): Integer; stdcall;
        procedure HeapMinimize; stdcall;
      end;
    


    Имеет GetSize, но Free не принимает второго аргумента, что бы удалить определённое количество.

    Так же и там. Майки не дают делать программисту - то, что ему не нужно
    10 июн 19, 13:53    [21905916]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    alekcvp
    Member

    Откуда:
    Сообщений: 1547
    GunSmoker
    alekcvp, может у меня глаз замылился, в чём там вопрос?


    В том, что память выделяется через GetDynData(), а освобождается через CoTaskMemFree(), вместо FreeDynData() (или как там).
    10 июн 19, 14:37    [21905960]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    shonli95
    Member

    Откуда:
    Сообщений: 85
    alekcvp,


    function GetDynData(const AFlags: DWORD; out AData: Pointer; out ADataSize: DWORD): BOOL; stdcall;
    var
      P: array of Something;
    begin
      P := { ... готовим данные ... };
     
      ADataSize := Length(P) * SizeOf(Something);
      AData := CoTaskMemAlloc(ADataSize);
      Move(Pointer(P)^, AData^, ADataSize);
     
      Result := True;
    end;
    


    Идём на сайт
    https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-cotaskmemalloc

    Видим, что это аналог IMalloc::Alloc видим, что освобождение идёт через CoTaskMemFree что аналогично IMalloc::Free


    Ну а ваще Ок

    procedure FreeDynData(var Data);
    begin 
     CoTaskMemFree(Data);
    end;
    
    10 июн 19, 15:27    [21906003]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    RWolf
    Member

    Откуда: Казань
    Сообщений: 430
    GunSmoker
    // Неправильно!
    procedure DoSomething(const AArg: ISomething); safecall;
     
    // Правильно
    procedure DoSomething(AArg: ISomething); safecall;
    


    Это ведь означает лишние _AddRef/_Release на каждый вызов функции, разве нет? в чём выгода?
    10 июн 19, 16:34    [21906048]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    автор
    Не нужно делать реализацию методов интерфейса виртуальными:
    Бред. Если методы будут в дальнейшем переопределяться, то они должны быть виртуальными
    автор
    Не помечайте интерфейсные параметры модификатором const:
    с какого перепугу? Наоборот, они должны быть всегда c const, чтобы не дергать счетчик ссылок
    автор
    // Правильно
    procedure GetSomething(const AIID: TGUID; out Intf); safecall;
    
    Идея красивая. Но импортер Delphi не умеет импортировать
    ([out] void ** AOut)
    
    в
    (out AOut)
    
    . А каждый раз руками править замучаешься
    10 июн 19, 17:51    [21906109]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    Kazantsev Alexey
    Member

    Откуда:
    Сообщений: 3820
    _Vasilisk_
    с какого перепугу? Наоборот, они должны быть всегда c const, чтобы не дергать счетчик ссылок

    Вангую, это такая соломка от:
    DoSomething(TSomethingImplementor.Create);
    

    тут без явной (as) передачи интерфейса будет утечка, если интерфейсный параметр является константным.
    10 июн 19, 18:09    [21906123]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    Kazantsev Alexey
    Вангую, это такая соломка от:
    Зато будет сюрприз
    var
      Some: TSomethingImplementor;
    begin
      Some := TSomethingImplementor.Create;
      try
        DoSomething(Some);
      finally
        Some.Free;  // Surprise!
      end;
    end;
    

    У себя всегда пишу так
    TSomethingImplementor = class(..., ISomething)
    ................
    public
      class function CreateIntf: ISomething; inline;
    end;
    
    class function TSomethingImplementor.CreateIntf: ISomething; 
    begin
      Result := Self.Create;
    end;
    
    10 июн 19, 18:58    [21906153]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    Kazantsev Alexey
    Member

    Откуда:
    Сообщений: 3820
    _Vasilisk_
    Зато будет сюрприз

    А так не будет:
    DoSomething(TSomethingImplementor.Create As ISomething);
    

    Тут уж, либо с интерфейсами работаем, либо вручную объектами управляем.
    10 июн 19, 19:23    [21906161]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    alekcvp
    Member

    Откуда:
    Сообщений: 1547
    shonli95
    alekcvp,

    function GetDynData(const AFlags: DWORD; out AData: Pointer; out ADataSize: DWORD): BOOL; stdcall;
    var
      P: array of Something;
    begin
      P := { ... готовим данные ... };
     
      ADataSize := Length(P) * SizeOf(Something);
      AData := CoTaskMemAlloc(ADataSize);
      Move(Pointer(P)^, AData^, ADataSize);
     
      Result := True;
    end;
    




    Я же специально указал раздел "выделенные функции", там в dll другой код - найдите тут CoTaskMemAlloc:

    unction GetDynData(const AFlags: DWORD; out AData: Pointer; out ADataSize: DWORD): BOOL; stdcall;
    var
      P: array of Something;
    begin
      P := { ... готовим данные ... };
     
      ADataSize := Length(P) * SizeOf(Something);
      Pointer(AData) := Pointer(P); // копируем указатель, не копируем данные
      Pointer(P) := nil; // блокируем автоматическую очистку 
     
      Result := True;
    end;
     
    


    И текст из статьи, цитирую:
    Другой вариант - обернуть ваш предпочитаемый менеджер памяти в экспортируемую функцию. Соответственно, в документации к функции должно быть указано, что для освобождения памяти нужно вызывать не CoTaskMemFree (или что вы там использовали), а вашу функцию-обёртку.
    10 июн 19, 19:32    [21906169]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    shonli95
    Member

    Откуда:
    Сообщений: 85
    alekcvp,

    Всё - всё, понял - понял)
    10 июн 19, 20:13    [21906185]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    GunSmoker
    Member

    Откуда:
    Сообщений: 3110
    alekcvp, спасибо, исправил.
    11 июн 19, 03:03    [21906290]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    GunSmoker
    Member

    Откуда:
    Сообщений: 3110
    _Vasilisk_
    с какого перепугу?


    У меня под конец уже время закончилось, я уж не стал расписывать, тем более, что в блоге и так было. Так да, это "защита от дурака".
    11 июн 19, 03:12    [21906291]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    В статье про DLL предлагается использовать BSTR получения/передачи строковых данных.
    Пытаюсь в DLL, написанной в Delphi, возвращать строковое значение из функции в WideString (он же BSTR), но получается ерунда.
    Если DLL вызывать из программы написанной в Delphi то все хорошо, если вызывать из C++, то получаем ошибку "Out of memory".

    Код DLL:
    +
    library test_ws;
    
    uses
      System.SysUtils,
      Vcl.Dialogs;
    
    function TestWideString: WideString; stdcall;
    begin
      try
        Result := 'This is the result of TestWideString';
      except
        on E:Exception do
          ShowMessage('Delphi exception::TestWideString : ' + E.Message); // In C++ : Out of memory
      end;
    end;
    
    exports
      TestWideString;
    
    begin
    end.
    

    Вызов DLL из Delphi (все работает):
    +
    program test_ws_call;
    
    {$APPTYPE CONSOLE}
    
    uses
      Windows, System.SysUtils;
    
    type
      TTestWideString = function : WideString; stdcall;
    
    var
      LibHandle: THandle;
      TestWideString: TTestWideString;
      str: WideString;
    begin
      LibHandle := LoadLibrary('test_ws.dll');
      @TestWideString := GetProcAddress(LibHandle, 'TestWideString');
      str := TestWideString();
      Writeln(str);
    
      ReadLn;
    end.
    

    Вызов из C++ (ошибка "Out of memory"):
    +
    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    int main()
    {
        HMODULE lib = LoadLibrary("test_ws.dll");
    
        typedef BSTR (__stdcall *Func)();
        Func TestWideString = (Func) GetProcAddress(lib, "TestWideString");
    
        BSTR str = TestWideString();
        wprintf(L"%s\n", str);
        SysFreeString(str);
    
        return 0;
    }
    


    Что тут не так? Почему не работает?
    Или идея с BSTR не совсем рабочая?
    10 июл 19, 11:04    [21924033]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

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

    а так пробовал?
    typedef BSTR* (__stdcall *Func)();
    
    10 июл 19, 12:01    [21924081]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

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

    При таком варианте, компилятор выдает ошибку на строке вызова функции:
    error: cannot convert 'OLECHAR** {aka wchar_t**}' to 'BSTR {aka wchar_t*}' in initialization
    
    10 июл 19, 13:51    [21924175]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    Импорт должен быть таким
     typedef void (__stdcall *Func)(BSTR * res);
    

    Ссылку на документацию найти не могу, но для сложных возвращаемых типов (строки, записи, массивы) в Delphi функция превращается в процедуру с последним var параметром.

    Т.е. это
    SQL-Talker
    function TestWideString: WideString; stdcall;
    
    компилятор превращает в это
    procedure TestWideString(var Result: WideString); stdcall;
    
    10 июл 19, 16:18    [21924280]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    asutp2
    Member

    Откуда: Тюмень
    Сообщений: 543
    GunSmoker
    alekcvp, спасибо, исправил.


    GunSmoker, подкорректируйте плиз тогда и глобальный пример, который у вас приложен к статье :-)
    10 июл 19, 16:58    [21924310]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

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

    Заработало! Спасибо))
    10 июл 19, 17:06    [21924316]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

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

    лучше уж тогда safecall заюзать, однотипно будет хоть
    10 июл 19, 17:10    [21924318]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

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

    stdcall - требование заказчика
    10 июл 19, 17:31    [21924334]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

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

    да это и есть тот же stdcall, только результат функции всегда один и тот же тип
    10 июл 19, 18:13    [21924364]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    ziv-2014
    Member

    Откуда:
    Сообщений: 462
    kealon(Ruslan),
    stdcall и safecall - это не одно и тоже. При safecall результат возвращается в параметрах.
    10 июл 19, 19:32    [21924403]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

    Откуда: Нижневартовск
    Сообщений: 5211
    ziv-2014,

    а при stdcall это невозможно? :-)

    абсолютно тот же stdcall, только результат функции всегда HResult
    10 июл 19, 20:08    [21924414]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    Правильно ли я понимаю, что для функции типа
    function SomeFunction(Check: BOOL): BSTR; stdcall;
    

    В C++ импорт должен быть таким:
    typedef void (__stdcall *Func)(BOOL, BSTR * res);
    


    Пробую так делать - вылетает ошибка при выполнении.
    11 июл 19, 09:22    [21924529]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

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

    я бы предложил взять idl-ку какую ни будь из SDK как шаблон - компиляция там простая, и извращаться там (т.е. описывать всё на одном языке). Для Delphi и fpc тоже консолька импорта в pas есть.
    Так вы сможете понять как это будет выглядеть на других языках. Ну и конечно safecall, он удобнее.
    11 июл 19, 09:39    [21924550]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    ziv-2014
    Member

    Откуда:
    Сообщений: 462
    SQL-Talker
    Правильно ли я понимаю, что для функции типа
    function SomeFunction(Check: BOOL): BSTR; stdcall;
    

    В C++ импорт должен быть таким:
    typedef void (__stdcall *Func)(BOOL, BSTR * res);
    


    Пробую так делать - вылетает ошибка при выполнении.

    Так должно быть
    function SomeFunction(Check: BOOL): BSTR; safecall;
    


    HRESULT __stdcall SomeFunction(BOOL, BSTR &res);
    описание типа:
    typedef HRESULT (__stdcall *Func)(BOOL, BSTR &res);
    
    11 июл 19, 14:46    [21924954]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    ziv-2014
    Member

    Откуда:
    Сообщений: 462
    SQL-Talker,
    Лучше переходи на интерфейсы (interface), так больше возможностей получаешь.
    Получаешь типа такого на си++:
    +

      DECLARE_INTERFACE_IID_(ICMWebRTCNative, IUnknown, "{D7C7A33F-CCE8-403A-B95E-44F2DE7493D4}")
      {
        IUNKNOWN_METHODS_PURE()
        virtual HRESULT __stdcall InitializeSSL();
        virtual HRESULT __stdcall CleanupSSL();
        virtual HRESULT __stdcall AddIceServer(_In_ BSTR uri, _In_ BSTR username, _In_ BSTR password);
        virtual HRESULT __stdcall ClearIceServers();
        virtual HRESULT __stdcall InitializePeerConnection(_Out_ BOOL &init);
        virtual HRESULT __stdcall ClosePeerConnection();
        virtual HRESULT __stdcall ProcessMessages(_In_ int delay, _Out_ BOOL &result);
        virtual HRESULT __stdcall PushFrame(_In_ ICMVideoCapturer * capturer, _In_ BITMAPINFO bmi, _In_ uint8_t * image, _Out_ BOOL &result);
        virtual HRESULT __stdcall CreateOffer(_Out_ BOOL &result);
        virtual HRESULT __stdcall CreateAnswer(_In_ BSTR sdp, _Out_ BOOL &result);
        virtual HRESULT __stdcall AddIceCandidate(_In_ BSTR  sdp_mid, _In_ int sdp_mlineindex, _In_ BSTR sdp, _Out_ BOOL &result);
        virtual HRESULT __stdcall SetRemoteDescription(_In_ BSTR type, _In_ BSTR sdp, _Out_ BOOL &result);
        virtual HRESULT __stdcall CreateDataCanal(_In_ BSTR label, _Out_  BOOL &result);
        virtual HRESULT __stdcall CreateAudioStream(_In_ BSTR label, _In_ STREAMLIST ids, _In_ AUDIOPARAMS params, _Out_ BOOL &result);
        virtual HRESULT __stdcall CreateCameraStream(_In_ BSTR label, _In_ STREAMLIST ids, _In_ BSTR device_id, _In_ VIDEOINFO info, _In_ VIDEOPARAMS params, _Out_ BOOL &result);
        virtual HRESULT __stdcall CreateVideoStream(_In_ BSTR label, _In_ STREAMLIST ids, _In_ VIDEOINFO info, _In_ VIDEOPARAMS params, _Out_ ICMVideoCapturer * capturer, _Out_ BOOL &result);
      };
    



    Делфи:
    +

      ICMWebRTCNative = interface
        ['{D7C7A33F-CCE8-403A-B95E-44F2DE7493D4}']
        procedure InitializeSSL; safecall;
        procedure CleanupSSL; safecall;
        procedure AddIceServer(uri, username, password : CMString); safecall;
        procedure ClearIceServers(); safecall;
        function InitializePeerConnection : LongBool; safecall;
        procedure ClosePeerConnection; safecall;
        function ProcessMessages(delay : Integer) : LongBool; safecall;
        function PushFrame(const Capturer : ICMVideoCapturer; bmi : TBitmapInfo; image : PByte) : LongBool; safecall;
        function CreateOffer() : LongBool; safecall;
        function CreateAnswer(sdp : CMString) : LongBool; safecall;
        function AddIceCandidate(sdp_mid : CMString; sdp_mlineindex : Integer; sdp : CMString) : LongBool; safecall;
        function SetRemoteDescription(_type, sdp : CMString) : LongBool; safecall;
        function CreateDataCanal(_label : CMString) : LongBool; safecall;
        function CreateAudioStream(_label : CMString; ids : TStreamList; params : TAudioParams) : LongBool; safecall;
        function CreateCameraStream(_label : CMString; ids : TStreamList; device_id : CMString; Info : TVideoInfo; Params : TVideoParams) : LongBool; safecall;
        function CreateVideoStream(_label : CMString; ids : TStreamList; info : TVideoInfo; Params : TVideoParams; var capturer : ICMVideoCapturer) : LongBool; safecall;
      end;
    



    Красота :)
    11 июл 19, 14:51    [21924958]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    SQL-Talker
    Пробую так делать - вылетает ошибка при выполнении.
    Проверь sizeof(BOOL) в Си и Делфи. А лучше использовать типы с явным размером. Например, WordBool

    SQL-Talker
    - вылетает ошибка при выполнении.
    Где? Какая ошибка?

    ziv-2014
    Так должно быть
    Не должно
    11 июл 19, 15:01    [21924976]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

    Откуда: Нижневартовск
    Сообщений: 5211
    ziv-2014,

    кстати, вполне вариант, условия на статик линковку у него вроде нет, судя по тому что он динамически грузит функцию

    загрузил одну функцию возвращающую интерфейс и всё

    интерфейс в idl описал для надёжности, лепота...
    11 июл 19, 15:32    [21925016]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

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

    И в Delphi и в C++ sizeof(BOOL) = 4

    Вот исходники:
    Delphi DLL:
    +
    library test_ws_b;
    
    uses
      System.SysUtils,
      Vcl.Dialogs;
    
    function GetLastErrText_CH(Check: WordBool): WideString; stdcall;
    begin
      Pointer(Result) := nil;
      if Check then
        Result := 'This is the result of GetLastErrText - TRUE'
      else
        Result := 'This is the result of GetLastErrText - FALSE'
       ;
    end;
    
    exports
      GetLastErrText_CH;
    
    begin
    end.
    

    C++:
    +
    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    int main()
    {
        std::cout << "\nsizeof(BOOL) = " << sizeof(BOOL); // 4
        HMODULE lib = LoadLibrary("test_ws_b.dll");
        if (lib == NULL) {
            std::cout << "\nLibrary not loaded";
            return -1;
        };
    
        typedef void (__stdcall *Func)(BOOL, BSTR * res);
        Func GetLastErrText_CH = (Func) GetProcAddress(lib, "GetLastErrText_CH");
        if (GetLastErrText_CH == 0) {
            std::cout << "\nFunction GetLastErrText_CH not found in Library";
            return -2;
        };
    
        BSTR bstr;
        std::cout << "\nbefore call";
        GetLastErrText_CH(true, &bstr);
        std::cout << "\nafter call";
    
        setlocale(LC_ALL, "Russian_Russia.866");
        std::wcout << bstr;
    
        SysFreeString(bstr);
    
        return 0;
    }
    

    При выполнении си-шного кода, спотыкается об строку вызова функции из DLL и выдает в консоль "Process returned -1073741819 (0xC0000005)"
    Это если из IDE запускать (Code::Blocks), а так молча завершается
    11 июл 19, 15:50    [21925038]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    Пардон, заголовок функции в Delphi такой :
    function GetLastErrText_CH(Check: BOOL): WideString; stdcall;
    
    11 июл 19, 15:56    [21925044]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

    Откуда: Нижневартовск
    Сообщений: 5211
    SQL-Talker,
    если заменить
    BSTR bstr;
    

    на
    BSTR bstr=SysAllocString(L"new string");
    


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

    Откуда:
    Сообщений: 462
    SQL-Talker,
    Тогда так
    typedef BSTR * (__stdcall *Func)(BOOL);
    

    Или в делфи
    function GetLastErrText_CH(Check: WordBool): WideString; safecall;
    

    Указатель на строку будет в eax, так что смотри сами.
    Лучше передавать данные через параметры, а не как результат функции - так надежнее будет.
    11 июл 19, 16:22    [21925071]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    kealon(Ruslan)
    SQL-Talker,
    если заменить
    BSTR bstr;
    

    на
    BSTR bstr=SysAllocString(L"new string");
    


    что будет?

    Тоже самое - падает на вызове функции из DLL
    11 июл 19, 16:24    [21925072]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

    Откуда: Если есть на свете рай, это - ...
    Сообщений: 419
    Обернул код в Delphi в try .. except - получается что при вызове этой DLL из C++ там (в dll) вываливается Access Violation

    library test_ws_b;
    
    uses
      System.SysUtils,
      Windows,
      Vcl.Dialogs;
    
    function GetLastErrText_CH(Check: BOOL): WideString; stdcall;
    begin
      try
        Pointer(Result) := nil;
        if Check then
          Result := 'This is the result of GetLastErrText - TRUE'
        else
          'This is the result of GetLastErrText - FALSE'
         ;
      except
        on E:Exception do
          ShowMessage('Exception in Delphi DLL : ' + E.Message);
      end;
    end;
    
    exports
      GetLastErrText_CH;
    
    begin
    end.
    


    Спотыкается на строке
    Pointer(Result) := nil;

    Если ее убрать, спотыкается на
    Result := ...

    Т.е. что-то не так с Result


    При этом если эту DLL вызвать из проекта на Delphi же все работает норм
    11 июл 19, 16:33    [21925077]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    kealon(Ruslan)
    Member

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

    Pointer(Result) := nil; финализирует переданную строку

    я предположил что там мусор, когда задал вопрос 21925071

    но ...

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

    Откуда: Украина, Харьков
    Сообщений: 11193
    SQL-Talker
    Pointer(Result) := nil;
    
    Убрать. Это потенциальная утечка памяти.

    Вызывать так
    BSTR bstr= null;
    GetLastErrText_CH(true, &bstr);
    

    Далее, адреса &bstr и @Result должны совпадать. Проверьте это
    11 июл 19, 17:28    [21925122]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    ziv-2014
    Member

    Откуда:
    Сообщений: 462
    SQL-Talker, А тебя не смущает, что у тебя заголовки функций на Delphi и си они разные? В си ты передаешь 2 параметра (один BOOL, другой указатель и ничего не возвращаешь), а в делфи один параметр и один возвращаешь в результате? С чего бы должно работать-то? Стек поганишь само собой!
    11 июл 19, 17:30    [21925125]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

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

    Вот тут _Vasilisk_ пояснял эту особенность: 21924280
    Эта схема у меня работает на функциях без пходящих параметров, затык случился с функцией, у которой есть входной параметр
    11 июл 19, 18:00    [21925158]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

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

    Pointer(Result) := nil; - убрал

    в C++ вывожу адрес:
    cout << "\nbstr addr = " << &bstr;
    
    все Ок

    в DLL вывожу адрес:
    ShowMessage(Format('%x', [Integer(addr(Result))]));
    
    Если DLL вызывать из Delphi-кода, то отображается 16-ричное число
    А если из C++ то показывает строго 1 (единицу)
    11 июл 19, 18:05    [21925162]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    SQL-Talker,

    Посмотрел. Для stdcall Result передается как первый параметр. Т.е. импорт должен быть таким
        typedef void (__stdcall *Func)(BSTR*, BOOL);
    
    и вызов
    	BSTR bstr = nullptr;
        GetLastErrText_CH(&bstr, true);
    
    11 июл 19, 18:08    [21925166]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    SQL-Talker
    Member

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

    Взлетело!
    Вы просто волшебник ))
    Спасибо
    11 июл 19, 18:18    [21925178]     Ответить | Цитировать Сообщить модератору
     Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
    _Vasilisk_
    Member

    Откуда: Украина, Харьков
    Сообщений: 11193
    SQL-Talker
    Взлетело!
    И обратите внимание, в Delphi у вас используется WordBool, а в Си BOOL. Это разные типы. Приведитесь к общему знаменателю
    11 июл 19, 18:28    [21925187]     Ответить | Цитировать Сообщить модератору
    Топик располагается на нескольких страницах: 1 2 3 4      [все]
    Все форумы / Delphi Ответить