renan-guimaraes / dwscript

Automatically exported from code.google.com/p/dwscript
0 stars 0 forks source link

Assert(sym.InheritsFrom(TDataSymbol)) fails when creating custom procedures in runtime in DLL #345

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Create a DLL and make the procedure. Add some parameter and result. Supply a 
function to OnEval
2. Compile a script and run it.
3. The assert will fail in runtime.

Asserts will fail at ParamAs*** and ResultAs***

If I comment the asserts, everything runs fine. No errors.
I'm using latest build on Win7x64 SP1.

Some code hinting.

var 
  du:TdwsUnit = nil;

//--------------------------------------
TDLLEval = class
    FEval:TOnEval;
    procedure OnEval(info : TProgramInfo);
    constructor Create(eval:TOnEval);
  end;

constructor TDLLEval.Create(eval: TOnEval);
begin
  FEval := eval;
end;

procedure TDLLEval.OnEval(info: TProgramInfo);
begin
  FEval(info);
end;

//---------------------
procedure RegisterUnit(dwUnit:PVOID); stdcall;
begin
  du := TdwsUnit(dwUnit);
  Assert(Assigned(du));

  RegisterScriptFunctions;
end;

/------------------
procedure onGetPixel(info : TProgramInfo);
var
  p1,p2:integer;
  c:integer;
begin
  p1 := info.ParamAsInteger[0]; //Assert will fail here
  p2 := info.ParamAsInteger[1]; //Assert will fail here
  c := GetPixel(ImagePtr, p1, p2, Width);;
  info.ResultAsInteger := c; //Assert will fail here
end;
/-----------
procedure RegisterScriptFunctions; stdcall;
var
  f:TdwsFunction;
  p:TdwsParameter;
  cls:TDLLEval;
begin
  Log('Adding functions', LOG_DEBUG);

  cls := TDLLEval.Create(onGetPixel);
  f := du.Functions.Add;
  f.Name := 'GetPixelA';

  p := f.Parameters.Add;
  p.Name := 'x';
  p.DataType := DTS_INTEGER;
  p := f.Parameters.Add;
  p.Name := 'y';
  p.DataType := DTS_INTEGER;

  f.ResultType := DTS_INTEGER;
  f.OnEval := cls.OnEval;

  Log('Added GetPixel', LOG_DEBUG);
end;
/---------------

Original issue reported on code.google.com by oleg.top...@gmail.com on 25 Feb 2013 at 8:33

GoogleCodeExporter commented 9 years ago
An explanation would be if the class in your DLL were duplicated (and thus 
different) from the ones in your main EXE.
Using a BPL isntead of a DLL might solve that.

The following line seem to be an indication of that:

   procedure RegisterUnit(dwUnit:PVOID); stdcall;
   begin
     du := TdwsUnit(dwUnit);

Original comment by zar...@gmail.com on 25 Feb 2013 at 1:52

GoogleCodeExporter commented 9 years ago
This is simple translation of instance to dll module.
dll should provide plugin functionality and therefor I need to pass dwsUnit 
there somehow.

There is no duplicates there.

Original comment by oleg.top...@gmail.com on 25 Feb 2013 at 3:30

GoogleCodeExporter commented 9 years ago
InheritsFrom does a pointer check.

If the TDataSymbol is compiled once in the main executable, and once in the 
DLL, there will be two distinct TDataSymbol classes, with distinct hierarchies.

To check that you could log IntToStr(Int64(TDataSymbol)) in the main exe and in 
the dll (f.i. just before the assert). If there is no duplication, the two 
numbers will be identical.

Original comment by zar...@gmail.com on 25 Feb 2013 at 3:40

GoogleCodeExporter commented 9 years ago
So, I cannot use dwScript to dynamically provide functions in outside DLL?

I have a form with dwsUnit, and it can be created multiply times. It is then 
supplied to dll as a reference.
I can't understand how it can be complied twice.

Original comment by oleg.top...@gmail.com on 25 Feb 2013 at 3:47

GoogleCodeExporter commented 9 years ago
For that you have to use BPLs (which are a special form of DLLs where the 
compiler takes care of not duplicating classes), the issue manifests itself 
there, but it's bound to manifest itself in all code that relies on a checked 
is/as/inheritsfrom, as well as in other situations.

A blind cast will get through and work only if you have binary compatibility 
between the exe and the dll (ie. if they were compiled at the same time from 
the same source), but if you require binary compatibility, you might as well 
not have a dll.

As for it getting compiled twice, when you compile the EXE, it gets a full copy 
of the DWScript source (and VCL, and RTL, etc.). When you compile a DLL (rather 
than a BPL) the compiler compiles another full copy of the DWSCript source (and 
RTL, and whatever your DLL uses), since it can't assume that DLL will be used 
by your main EXE, or even a Delphi application (the DLL could be used by a C 
app f.i.)

Original comment by zar...@gmail.com on 25 Feb 2013 at 3:57