powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
25 сообщений из 87, страница 2 из 4
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
25 сообщений из 87, страница 2 из 4
Форумы / Delphi [игнор отключен] [закрыт для гостей] / DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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