How do I pass and retrieve memory stream from my Application to/from DLL?

前端 未结 3 2138
心在旅途
心在旅途 2021-02-10 16:54

Suppose I have a TMemoryStream I need to pass to my DLL and get back TMemoryStream (Bitmap stream) from the DLL.

I was thinking my DLL would ha

3条回答
  •  故里飘歌
    2021-02-10 17:17

    A slightly different approach is to wrap each memory stream up as a IStream, and pass around the resulting interface references. So, from the DLL's side:

    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;
    

    Personally I like using safecall as well because it's an easy way to be exception-safe, but I guess that's a matter of taste.

    Edit

    A variant of the above is to have the caller provide both the stream to read and a stream to write to:

    //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;
    

    The EXE side might then look something like this:

    //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;
    

提交回复
热议问题