Search code examples
delphidllfastmm

Why does the is operator fail to return what I expect when passed an instance from a different module?


I work on Delphi project who interac with many other small libraries. I use FastMM4 and I would like work with complex classes passed on dll parameter.

So for exemple I send my form to my dll. Into the dll I test the type of parameter with the operator "IS".

But into the Dll the operator "IS" return always "false"

Exemple

library Dll;

uses
     FastMM4,
     System.SysUtils,
     System.Classes,
     Vcl.Dialogs,
     Vcl.Forms;

{$R *.res}

procedure Complex(L : TObject);stdcall;
begin
     if L is TForm then
        showmessage('Ok')
     else
        showmessage('Pas ok') ;

     if L is TCustomFrame then
         showmessage('Ok')
     else
         showmessage('Pas ok')
end;

exports
  Complex;

begin
end.

And the call

procedure TffsIsOperator.Button2Click(Sender: TObject);
var
 MaDLL : THandle;
 Proc  : procedure (l : TObject);
begin
   try
      MaDLL := LoadLibrary(PChar('Dll.dll'));
      @Proc := GetProcAddress(MaDLL, 'Complex');
      Proc(self);
   finally
      FreeLibrary(MaDLL);
   end;
end;

Solution

  • Firstly, you have a calling convention mis-match. You must fix that by making the calling convention the same on both sides of the interop boundary.

    Even when you fix that, the apparent misbehaviour of the is operator is to be expected. You have two instances of the VCL in your process. One in the host and one in the DLL. They each have distinct versions of the classes defined in the VCL. So, the DLL's TForm is a different class form the TForm in the host. And that is why is evaluates false.

    The traditional way to handle this is to arrange that you only have one instance of the RTL/VCL in your process. And you achieve that through the use of runtime packages.

    If runtime packages are not a viable option for you, and you must use a DLL, then you will have to give up passing any Delphi classes across the DLL boundary. I fully expect this to be unwelcome news, but that is just how it is. You cannot pass TObject instances across a DLL boundary and attempt to call methods, query type identity, etc. That is simply not supported for DLLs. Only for runtime packages.

    So, if you have to use DLLs then you need to stick to simple types. Integers, floating point values, character types, arrays (but not dynamic arrays), records, pointers to such types, interfaces. As a simple rule of thumb, if you cannot find an example of your proposed interop in Win32, then it is probably invalid.