在DLL中可以封装窗体,需要解决的关键问题在于DLL中的Application对象和调用的Application对象是有区别的。对于一般的应用程序来说,Application 对象是 VCL 固定的,一般不需要修改Application对象指针。但是在 DLL中,使用窗体或者使用Application对象时,必须使DLL的Application和调用程序一样,这样才不至于混淆。如果不修改 Application 对象,那么应用程序退出的时候,可能会出现错误。例如使用如下代码在调用程序中导出一个函数:
function DllFunction(App:TApplication;PForm:TForm):TForm2;stdcall;
begin
Result:=TForm2.Create(PForm);
end;
当主程序退出时,就有可能发生错误。 解决该问题的步骤如下:
• 按照创建DLL的步骤新建一个DLL项目。
• 在DLL项目中新建一个需要封装的窗体,并根据需要添加窗体代码。
• 增加一个过程,过程以应用程序的句柄作为参数,并将此句柄赋值给DLL的Application对象的句柄,示例代码如下:
procedure SynAPP(App: THandle); stdcall;
begin
Application.Handle := App;//即使不调用此方法,下面的 Appliaciton 在运行是调试依然是当然 exe 的全名
end;
• 编译生成DLL文件。
• 应用程序中需要调用封装在DLL中的窗体时,首先调用SynAPP过程,然后进行其他操作。
下面举例说明这个步骤。在DLL中封装一个窗体,窗体中只有一个“随机颜色”按钮,单击该按钮则改变窗体的背景色。 首先,新建一个DLL项目工程,新建一个窗体并在该窗体上添加一个名为“随机颜色”的按钮, 其 Click 事件处理代码如下:
procedure TDllTestForm.btn1Click(Sender: TObject);
begin
Color := Random(111*111*111);//Random(0,255*255*255);
end;
然后,在窗体中增加方法SynApp和显示窗体的方法ShowDllForm。代码如下: interface {省略了其他代码}
interface
procedure SynAPP(App: THandle); stdcall;
procedure ShowDllForm; stdcall;
implementation
procedure SynAPP(App: THandle); stdcall;
begin
Application.Handle := App;
end;
procedure ShowDllForm; stdcall;
var
ADllTestForm: TDllTestForm;
begin
try
ADllTestForm := TDllTestForm.Create(Application);
try
ADllTestForm.ShowModal;
finally
ADllTestForm.Free;
end;
except
on E: Exception do
MessageDlg('Error in DllForm: ' + E.Message, mtError, [mbOK], 0);
end;
end;
在DLL项目文件中增加导出函数/过程的声明:
exports
SynAPP,
//CreateDllSkin, //创建皮肤控件窗体
//DestroyDllSkin, //销毁皮肤控件窗体
ShowDllForm,
编译之后DLL就创建完成了。 在使用DLL时,首先必须调用SynApp,并且将主程序的Application的句柄作为参数传递,否则主程序退出时会引起操作系统错误。 主程序也非常简单,就是在一个窗口中加入一个按钮,直接显示封装在DLL中的窗体。 首先声明需要导入的过程:
interface {省略了其他代码}
procedure SynAPP(App: THandle); stdcall; external 'PDll.dll';
procedure ShowDllForm; stdcall; external 'PDll.dll';
调用封装在DLL中的窗体的代码并添加在按钮的Click事件处理过程中:
procedure TForm2.btn1Click(Sender: TObject);
begin
//首先必须调用这个过程,并且使用 Application 的句柄作为参数,亲测不掉用也没发现问题,可能没测到
SynApp(Application.Handle);
ShowDllForm;
end;