Unexpected thread behavior causing Delphi DLL

Continue with my other question: How do I transfer and receive a memory stream from my application to / from a DLL?

I wrote a DLL using IStreamboth input / output . The DLL uses IXMLDocument(which at first I thought was related to the subsequent problem) Tested it and it worked well in the main user interface. The problems started when I called the DLL from the workflow.

DLL:

library MyDLL;

uses
  Windows,
  Variants,
  SysUtils,
  Classes,
  AxCtrls,
  ActiveX,
  XMLDoc,
  XMLIntf;

{$R *.res}    

procedure Debug(V: Variant);
begin
  OutputDebugString(PChar(VarToStr(V)));
end;

procedure DoProcess(InStream, OutStream: TStream);
var
  Doc: IXMLDocument;
begin
  InStream.Position := 0;
  Doc := TXMLDocument.Create(nil);
  Doc.LoadFromStream(InStream);
  // plans to do some real work...
  OutStream.Position := 0;
  Debug('MyDLL DoProcess OK');
end;

function Process(AInStream, AOutStream: IStream): Integer; stdcall;
var
  InStream, OutStream: TStream;
begin
  try
    InStream := TOleStream.Create(AInStream);
    try
      OutStream := TOleStream.Create(AOutStream);
      try
        DoProcess(InStream, OutStream);
        Result := 0;
      finally
        OutStream.Free;
      end;
    finally
      InStream.Free;
    end;
  except
    on E: Exception do
    begin
      Result := -1;
      Debug('MyDLL Error: ' + E.Message);
    end;
  end;
end;

exports
  Process;

begin
end.

And my caller app:

implementation

uses
  ActiveX,ComObj;

{$R *.dfm}

procedure Debug(V: Variant);
begin
  OutputDebugString(PChar(VarToStr(V)));
end;

const
  MyDLL = 'MyDLL.dll';

{$DEFINE STATIC_DLL}
{$IFDEF STATIC_DLL}
function Process(AInStream, AOutStream: IStream): Integer; stdcall; external MyDLL;
{$ENDIF}

type
  // Dynamic
  TDLLProcessProc = function(AInStream, AOutStream: IStream): Integer; stdcall;

function DLLProcess(AInStream, AOutStream: TStream): Integer;
var
  InStream, OutStream: IStream;
  Module: HMODULE;
  DLLProc: TDLLProcessProc;
begin
  InStream := TStreamAdapter.Create(AInStream, soReference);
  OutStream := TStreamAdapter.Create(AOutStream, soReference);
{$IFDEF STATIC_DLL}
  Result := Process(InStream, OutStream); // Static
  Exit;
{$ENDIF}
  // Dynamic load DLL ...
  Module := LoadLibrary(MyDLL);
  if Module = 0 then RaiseLastOSError;
  try
    DLLProc := GetProcAddress(Module, 'Process');
    if @DLLProc = nil then RaiseLastOSError;
    Result := DLLProc(InStream, OutStream);
  finally
    FreeLibrary(Module);
  end;
end;

type
  TDLLThread = class(TThread)
  private
    FFileName: string;
  public
    constructor Create(CreateSuspended: Boolean; AFileName: string);
    procedure Execute(); override;
  end;

constructor TDLLThread.Create(CreateSuspended: Boolean; AFileName: string);
begin
  FreeOnTerminate := True;
  FFileName := AFileName;
  inherited Create(CreateSuspended);
end;

procedure TDLLThread.Execute;
var
  InStream, OutStream: TMemoryStream;
  RetValue: Integer;
begin
  try
    //CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
    CoInitialize(nil);
    try
      InStream := TMemoryStream.Create;
      try
        InStream.LoadFromFile(FFileName);
        OutStream := TMemoryStream.Create;
        try
          RetValue := DLLProcess(InStream, OutStream);
          Sleep(0);
          Debug('TDLLThread Result=> ' + IntToStr(RetValue));
          if RetValue = 0 then
          begin
            Debug('TDLLThread OK');
          end;
        finally
          OutStream.Free;
        end;
      finally
        InStream.Free;
      end;
    finally
      CoUninitialize;
    end;
  except
    on E: Exception do
    begin
      Debug('TDLLThread Error: ' + E.Message);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject); // Test
var
  I: Integer;
begin
  for I := 1 to 5 do
    TDLLThread.Create(False, '1.xml');
end;

When performing some tests, I sometimes get access violations that even exception blocks cannot catch. And the program just crashes with Runtime error 216 at xxxxxxxor Invalid pointer operation.

, DLL ( ), LoadLibrary/FreeLibrary).

, IXMLDocument :

Doc := TXMLDocument.Create(nil);
Doc.LoadFromStream(InStream);

:

.

:

.

, , . , , AVs!

, DLL . , DLLMain.

, ... - , ? ( - ?)


EDIT: ( IsMultiThread): Delphi DLL -

IsMultiThread: IsMultiThread

+4
1

Delphi . . , . , IsMultiThread True.

, Delphi, IsMultiThread True . , IsMultiThread True. DLL. .dpr :

begin
  IsMultiThread := True;
end.
+4

Source: https://habr.com/ru/post/1620734/


All Articles