稍微不同的方法是将每个内存流包装为 IStream,并传递生成的接口引用。所以,从 DLL 的角度来看:
uses
System.SysUtils, System.Classes, Vcl.AxCtrls;
procedure DoProcess(InStream, OutStream: TStream);
begin
//...do the actual processing here
end;
//wrapper export
procedure Process(AInStream: IStream; out AOutStream: IStream); safecall;
var
InStream, OutStream: TStream;
begin
InStream := TOleStream.Create(AInStream);
try
OutStream := TMemoryStream.Create;
try
DoProcess(InStream, OutStream);
AOutStream := TStreamAdapter.Create(OutStream, soOwned);
except
OutStream.Free;
raise;
end;
finally
InStream.Free;
end;
end;
就我个人而言,我也喜欢使用 safecall,因为这是一种实现异常安全的简单方法,但我想这是一个品味问题。
Edit
上述的一个变体是让调用者提供要读取的流and要写入的流:
//wrapper export
procedure Process(AInStream, AOutStream: IStream); safecall;
var
InStream, OutStream: TStream;
begin
InStream := TOleStream.Create(AInStream);
try
OutStream := TOleStream.Create(AOutStream);
try
DoProcess(InStream, OutStream);
finally
OutStream.Free;
end;
finally
InStream.Free;
end;
end;
EXE 端可能看起来像这样:
//wrapper import
type
TDLLProcessProc = procedure(AInStream, AOutStream: IStream); safecall;
procedure Process(AInStream, AOutStream: TStream);
var
InStream, OutStream: IStream;
DLLProc: TDLLProcessProc;
Module: HMODULE;
begin
InStream := TStreamAdapter.Create(AInStream, soReference);
OutStream := TStreamAdapter.Create(AOutStream, soReference);
Module := LoadLibrary(MySuperLib);
if Module = 0 then RaiseLastOSError;
try
DLLProc := GetProcAddress(Module, 'Process');
if @DLLProc = nil then RaiseLastOSError;
DLLProc(InStream, OutStream);
finally
FreeLibrary(Module);
end;
end;