Reputation: 9
Decided to migrate from Delphi 2007 to Delphi 11 Alexandria. I had DLLs made with component creation from them. In the program, I dynamically load the DLL, a component is created in the DLL. Code that worked without issue on Delphi 2007 does not work on Delphi 11 Alexandria. Errors are constantly different, if I solve one error, another error appears. I can't find a solution. Please tell me how to create a component from a DLL.
My old code:
DLL:
library PascalHighlighter;
uses
Forms,
SynEditHighlighter, SynHighlighterPas, SynMemo;
{$R *.res}
var Component:TSynPasSyn;
type TSynPasSynClass = class of TSynPasSyn;
procedure PascalHighlighter_Create(Form:TForm; ComponentNum:Word);
begin
if Component=nil then begin
Component := TSynPasSynClass.Create(Form);
Component.Name:='SynPasSyn1';
end;
TSynmemo(Form.Components[ComponentNum]).Highlighter:=Component;
Component.CommentAttri.Foreground:=$00007F00;
Component.KeyAttri.Foreground:=$00A40000;
Component.StringAttri.Foreground:=$00FE0000;
end;
exports PascalHighlighter_Create;
begin
end.
Load DLL:
type
TDLLComponent = function(Form:TForm; ComponentNum: Word): Word;
var
PascalHighlighter_Create: TDLLComponent;
dll_PascalHighlighter: Thandle;
procedure TForm1.ButtinClick(Sender: TObject);
begin
if Fileexists(dirplugins+'PascalHighlighter.dll') then begin
dll_PascalHighlighter:= LoadLibrary(PChar(dirplugins+'PascalHighlighter.dll'));
@PascalHighlighter_Create:= GetProcAddress(dll_PascalHighlighter, 'PascalHighlighter_Create');
end;
if Assigned(PascalHighlighter_Create) then begin
PascalHighlighter_Create(Form1,(Form1.Findcomponent('Synmemo1') as TSynmemo).ComponentIndex);
end;
end;
I tried to create an ordinary Memo from a DLL. Another error, but it doesn't work either.
I need to understand how to create a SynPasSyn1 component from a DLL and connect it to SynMemo. Or at least using the example of any other component, I can figure it out myself further.
Here is an example of creating a Memo. Why does it give an error " cannot assign a TFont to a TFont" and how to solve it?
library Mymemo;
uses
Vcl.Forms, Vcl.StdCtrls;
{$R *.res}
var Component:TMemo;
procedure Mymemo_Create(Form:TForm); stdcall;
begin
Component := TMemo.Create(Form);
Component.Name:='Memo1';
with Component do begin
Left := 100;
Top := 100;
Width := 400;
Height := 300;
Visible := True;
Parent := Form; //Any container: form, panel, ...
end;
end;
exports Mymemo_Create;
begin
end.
unit Unit1;
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;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
type
TDLLComponent = procedure(Form:TForm{; ComponentNum: Word}); stdcall;//: Word;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
Mymemo_Create :TDLLComponent;
dll_Mymemo :THandle;
dirplugins :String;
begin
dirplugins:='E:\_Downloads\vk\Mymemo\';
if Fileexists(dirplugins+'Mymemo.dll') then begin
dll_Mymemo:= LoadLibrary(PChar(dirplugins+'Mymemo.dll'));
if dll_Mymemo <> 0 Then begin
edit1.Text:='load';
end;
//@
Mymemo_Create:= GetProcAddress(dll_Mymemo, 'Mymemo_Create');
if Assigned(Mymemo_Create) = True then begin
edit1.Text:='load & create';
Mymemo_Create(Form1);
end;
end;
end;
end.
How to create a component from a DLL?
Upvotes: 0
Views: 625
Reputation: 9
I found a solution with DLL connection.Unit FastMM5. In the DPR file, in the Uses add "FastMM5", necessarily in the first place. It is added to the DLL and to the program where the library will be called from. Seems, no crashes, no hanging processes.
Upvotes: 0
Reputation: 597941
The error message "cannot assign TFont to a TFont" means that you have an RTTI mismatch, because the TFont
class (and other classes) compiled inside the DLL is/are different than the TFont
class (and others) compiled inside the host app. As such, when the VCL internally tries to Assign()
a TFont
object from the DLL to a TFont
object in the host app (or vice versa), it can't verify they are instances of the same class type, and so it fails with the error above.
When using components across the DLL boundary, the host app and the DLL MUST be compiled with the same Delphi version, and MUST both be compiled with Runtime Packages enabled, so they can share a single instance of the RTL/VCL frameworks and all of their respective RTTI in memory.
Otherwise, you SHOULD NOT be doing this kind of work with a plain DLL to begin with. You SHOULD be doing it with a BPL Package instead (and thus replace LoadLibrary()
with LoadPackage()
). A BPL Package is a special kind of DLL with built-in support for the RTL/VCL frameworks. It is designed to solve these kinds of problems for you, whereas you have to manage everything manually in a plain DLL.
Read Delphi's documentation for more details: Working with Packages and Components Index
The fact that your approach "worked" at all in Delphi 2007 was pure luck. What I described is how Delphi has always operated in all versions.
On a side note:
In your "old" code, your TDLLComponent
type is declared wrong. It should be:
type
//TDLLComponent = function(Form:TForm; ComponentNum: Word): Word;
TDLLComponent = procedure(Form:TForm; ComponentNum: Word);
Upvotes: 0