Ответ Дэвида на другой вопрос показывает функцию DLL Delphi, возвращающую 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 (Attempted to read or write protected memory
).
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!
Вот продолжение .