David's answer to another question pokazuje funkcję DLL Delphi zwracającą WideString. Nigdy nie sądziłem, że było to możliwe bez użycia ShareMem
.Dlaczego biblioteki DLL Delphi mogą korzystać z WideString bez korzystania z ShareMem?
Moje testy DLL:
function SomeFunction1: Widestring; stdcall;
begin
Result := 'Hello';
end;
function SomeFunction2(var OutVar: Widestring): BOOL; stdcall;
begin
OutVar := 'Hello';
Result := True;
end;
Mój program rozmówcy:
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;
Działa, a ja nie rozumiem, jak to zrobić. Konwencja znam jest używany przez Windows API, na przykład w systemie Windows GetClassNameW
:
function GetClassNameW(hWnd: HWND; lpClassName: PWideChar; nMaxCount: Integer): Integer; stdcall;
Znaczenie rozmówcę zapewnia bufor, a maksymalna długość. Biblioteka DLL systemu Windows zapisuje do tego bufora z ograniczeniem długości. Wywołujący przydziela i zwalnia pamięć.
Inną opcją jest to, że biblioteka DLL przydziela pamięć, na przykład za pomocą LocalAlloc
, a osoba wywołująca zwolni pamięć, dzwoniąc pod numer LocalFree
.
jaki sposób alokacji pamięci i praca dealokacji z moim przykładzie DLL? Czy "magia" ma miejsce, ponieważ wynikiem jest WideString
(BSTR
)? I dlaczego nie są deklarowane interfejsy API Windows z tak wygodną konwencją? (Czy są jakieś znane API Win32, który używa takiej konwencji?)
EDIT:
testowałem DLL z C#.
Wywołanie SomeFunction1
powoduje AV (Attempted to read or write protected memory
).
SomeFunction2
działa dobrze.
[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!
Oto followup.
Dzięki za odpowiedź. Spójrz [tutaj] (http://stackoverflow.com/a/5007216/937125). rozumiem, że biblioteka DLL powinna wywoływać 'CoTaskMemAlloc'. czy Delphi wywołuje to przy alokacji 'WideString'? także, kiedy wywoływane jest 'CoTaskMemFree'? – kobik
Funkcje 'SysXXX' tworzą niezbędne wywołania do przydziału COM. –
Link w twoim komentarzu po prostu stwierdza, że element p/invoke marshaller zakłada, że zwracana wartość typu 'string' została przydzielona z' CoTaskMemAlloc' i dlatego wywołuje 'CoTaskMemFree' po zakończeniu sortowania. –