delphi 从DLL、运行时创建组件

wd2eg0qa  于 2023-04-20  发布在  其他
关注(0)|答案(2)|浏览(178)

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?

hfyxw5xn

hfyxw5xn1#

错误消息“cannot assign TFont to a TFont”表示存在RTTI不匹配,因为TFont类DLL内部编译的类(和其他类)与TFont类不同(和其他)在主机应用程序内编译。因此,当VCL在内部尝试将Assign()对象从DLL转换为主机应用程序中的TFont对象时(反之亦然),它无法验证它们是否是相同类类型的示例,因此它会失败,并出现上面的错误。
当使用跨DLL边界的组件时,宿主应用程序和DLL * 必须 * 使用相同的 Delphi 版本编译,并且 * 必须 * 都启用Runtime Packages编译,因此它们可以共享RTL/VCL框架的 * 单个示例 * 以及内存中各自的所有RTTI。
否则,你不应该用一个普通的DLL来做这类工作,你应该用一个BPL Package来做(因此将LoadLibrary()替换为LoadPackage())。BPL包是一种特殊类型的DLL,内置了对RTL/VCL框架的支持。它旨在为您解决这类问题,而您必须在普通DLL中手动管理所有内容。
阅读 Delphi 的文档了解更多细节:Working with Packages and Components Index
事实上,你的方法在 Delphi 2007中“工作”了 * 纯粹是运气 *。我所描述的是Delphi在所有版本中的操作方式。
顺便说一句:
在您的“旧”代码中,您的TDLLComponent类型被声明为错误。它应该是:

type
  //TDLLComponent = function(Form:TForm; ComponentNum: Word): Word;
  TDLLComponent = procedure(Form:TForm; ComponentNum: Word);
a14dhokn

a14dhokn2#

@RemyLebeau加载后,在Synmemo上高亮显示BPL代码。如果我只是开始在Synmemo中编写一些东西,那么一切都很好。但是如果我直接从 Delphi 插入这些代码到Synmemo中,那么立刻就会出现很多“访问冲突”错误。这不是关于组件的,因为如果我创建一个新项目,将Synmemo和SynPasSyn放在表单上,那么一切都很好。我想错了什么,我得到了一个“访问冲突”错误?
BPL:

package Package1;

{$R *.res}
{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO OFF}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS ON}
{$RANGECHECKS ON}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES ON}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$DEFINE DEBUG}
{$ENDIF IMPLICITBUILDING}
{$IMPLICITBUILD ON}

requires
  rtl,
  vcl,
  SynEdit_R;

contains
  Unit1 in 'Unit1.pas';

end.

Unit1.pas:

unit Unit1;

interface

uses
  SynEditHighlighter, SynHighlighterPas, SynEditCodeFolding;

implementation

{$R *.res}

var Component:TSynPasSyn;

type
 TSynPasSynClass = class of TSynPasSyn;

function PascalHighlighter_Create: TSynCustomHighlighter;// stdcall;
begin
if Component=nil then begin
 Component := TSynPasSynClass.Create(nil);
 Component.Name:='SynPasSyn1';
end;
if Component <> nil then begin
 //TSynmemo(Form.Components[ComponentNum]).Highlighter:=Component;
 //Component.CommentAttri.Foreground:=$00007F00;
 //Component.KeyAttri.Foreground:=$00A40000;
 //Component.StringAttri.Foreground:=$00FE0000;
 Result:=Component;
end;

end;

exports PascalHighlighter_Create;

begin
end.

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, SynEdit, SynMemo, SynEditHighlighter;

type
  TForm1 = class(TForm)
    Button1: TButton;
    SynMemo1: TSynMemo;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
type
 TPascalHighlighter_Create = function :TSynCustomHighlighter;// stdcall;
var
 PackageModule: HModule;
 PascalHighlighter_Create: TPascalHighlighter_Create;
begin
 PackageModule := LoadPackage('C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\Package1.bpl');
 if PackageModule <> 0 then
 begin
  edit1.Text:='load'; //performed
 @PascalHighlighter_Create := GetProcAddress( PackageModule, 'PascalHighlighter_Create' );
 if @PascalHighlighter_Create <> nil then
 edit1.Text:='load 2'; //performed
synmemo1.Highlighter:=PascalHighlighter_Create;

end;

end.

相关问题