powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
87 сообщений из 87, показаны все 4 страниц
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815407
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Возникла необходимость на Delphi написать DLL в которой функция должна возвращать массив записей типа :
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
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++ это разные вещи.

У кого был такой опыт подскажите как тут быть, с какой стороны подойти...
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815410
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker
Код: pascal
1.
2.
3.
4.
5.
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
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815431
ёёёёё
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

не, нельзя управляемые типы (string, объекты).
Можно, если использовать COM(OLE), вебсервисы и проч.
Можно упаковывать в портабельные форматы (json, xml).
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815437
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
Используй интерфейсы.
Строки передавай в widestring, pansichar, pchar, pwidechar.
Не используй управляемые типы.
Используй метод передачи параметров safecall или stdcall, cdecl (для java).
Не возвращай записи в результате функции. В функции возвращаешь результат работы функции или код ошибки.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815438
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
В какой DLL выделил память в той и удаляешь.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815444
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И делай структуры packed, чтобы не налететь на разницу в выравнивании. Либо явно задавай размер выравнивания
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815446
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014Используй интерфейсы.

Вовсе не обязательно. Большой оверхед во многих случаях
Не возвращай записи в результате функции. В функции возвращаешь результат работы функции или код ошибки.
Можно, но не обязательно
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815529
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий 2Не возвращай записи в результате функции. В функции возвращаешь результат работы функции или код ошибки.
Можно, но не обязательно
Разные языки программирования по разному возвращают структуры, как результат функции.
С# и Delphi не совместимы и будет эксепшен.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39815619
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

От managed-типов придётся отказаться, либо "выводить" функции для управления ими

К дельфи-специфичным типам вроде TDateTime тоже лучше не прибегать. Возьми аналоги, например Linux Time

С масивом всё просто, смотри похожие функции в WinAPI, там везде функция имеет два логичесикх варианта вызова: определение необходимого размера и собственно сама работа. Т.е. необходимую память выделяет вызывающая сторона.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819368
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пытаюсь вернуть строку из DLL.
Пишу в таком духе:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
// процедура в 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;



вот так пытаюсь ее прочитать из внешней программы:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
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 в итоге оказывается мусор из иероглифов

В чем ошибка?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819394
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
зачем
Код: pascal
1.
GetMemory(Size * 2);


если
Код: pascal
1.
dwSize := Length(OutStr) * 2;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819404
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cptngrb,

Вы правы, промашка. Но это не решает проблему.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819407
Александр Спелицин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-TalkerВ чем ошибка?
Например в том, что несколько вызовов PChar(Buffer) не гарантируют одного и того же результата.
Убирайте Ваш PChar() и передавайте уже саму переменную Buffer, как ссылку на выделенный участок памяти.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819419
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker, а
Код: pascal
1.
Buffer: LPWSTR

и
Код: pascal
1.
Pchar(PChar)

одно и тоже?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819421
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-TalkerВ чем ошибка?Во всем. Начиная с записи в пустоту
SQL-Talker
Код: pascal
1.
Buffer := StrNew(PChar(OutStr));


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
// процедура в 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;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819422
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
// процедура в 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;



Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
// внешняя программа
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;


Все равно не получаю то что надо...
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819424
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В моем примере заменить
_Vasilisk_
Код: pascal
1.
MyStr: String;

на
Код: pascal
1.
MyStr: WideString;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819425
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
Код: pascal
1.
2.
3.
4.
var
  MyStr: String;
   Buffer: PChar;
MyStr := Buffer;



и вы будете менять pchar, pansichar, widestring, string то ничего не получиться. подбором может только случайно получиться
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819427
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

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

Буду разбирать, чего я в этой технологии не понимаю.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819440
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

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

Память мы выделяем функцией SetLength. В Делфи все строки заканчиваются \0, поэтому SetLength автоматически выделит память под этот \0. Отсюда -1
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819452
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

авторВ Делфи все строки заканчиваются \0
это где так?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819454
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaonавторВ Делфи все строки заканчиваются \0это где так?Везде
Код: pascal
1.
2.
3.
4.
5.
6.
7.
Str: string;
begin
  Str := 'abc';
  ShowMessage(IntToStr(Ord(
    Str[Length(Str)] + 1
  )));
end;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819456
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon,

А как, по твоему, работает привидение к PChar?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819476
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

авторА как, по твоему, работает привидение к PChar?
чудом, не иначе
включи range check, узнаешь много нового. никакого нуля сзади строки нет. ну и посмотри как приведение работает. подсказка: UStrToPWChar.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819478
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaonвключи range check,Мы сейчас говорим о корректности обращении к символу строки за пределами ее длины или о физическом состоянии памяти?
makhaonподсказка: UStrToPWChar.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
function _UStrToPWChar(const S: UnicodeString): PWideChar;
begin
  if Pointer(S) = nil then
    Result := @(PEmptyString(@EmptyStringW[1])^.Nul)
  else
    Result := Pointer(S);
end;

и что я должен был тут увидеть? То, что просто возвращается указатель на строку? Которая, внезапно, оказывается нуль-терминатной?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819486
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

в документации описано про гарантированный ноль в конце строки?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819537
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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:
Код: pascal
1.
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.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819619
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а я видел строки без /0 и с /0 посередине ))
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819652
RWolf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cptngrbа я видел строки без /0 и с /0 посередине ))
вот прямо string без завершающего нуля?
это, наверно, ошибка в программе была. Delphi всегда выделяет памяти на символ больше длины строки и пишет 0 в лишний символ.
В самой строке нулей может быть сколько угодно, конечно.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819655
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RWolf, конечно ошибка, но я то думал, что такого не бывает
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819658
Фотография Квейд
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon_Vasilisk_,

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

Есть

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

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

Код: pascal
1.
2.
3.
4.
5.
6.
7.
function _UStrToPWChar(const S: UnicodeString): PWideChar;
begin
  if Pointer(S) = nil then
    Result := @(PEmptyString(@EmptyStringW[1])^.Nul)
  else
    Result := Pointer(S);
end;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819731
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ок, уговорили, черти красноречивые
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819848
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cptngrbа я видел строки без /0 и с /0 посередине ))И что? Это не противоречит тому, что строка оканчивается \0

Вот при касте к PChar такой строки она обрежется до серединного \0. Вернее, если принимающая сторона считает длину строки по завершающему \0, то она прочитает только часть строки
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819954
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_, вы категорично заявляли, что заканчивается 0.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39819956
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_Вот при касте к PChar такой строки она обрежется до серединного \0. Вернее, если принимающая сторона считает длину строки по завершающему \0, то она прочитает только часть строки

вот и приходилось нолик игнорировать в середине
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39820002
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cptngrb_Vasilisk_, вы категорично заявляли, что заканчивается 0.да, заканчивается, но это никак не исключает, что нулей может быть больше одного, завершающего

"Те кто говорят, что у Кутозова не было одного глаза, нагло врут. Один глаз у него был!!!"
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824331
GunSmoker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824354
shonli95
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
makhaon никакого нуля сзади строки нет

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
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.



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



Из неё попадаем в
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
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;



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



Идём дальше, и проверяем PAnsiChar И в конечном итоге попадаем на выделение строки
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
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;



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



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

AnsiString type

Код: pascal
1.
 _PAnsiChr(Str)[NewLength] := #0;



Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
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]
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824438
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shonli95,

Явного нуля в конце строки нет. Текущая частная реализация. Можно, конечно, заложиться. Но внезапно поменяется завтра что-то - и всё посыпется.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824443
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824801
shonli95
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
makhaon,

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


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
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 приведёт к тому, что строка будет скопирована


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
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 ->


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
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;




Где на конце, располагается символ конца строки
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824854
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GunSmokerЧитай сюда: Разработка API (контракта) для своей DLL или: не создавайте своих DLL, не прочитав эту статью! .

Мне кажется, или там ошибка в разделе "Выделенные функции"?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
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;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824910
GunSmoker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp, может у меня глаз замылился, в чём там вопрос?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824939
shonli95
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alekcvp,

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

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

К примеру
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
  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 не принимает второго аргумента, что бы удалить определённое количество.

Так же и там. Майки не дают делать программисту - то, что ему не нужно
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824966
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GunSmokeralekcvp, может у меня глаз замылился, в чём там вопрос?

В том, что память выделяется через GetDynData(), а освобождается через CoTaskMemFree(), вместо FreeDynData() (или как там).
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39824994
shonli95
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alekcvp,


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
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


Ну а ваще Ок

Код: pascal
1.
2.
3.
4.
procedure FreeDynData(var Data);
begin 
 CoTaskMemFree(Data);
end;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825020
RWolf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GunSmoker
Код: pascal
1.
2.
3.
4.
5.
// Неправильно!
procedure DoSomething(const AArg: ISomething); safecall;
 
// Правильно
procedure DoSomething(AArg: ISomething); safecall;



Это ведь означает лишние _AddRef/_Release на каждый вызов функции, разве нет? в чём выгода?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825055
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторНе нужно делать реализацию методов интерфейса виртуальными:Бред. Если методы будут в дальнейшем переопределяться, то они должны быть виртуальными
авторНе помечайте интерфейсные параметры модификатором const:с какого перепугу? Наоборот, они должны быть всегда c const, чтобы не дергать счетчик ссылок
автор
Код: pascal
1.
2.
// Правильно
procedure GetSomething(const AIID: TGUID; out Intf); safecall;

Идея красивая. Но импортер Delphi не умеет импортировать
Код: plaintext
1.
([out] void ** AOut)

в
Код: pascal
1.
(out AOut)

. А каждый раз руками править замучаешься
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825065
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_с какого перепугу? Наоборот, они должны быть всегда c const, чтобы не дергать счетчик ссылок
Вангую, это такая соломка от:
Код: pascal
1.
DoSomething(TSomethingImplementor.Create);


тут без явной ( as ) передачи интерфейса будет утечка, если интерфейсный параметр является константным.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825089
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev AlexeyВангую, это такая соломка от:Зато будет сюрприз
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
var
  Some: TSomethingImplementor;
begin
  Some := TSomethingImplementor.Create;
  try
    DoSomething(Some);
  finally
    Some.Free;  // Surprise!
  end;
end;


У себя всегда пишу так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
TSomethingImplementor = class(..., ISomething)
................
public
  class function CreateIntf: ISomething; inline;
end;

class function TSomethingImplementor.CreateIntf: ISomething; 
begin
  Result := Self.Create;
end;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825095
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_Зато будет сюрприз
А так не будет:
Код: pascal
1.
DoSomething(TSomethingImplementor.Create As ISomething);


Тут уж, либо с интерфейсами работаем, либо вручную объектами управляем.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825099
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shonli95alekcvp,

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
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:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
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 (или что вы там использовали), а вашу функцию-обёртку .
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825110
shonli95
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alekcvp,

Всё - всё, понял - понял)
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825156
GunSmoker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp, спасибо, исправил.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825157
GunSmoker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_с какого перепугу?

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

Код DLL:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
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 (все работает):
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
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"):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
#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 не совсем рабочая?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39835888
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

а так пробовал?
Код: plaintext
1.
typedef BSTR* (__stdcall *Func)();
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39835952
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan),

При таком варианте, компилятор выдает ошибку на строке вызова функции:
Код: sql
1.
error: cannot convert 'OLECHAR** {aka wchar_t**}' to 'BSTR {aka wchar_t*}' in initialization
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836017
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Импорт должен быть таким
Код: plaintext
1.
 typedef void (__stdcall *Func)(BSTR * res);


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

Т.е. это
SQL-Talker
Код: pascal
1.
function TestWideString: WideString; stdcall;

компилятор превращает в это
Код: pascal
1.
procedure TestWideString(var Result: WideString); stdcall;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836032
asutp2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GunSmokeralekcvp, спасибо, исправил.

GunSmoker, подкорректируйте плиз тогда и глобальный пример, который у вас приложен к статье :-)
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836036
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

Заработало! Спасибо))
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836038
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

лучше уж тогда safecall заюзать, однотипно будет хоть
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836050
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan),

stdcall - требование заказчика
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836067
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

да это и есть тот же stdcall, только результат функции всегда один и тот же тип
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836090
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan),
stdcall и safecall - это не одно и тоже. При safecall результат возвращается в параметрах.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836096
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014,

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

абсолютно тот же stdcall, только результат функции всегда HResult
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836170
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Правильно ли я понимаю, что для функции типа
Код: pascal
1.
function SomeFunction(Check: BOOL): BSTR; stdcall;


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



Пробую так делать - вылетает ошибка при выполнении.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836180
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

я бы предложил взять idl-ку какую ни будь из SDK как шаблон - компиляция там простая, и извращаться там (т.е. описывать всё на одном языке). Для Delphi и fpc тоже консолька импорта в pas есть.
Так вы сможете понять как это будет выглядеть на других языках. Ну и конечно safecall, он удобнее.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836399
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-TalkerПравильно ли я понимаю, что для функции типа
Код: pascal
1.
function SomeFunction(Check: BOOL): BSTR; stdcall;


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



Пробую так делать - вылетает ошибка при выполнении.
Так должно быть
Код: pascal
1.
function SomeFunction(Check: BOOL): BSTR; safecall;



Код: plaintext
1.
2.
3.
HRESULT __stdcall SomeFunction(BOOL, BSTR &res);
описание типа:
typedef HRESULT (__stdcall *Func)(BOOL, BSTR &res);
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836401
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
Лучше переходи на интерфейсы (interface), так больше возможностей получаешь.
Получаешь типа такого на си++:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
  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);
  };




Делфи:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
  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;




Красота :)
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836411
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-TalkerПробую так делать - вылетает ошибка при выполнении.Проверь sizeof(BOOL) в Си и Делфи. А лучше использовать типы с явным размером. Например, WordBool

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

ziv-2014Так должно бытьНе должно
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836437
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014,

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

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

интерфейс в idl описал для надёжности, лепота...
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836451
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

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

Вот исходники:
Delphi DLL:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
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++:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
#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), а так молча завершается
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836455
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пардон, заголовок функции в Delphi такой :
Код: pascal
1.
function GetLastErrText_CH(Check: BOOL): WideString; stdcall;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836464
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
если заменить
Код: plaintext
1.
BSTR bstr;


на
Код: plaintext
1.
BSTR bstr=SysAllocString(L"new string");



что будет?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836465
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
Тогда так
Код: plaintext
1.
typedef BSTR * (__stdcall *Func)(BOOL);


Или в делфи
Код: pascal
1.
function GetLastErrText_CH(Check: WordBool): WideString; safecall;


Указатель на строку будет в eax, так что смотри сами.
Лучше передавать данные через параметры, а не как результат функции - так надежнее будет.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836466
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)SQL-Talker,
если заменить
Код: plaintext
1.
BSTR bstr;


на
Код: plaintext
1.
BSTR bstr=SysAllocString(L"new string");



что будет?
Тоже самое - падает на вызове функции из DLL
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836469
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Обернул код в Delphi в try .. except - получается что при вызове этой DLL из C++ там (в dll) вываливается Access Violation

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
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 же все работает норм
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836489
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

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

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

но ...

сделайте ассемблерный листинг, гнуса нет посмотреть
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836500
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker
Код: pascal
1.
Pointer(Result) := nil;

Убрать. Это потенциальная утечка памяти.

Вызывать так
Код: plaintext
1.
2.
BSTR bstr= null;
GetLastErrText_CH(true, &bstr);


Далее, адреса &bstr и @Result должны совпадать. Проверьте это
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836501
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker, А тебя не смущает, что у тебя заголовки функций на Delphi и си они разные? В си ты передаешь 2 параметра (один BOOL, другой указатель и ничего не возвращаешь), а в делфи один параметр и один возвращаешь в результате? С чего бы должно работать-то? Стек поганишь само собой!
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836515
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014,

Вот тут _Vasilisk_ пояснял эту особенность: 21924280
Эта схема у меня работает на функциях без пходящих параметров, затык случился с функцией, у которой есть входной параметр
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836518
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

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

в C++ вывожу адрес:
Код: plaintext
1.
cout << "\nbstr addr = " << &bstr;

все Ок

в DLL вывожу адрес:
Код: pascal
1.
ShowMessage(Format('%x', [Integer(addr(Result))]));

Если DLL вызывать из Delphi-кода, то отображается 16-ричное число
А если из C++ то показывает строго 1 (единицу)
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836522
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

Посмотрел. Для stdcall Result передается как первый параметр. Т.е. импорт должен быть таким
Код: plaintext
1.
    typedef void (__stdcall *Func)(BSTR*, BOOL);

и вызов
Код: plaintext
1.
2.
	BSTR bstr = nullptr;
    GetLastErrText_CH(&bstr, true);
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836532
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

Взлетело!
Вы просто волшебник ))
Спасибо
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836540
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-TalkerВзлетело!И обратите внимание, в Delphi у вас используется WordBool, а в Си BOOL. Это разные типы. Приведитесь к общему знаменателю
...
Рейтинг: 0 / 0
87 сообщений из 87, показаны все 4 страниц
Форумы / Delphi [игнор отключен] [закрыт для гостей] / DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]