Почему библиотеки DLL Delphi могут использовать WideString без использования ShareMem?

В ответе Дэвида на другой вопрос показана функция Delphi DLL, возвращающая WideString. Я никогда не думал, что это возможно без использования ShareMem .

Моя тестовая DLL:

function SomeFunction1: Widestring; stdcall;
begin
  Result := 'Hello';
end;

function SomeFunction2(var OutVar: Widestring): BOOL; stdcall;
begin
  OutVar := 'Hello';
  Result := True;
end;

Моя вызывающая программа:

function SomeFunction1: WideString; stdcall; external 'Test.dll';
function SomeFunction2(var OutVar: Widestring): BOOL; stdcall; external 'Test.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
  W: WideString;
begin
  ShowMessage(SomeFunction1);
  SomeFunction2(W);
  ShowMessage(W);
end;

Она работает , и я не понимаю, как. Я знаю соглашение, используемое Windows API, например Windows GetClassNameW :

function GetClassNameW(hWnd: HWND; lpClassName: PWideChar; nMaxCount: Integer): Integer; stdcall;

Это означает, что вызывающий объект предоставляет буфер и максимальную длину. Windows DLL записывает в этот буфер с ограничением длины. Вызывающий абонент выделяет и освобождает память.

Другой вариант состоит в том, что DLL выделяет память, например, с помощью LocalAlloc , а вызывающий объект освобождает память, вызывая LocalFree .

Как распределение и освобождение памяти работает с моим примером DLL? "Волшебство" происходит из-за того, что результатом является WideString ( BSTR )? И почему API Windows не объявлены с таким удобным соглашением? (Существуют ли какие-либо известные API-интерфейсы Win32, использующие такое соглашение?)


РЕДАКТИРОВАТЬ:

Я протестировал DLL с помощью C #.
Вызов SomeFunction1 вызывает AV ( Попытка чтения или записи в защищенную память ).
SomeFunction2 работает нормально.

[DllImport(@"Test.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string SomeFunction1();

[DllImport(@"Test.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SomeFunction2([MarshalAs(UnmanagedType.BStr)] out string res);

...

string s;
SomeFunction2(out s);
MessageBox.Show(s); // works ok
MessageBox.Show(SomeFunction1()); // fails with AV!

Вот продолжение .

21
задан Community 23 May 2017 в 12:00
поделиться