DLL中的VCL样式正在影响应用程序中的TMenuItem [英] VCL Style from DLL is affecting TMenuItem in Application

查看:328
本文介绍了DLL中的VCL样式正在影响应用程序中的TMenuItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是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组成。运行它,然后点击弹出窗口,然后尝试从弹出窗口中选择一些。它会崩溃并停止在一些StdWindowProc或类似的东西。另外如果你去窗口系统菜单(左上角),当你尝试从菜单中选择一些东西,你会注意到,系统菜单被设计为DLL gui和崩溃。链接到rar文件: dropbox.com/sh/f2jmbsmw18akpyg/AAA6SWdBmVhf6n6K-mvYLLmua ?dl = 0





感谢您的帮助。

解决方案

这是VCL风格和风格菜单的一个基本问题。造型采用过程宽钩来实现。具体来说,通过调用 VCL中的 SetWindowsHookEx TCustomStyleEngine.CreateSysHook 中安装的CBT钩子。主题单位。事实上,这个钩子只适用于GUI线程,但是在这个过程中正好有一个GUI线程的意义上,这个过程很广泛。



由于你有多个应用程序中的VCL实例(一个在DLL中,一个在应用程序中),安装了两个钩子。那是太多了最近安装的钩子(DLL发生)赢了,这就是为什么DLL菜单样式感染你的可执行文件。为什么你遇到访问冲突。 DLL正试图在属于可执行文件的菜单上进行操作。所以尽管做了最大的努力,但是你最终还是从主机可执行程序中访问VCL对象的DLL代码。



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



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



也许另一种方法要从DLL中卸载钩子。只要你的DLL没有显示菜单,那么你可以卸载挂钩。它将禁用DLL显示的菜单的样式,但也许这是可以接受的。



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

 库VCLStyleDLL; 

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

使用
VCL.Styles,
VCL.Themes,
VCL.SysStyles; //访问TSysPopupStyleHook

{$ R * .res}

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

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


I am using Delphi XE6 and VCL styles. I have main application and dlls. My main application has enabled runtime themes and I am using vcl style files. I did quite similar thing to my DLLs. I enabled runtime themes and added VCL.Themes, VCL.Styles under uses and resource file with VCL style file within it. When DLL is loaded I load VCL style from resources and set it for DLL gui. Main app and DLL are not built with runtime packages.

Now I have main app GUI styled with own style and DLL gui styled with own style too. This seems to work fine until...

When I click on button in my main app which event opens TPopupMenu it's styled with same style as DLL GUI instead of main app style. If I navigate through menu I get AV too and program crashes. Take a look at the attached image.

What am I doing wrong? The only workaround I currently see would be to make my own customized TPopupMenu derived from some other control.


As I promised I prepared simple demo program which is similar to my application. It consists of host application with own style and DLL with style added to resource. Run it and click on button Popup then try select something from popup. It will crash and stop in some StdWindowProc or something like that. Also if you go to window system menu (left top corner) when you try to select something from that menu you will notice that system menu is styled as DLL gui and crashes too. Link to rar file: dropbox.com/sh/f2jmbsmw18akpyg/AAA6SWdBmVhf6n6K-mvYLLmua?dl=0

Thanks for your help.

解决方案

This is a fundamental problem with VCL styles and the way that they style menus. The styling is implemented with a process wide hook. Specifically a CBT hook installed by a call to SetWindowsHookEx from TCustomStyleEngine.CreateSysHook in the Vcl.Themes unit. In fact, the hook applies just to the GUI thread, but that is process wide in the sense that there is exactly one GUI thread in the process.

Since you have multiple instances of the VCL in your application (one in the DLL and one in the application), two hooks are installed. That is one too many. The hook installed most recently (the DLL as it happens) wins, and that's why the DLL menu styling infects your executable. And why you encounter an access violation. The DLL is trying to operate on a menu that belongs to the executable. And so, in spite of your best efforts, you've ended up with the DLL code accessing VCL objects from the host executable.

There's no simple way to work around this and support styles fully in both modules. What we have here is a fundamental consequence of the design. The system was not designed to support multiple VCL instances. If you wish to use VCL styles in multiple modules, then the designers expect you to use runtime packages.

I suppose that you might be able to get some traction by operating the DLL out of a completely different thread. That would involve loading the DLL from that different thread so that the VCL is initialized in the thread. And all calls to the DLL would have to be from that thread. And you'd need to run a message loop in that thread. It's possible that you might be able to make that work, but I doubt it. Even with all the provisos mentioned you still have to handle the fact that you have two GUI threads which presents all sorts of issues with the input queue handling.

Perhaps another approach would be to uninstall the hook from the DLL. So long as your DLL is not showing menus then you may well be able to get away with uninstalling that hook. It would disable styling for menus shown by the DLL, but perhaps that's acceptable.

This version of your DLL (after I simplified it somewhat also) uninstalls the hook.

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.

With this version of the DLL, the host executable does not suffer the problems your describe in your question.

这篇关于DLL中的VCL样式正在影响应用程序中的TMenuItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆