决定从 Delphi 2007 迁移到 Delphi 11 Alexandria。我用它们创建的组件制作了 DLL。在程序中,我动态加载了DLL,在DLL中创建了一个组件。在 Delphi 2007 上正常运行的代码不适用于 Delphi 11 Alexandria。错误总是不同的,如果我解决了一个错误,就会出现另一个错误。我找不到解决办法。请告诉我如何从 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.
加载动态链接库:
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;
我试图从 DLL 创建一个普通的备忘录。另一个错误,但它也不起作用。
我需要了解如何从 DLL 创建 SynPasSyn1 组件并将其连接到 SynMemo。或者至少使用任何其他组件的示例,我可以自己进一步弄清楚。
这里是一个创建备忘录的例子。为什么会报错“cannot assign a TFont to a TFont”,如何解决?
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.
如何从 DLL 创建组件?
错误消息“cannot assign TFont to a TFont”意味着您有一个RTTI不匹配,因为在DLL中编译的
TFont
类(和其他类)与TFont
类(和其他)在主机应用程序中编译。当 VCL 在内部尝试将 DLL 中的 Assign()
TFont
对象转换为主机应用程序中的 TFont
对象(反之亦然)时,它无法验证它们是同一类类型的实例,因此它因上述错误而失败。
当跨 DLL 边界使用组件时,主机应用程序和 DLL 必须 使用相同的 Delphi 版本进行编译,并且 必须 都在启用 运行时包 的情况下进行编译,这样它们就可以共享一个 单个实例 RTL/VCL 框架及其在内存中的所有 RTTI。
否则,您不应该开始使用普通 DLL 进行此类工作。你 应该 用 BPL Package 代替(因此用
LoadLibrary()
替换 LoadPackage()
)。 BPL 包是一种特殊的 DLL,内置了对 RTL/VCL 框架的支持,可以解决这类问题。
旁注:
在您的“旧”代码中,您的
TDLLComponent
类型被声明为错误。应该是:
type
//TDLLComponent = function(Form:TForm; ComponentNum: Word): Word;
TDLLComponent = procedure(Form:TForm; ComponentNum: Word);