我已经开发了一个DLL有一个表单。我用下面的代码设置了一个样式。
library TestLib;
uses Vcl.Themes, Vcl.Styles,....
.
.
exports
function1,
function2;
begin
TStyleManager.TrySetStyle('Style1');
end.
当我加载这个dll并调用function 1打开这个窗体时。窗体打开并应用了样式。
现在,当我最小化该窗口时,我得到了一个访问冲突。包括最大化和恢复在内的一切都工作正常。所有的功能都工作得很好。
我猜它不是在处理这个表单的Minimize事件生成的消息。请咨询。
**注意:**当我删除样式时,一切正常。
Call Stack
:0976742b TWinControl.HandleNeeded + $3
:0978ad8a TStyleManager.HandleMessage + $56
:09762a3c TWinControl.DoHandleStyleMessage + $14
:0972e6be TCustomForm.WndProc + $612
:09763c2b TWinControl.MainWndProc + $2F
更新:SSCCE
Project1.EXE(有一个格式Unit1.pas/dfm)
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;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
function InitDLL: Boolean;
end;
var
Form1: TForm1;
implementation
const
cLIBRARY = 'Project2.dll';
var
DLLHandle : THandle;
showfrm: procedure;
procedure TForm1.Button1Click(Sender: TObject);
begin
if InitDLL then
showfrm;
end;
function TForm1.InitDLL: Boolean;
begin
if DLLHandle = 0 then
begin
DLLHandle := LoadLibrary(PChar(cLIBRARY));
if DLLHandle <> 0 then
begin
@showfrm := GetProcAddress(DLLHandle, 'showfrm');
end
else
begin
Result := False;
raise Exception.Create('Error loading DLL: ' + cLIBRARY);
end;
end;
Result := (DLLHandle > 0);
end;
{$R *.dfm}
end.
创建一个DLL Project2.dll,其具有作为任何形式的单元2和将调用该形式的单元3。将样式(例如AnyStyle 1)作为资源添加到此dll。
library Project2;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
{$R *.dres}
uses
ShareMem,
Vcl.Themes,
Vcl.Styles,
Vcl.Dialogs,
System.SysUtils,
System.Classes,
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas';
{$R *.res}
exports
showfrm;
begin
if TStyleManager.TrySetStyle('AnyStyle1') then
begin
ShowMessage('True');
end
else
ShowMessage('False');
end.
unit3.pas
unit Unit3;
interface
uses Unit2;
procedure showfrm;
implementation
procedure showfrm;
begin
with TForm2.Create(nil) do
Show;
end;
end.
现在按下Unit 2窗口的最小化按钮。您将遇到访问冲突。
4条答案
按热度按时间wr98u20j1#
访问冲突的原因是 Delphi 中的vcl样式似乎没有考虑dll中的VCL样式。AV在表单样式钩子的
WM_SIZE
处理程序中抛出:样式钩子测试消息是否在主表单上被处理,但dll中没有主表单。访问未赋值引用的句柄会导致异常。
下面的解决方法引入了一个后代样式的钩子来防止这种情况,它绕过了对主窗体的检查,并让消息的处理在
TWinControl
处继续。这是dll中完整的修改后的“unit3”:
还要注意,在考虑在dll中使用样式时,可能会继续遇到这样的问题。
mum43rcc2#
您应该在同一版本的RAD Studio中编译bouth dll和exe,并启用“运行时包”。只有在这种情况下,dll中的表单才能保证正常工作。
wko9yo5t3#
样式越来越流行,所以它可能会帮助未来的读者,特别是因为最小化AV仍然存在于Delphi RIO10.3.3中。
我发现在dll中创建一个虚拟的隐藏主表单会有所帮助。
只需将应用程序对象传递给dll并在内部执行此操作
6rvt4ljy4#
在DLL中,在调用DLL中的SetStyle之前必须关闭系统钩子,否则它将尝试访问不存在的Mainform,并且您将获得访问违规等。
我花了很长时间才发现这一点,它需要更广泛的记录,因此这篇文章。