7

我正在使用 Delphi XE6 和 VCL 样式。我有主要的应用程序和 dll。我的主应用程序启用了运行时主题,我正在使用 vcl 样式文件。我对我的 DLL 做了非常相似的事情。我启用了运行时主题并在使用和资源文件下添加了 VCL.Themes、VCL.Styles,其中包含 VCL 样式文件。加载 DLL 时,我从资源中加载 VCL 样式并将其设置为 DLL gui。主应用程序和 DLL 不是使用运行时包构建的。

现在我有自己风格的主应用程序 GUI 和自己风格的 DLL gui。这似乎工作正常,直到......

当我单击主应用程序中的按钮时,哪个事件会打开 TPopupMenu,它的样式与 DLL GUI 相同,而不是主应用程序样式。如果我浏览菜单,我也会得到 AV 并且程序崩溃。看一下附加的图像。

我究竟做错了什么?我目前看到的唯一解决方法是制作我自己的自定义 TPopupMenu 从其他一些控件派生。在此处输入图像描述


正如我所承诺的,我准备了与我的应用程序类似的简单演示程序。它由具有自己样式的宿主应用程序和添加到资源的样式的 DLL 组成。运行它并单击按钮 Popup 然后尝试从弹出窗口中选择一些东西。它会在某些 StdWindowProc 或类似的东西中崩溃并停止。此外,如果您在尝试从该菜单中选择某些内容时转到窗口系统菜单(左上角),您会注意到系统菜单的样式为 DLL gui 并且也会崩溃。rar 文件链接:dropbox.com/sh/f2jmbsmw18akpyg/AAA6SWdBmVhf6n6K-mvYLLmua?dl=0

在此处输入图像描述

谢谢你的帮助。

4

2 回答 2

10

这是 VCL 样式及其样式菜单的方式的一个基本问题。样式是通过进程范围的钩子实现的。特别是在单元中通过调用SetWindowsHookExfrom安装的 CBT 挂钩。实际上,该钩子仅适用于 GUI 线程,但从进程中只有一个 GUI 线程的意义上说,这是进程范围的。TCustomStyleEngine.CreateSysHookVcl.Themes

由于您的应用程序中有多个 VCL 实例(一个在 DLL 中,一个在应用程序中),因此安装了两个挂钩。那太多了。最近安装的钩子(DLL)获胜,这就是为什么 DLL 菜单样式会感染您的可执行文件。以及您遇到访问冲突的原因。DLL 正在尝试对属于可执行文件的菜单进行操作。因此,尽管您尽了最大努力,最终还是得到了 DLL 代码从主机可执行文件访问 VCL 对象。

没有简单的方法可以解决这个问题并在两个模块中完全支持样式。我们在这里拥有的是设计的基本结果。该系统不是为支持多个 VCL 实例而设计的。如果您希望在多个模块中使用 VCL 样式,那么设计人员希望您使用运行时包。

我想您可以通过在完全不同的线程中操作 DLL 来获得一些牵引力。这将涉及从那个不同的线程加载 DLL,以便在线程中初始化 VCL。对 DLL 的所有调用都必须来自该线程。而且您需要在该线程中运行消息循环。你有可能做到这一点,但我对此表示怀疑。即使提到了所有附带条件,您仍然必须处理这样一个事实,即您有两个 GUI 线程,这会带来输入队列处理的各种问题。

也许另一种方法是从 DLL 中卸载钩子。只要您的 DLL 不显示菜单,那么您很可能可以通过卸载该钩子而侥幸逃脱。它会禁用 DLL 显示的菜单的样式,但也许这是可以接受的。

这个版本的 DLL(在我稍微简化之后)卸载了钩子。

library VCLStyleDLL;

{$R 'Style.res' 'Style.rc'}

uses
  VCL.Styles,
  VCL.Themes,
  VCL.SysStyles; // to gain access to TSysPopupStyleHook

{$R *.res}

begin
  TStyleManager.TrySetStyle('Glossy', false);
  TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
end.

使用此版本的 DLL,主机可执行文件不会遇到您在问题中描述的问题。

于 2014-09-19T15:11:55.803 回答
9

正如大卫所说,这是因为每个 VCL 实例都安装了一个钩子来检测何时创建弹出菜单(#32768)。所以有两个钩子实例同时工作。

作为解决方法,您可以使用 Vcl.SysStyles 单元中定义的 UnRegisterSysStyleHook 函数禁用 dll(或应用程序)中的 popupmenu 样式挂钩。

TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
于 2014-09-19T15:32:52.583 回答