Skip to content

using python4delphi via compiled DLL, avoids reading variables from python to delphi #472

Closed
@mp1609

Description

@mp1609

Hi there,

I got a strange issue when using python4delphi as a DLL.
I have a running demo (compiled as "exe" file) which is working:

FYI using the current latest code of this repo.

program ProjectWorking;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Classes,
  System.Variants,
  System.Diagnostics,
  WinApi.Windows,
  IOUtils,
  PythonEngine,
  VarPyth;

{$R *.res}


const
  coPythonFolder = 'python-3.8.3-embed-win32';

type
  TArrayOfDouble = TArray<double>;


var
  PythonEngine : TPythonEngine;
  cmd          : TStringList;

procedure CreatePythonEnvironment;
begin
end;

procedure CreatePyEngine;
begin
  PythonEngine := TPythonEngine.Create(nil);
  PythonEngine.Name := 'PythonEngine';

  with PythonEngine do
  begin
    APIVersion          := 1013;
    AutoLoad            := False;
    AutoUnload          := true;
    AutoFinalize        := true;
    UseLastKnownVersion := false;
    DllName := 'python38.dll';
    DllPath := GetCurrentDir + '\' + coPythonFolder;

    PyFlags := [];
  end;

  PythonEngine.LoadDll;
end;

procedure DestroyEngine;
begin
  PythonEngine.Free;
end;

procedure demo;  stdcall;
var
  foo   : Variant;
var
  taps,
  freq,
  gain : TArrayOfDouble;
begin
  freq := [0, 0.5, 1];
  gain := [0,   1, 0];

  try
    cmd.Clear;
    cmd.Add('N = [0,1,2,3,4,5,6,7,8,9,10]');

    PythonEngine.ExecStrings(cmd);
    foo             := MainModule.N;     // foo = OK, I see data of "N"

  finally

  end;
end;


exports
  demo;

var
  taps : Variant;
begin
  CreatePyEngine;
  cmd := TStringList.Create;
  demo;
end.

So, when running the code, my variable "foo" is readable:
grafik

Now I copy that same code and compile it as DLL:

library ProjectDll;


uses
  System.SysUtils,
  System.Classes,
  System.Zip,
  System.Variants,
  System.Diagnostics,
  WinApi.Windows,
  IOUtils,
  PythonEngine,
  VarPyth;

{$R *.res}


const
  coPythonFolder = 'python-3.8.3-embed-win32';

type
  TArrayOfDouble = TArray<double>;


var
  PythonEngine : TPythonEngine;
  cmd          : TStringList;

procedure CreatePythonEnvironment;
begin
end;

procedure CreatePyEngine;
begin
  PythonEngine := TPythonEngine.Create(nil);
  PythonEngine.Name := 'PythonEngine';

  with PythonEngine do
  begin
    APIVersion          := 1013;
    AutoLoad            := False;
    AutoUnload          := true;
    AutoFinalize        := true;
    UseLastKnownVersion := false;
    DllName := 'python38.dll';
    DllPath := GetCurrentDir + '\' + coPythonFolder;

    PyFlags := [];
  end;

  PythonEngine.LoadDll;
end;

procedure DestroyEngine;
begin
  PythonEngine.Free;
end;

procedure demo;  stdcall;
var
  foo   : Variant;
var
  taps,
  freq,
  gain : TArrayOfDouble;
begin
  freq := [0, 0.5, 1];
  gain := [0,   1, 0];

  try
    cmd.Clear;
    cmd.Add('N = [0,1,2,3,4,5,6,7,8,9,10]');

    PythonEngine.ExecStrings(cmd);
    foo             := MainModule.N;          // foo = is NOT OK - I can not see data of "N"

  finally

  end;
end;


exports
  demo;

var
  taps : Variant;
begin
  CreatePyEngine;
  cmd := TStringList.Create;
end.

To demonstrate how I call the DLL, here is my "DLL caller":

unit UnitDllCaller;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    dll_demo : procedure;  stdcall;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  FDLLHandle : THandle;
implementation

{$R *.dfm}

procedure loadDLLFunction(var APointer : Pointer; AFnName : String; const ARequired : boolean = true);
var
  fnName : PAnsiChar;
begin
  fnName := PAnsiChar(AnsiString(AFnName));

  APointer := GetProcAddress(FDLLHandle, fnName);
end;


procedure TForm1.Button1Click(Sender: TObject);
begin

  FDLLHandle := LoadLibrary(PWchar('ProjectDll.dll'));

  if(FDLLHandle > 0) then
  begin
    loadDLLFunction(@dll_demo , 'demo');
    dll_demo();
  end;
end;

end.

So running DLL caller, is working, but my "foo" variable causes an exception:
grafik

Here is also the Delphi project to reproduce this:
demo.zip

Anyone got an idea?
The python code was always executed without errors.
I tried to debug a little bit more:

    cmd.Clear;
    cmd.Add('N = [0,1,2,3,4,5,6,7,8,9,10]');
    cmd.Add('f = open("demofile2.txt", "w")');
    cmd.Add('f.write(str(N))');
    cmd.Add('f.close()');

The written demofile2.txt looks as expected, so it seems that reading the variable back causes an error?!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions