別の質問に対するDavidの回答は、DelphiDLL関数が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は、長さの制限付きでそのバッファに書き込みます。呼び出し元は、メモリの割り当てと割り当て解除を行います。
もう1つのオプションは、DLLがたとえばを使用してメモリをLocalAlloc
割り当て、呼び出し元がを呼び出してメモリの割り当てを解除することLocalFree
です。
DLLの例では、メモリの割り当てと割り当て解除はどのように機能しますか?WideString
結果が( )であるため、「魔法」は起こりBSTR
ますか?そして、なぜWindows APIはそのような便利な規則で宣言されないのですか?(そのような規則を使用する既知のWin32 APIはありますか?)
編集:
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!
これがフォローアップです。