1
votes

I am trying to create a TButton object in DLL to show it up in EXE Main Form.Here is My Code:

DLL:

library dlltest1;

{$mode objfpc}{$H+}

uses
  Classes,sysutils,Forms,Interfaces,StdCtrls,Windows,Dialogs
  { you can add units after this };
function test(hand:TForm):HWND;

var
  a:TButton;
begin
  a:=TButton.Create(hand);
  a.Show;
  a.Caption:='a';
  result:=a.Handle;
end;

exports test;
begin
end.  

EXE:

  procedure test(hand:HWND);  external 'dlltest1.dll';
type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    TIPropertyGrid1: TTIPropertyGrid;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }
  type TComp=function(Hand:HWND):HWND;
var
  comps:array of TComp;

procedure TForm1.FormCreate(Sender: TObject);
begin
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  a:HWND;
begin
SetLength(comps,1);
a:=LoadLibrary('dlltest1.dll');
comps[0]:=TComp(GetProcAddress(a,'test'));
(FindControl(comps[0](Form1.Handle)) as TButton).Caption:='A'; 
end;

It creates button succesfuly with command comps[0](Form1.Handle) but when i try to execute this (FindControl(comps[0](Form1.Handle)) as TButton).Caption:='A'; ,it says INVALID TYPE CAST.I checked the class name in main exe.ClassName was TButton.I am compiling both projects under Lazarus IDE for Windows x86_64.I also tried to use RTTI TPropertyEditor Grid.When i assign it like:TIPropertyEditor1.TIObject:=FindControl(comps[0](Form1.Handle)) TIPropertyEditor1 acts like it as TButton as normal.But I can't figure out why 'as TButton ' causes Invalid Type Cast.Is there any solution for my problem?

2
Type identity doesn't work as you'd expect across modules. Use packages which are designed for this purpose. Assuming Lazarus has package support. - David Heffernan
Lazarus has package support,If you have any suggestions to tell me about ,I would be very happy - HolyLilly
Surely there is documentation - David Heffernan
TIObject can sense it is TButton and it can handle it without exception.So that means Type identity works across modules.But i am looking for answer about why (as TButton) causes "Invalid Type Cast" exception and how to solve it. - HolyLilly
I also tried to run this code under Delphi 10.2 Tokyo,It is doing nothing.Not creating any Buttons on Form. - HolyLilly

2 Answers

-1
votes

It is right decision to send reference to Form instance to button creation call, as only forn is die it will call destructor of all child component.

You should return from test functon not Handle but TButton instannce, difference between HWND and TButton. Delphi wrap OS GUI APIs inside TButton, TForm, any TWinControl instances. On low level OS use HWND as references to OS low level objects.

You should not worry about memory leaks cause of you send Form instance to TButton.Create constructor.

function test(Owner: TForm): TButton;
begin
  Result := TButton.Create(Owner);
  Result.Show;
  Result.Caption:='a';
end;
3
votes

Packages (as in BPL packages) are worked on in trunk, but not yet operational. Designtime components are compiled into the IDE binary (which also has advantages like Lazarus' much faster start)

Without those using the normal .so/dlls, besides the identity problem, both the DLL and the main program have full copies of the RTL and its state, which includes the memory manager, VMTs, RTTI, localization etc etc. Using managed types or any scenario where one module allocates and the other deallocates is dangerous in such case. The AS case uses classtype information which is also duplicate per module.

See also http://wiki.freepascal.org/packages for a short treatise.

P.s. David is mostly right and the state for Lazarus is roughly the same as for Delphi, except that there are no working packages yet, nor a shared memory manager concept to work around that.