Even though it is not officially supported by Embarcadero there are many examples showing that you can include a FMX form in a VCL application e.g. MonkeyMixer and this SO question.
However, when I create a test application with only one empty VCL form and one empty FMX form, I get two problems:
There are two application icons in the task bar (apparently one for
each instance of TApplication i.e. VCL and FMX)
It crashes when I close the application (when it calls TStyleManager.UnInitialize in FMX.Forms.FinalizeForms).
How can I make this work?
I need this combination as we want our application to be native on Windows, Mac OS and iOS. Therefore on Windows it is a VCL application and the other OS's are FMX using the TMS native components. We have some large custom graphical components that are made for FMX, and they must also work on Windows.
Edit:
I see only two alternative solutions, and I like none of them:
Use FMX on Windows too. I don't like the idea of styled components instead of native. Experienced users can easily tell the difference.
Maintain to sets of our custom components: VCL and FMX editions. That will require some work, and also the graphical features of FMX are much better than VCL.
I've needed to host an FMX app inside a VCL app for display and training purposes. The FMX app is really an Android target and the VCL a Windows 'demonstrator'. The FMX hosting is done using TFireMonkeyContainer hosting the FMX main form. Yes it's got slight wrinkles but it works ok and I'm sure we'll find a way to improve things.
My FMX main form is created at runtime and has visibility of only FMX.Forms. It is then passed to TFireMonkeyContainer and is destroyed by it when the VCL app closes.
Related
I'm trying to create an Android (multi-device) application with Delphi 10.2 that uses TWebBrowser. I load a URL and I want to parse its contents for fields, but I don't know how do it.
I read this excellent guide: http://www.cryer.co.uk/brian/delphi/twebbrowser/twebbrowser_oleobject.htm#OleObject.Document, but the property WebBrowser.OleObject.Document doesn't exist.
Can somebody help me, please?
The TWebBrowser for FMX is completely different from TWebBrowser for VCL. The VCL one makes use (for access to the Document, etc) of interfaces provided by Internet Explorer, or rather the DLLs on which it is based. IE only runs on Windows, so you shouldn't be surprised to learn that the interfaces it provides are not available on FMX.
The FMX TWebBrowser is a completely different and far more limited beast. It is not automatable in the same way TWebBrowser for VCL/Windows is, and some would say that is a good thing.
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.
As David says this is caused because each VCL instance install a hook to detect when a popup menu (#32768) is created. So there is two hook instances working at the same time.
As workaround you can disable the popupmenu style hook in the dll (or in the app) using the UnRegisterSysStyleHook function defined in the Vcl.SysStyles unit.
TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
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.
As David says this is caused because each VCL instance install a hook to detect when a popup menu (#32768) is created. So there is two hook instances working at the same time.
As workaround you can disable the popupmenu style hook in the dll (or in the app) using the UnRegisterSysStyleHook function defined in the Vcl.SysStyles unit.
TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
Ok, so I downloaded a .zip file of all different kinds of examples from embarcadero... the way the buttons look and among other things are completely different from when I just create an application within my Delphi 7. I believe these examples were made for or made at a new time... because the button look way different from the way the button when I put them on my application. the buttons from the example look very modern and sleek and have mouse over effects (This applies for all the examples..its not a custom component ) I was wondering I can get this effect in my own applications within Delphi 7.. I can do this by opening one of the examples and just erasing all the code... but that's not what im trying to do..im wondering how I can accomplish these styles.. how come the examples have these nice looking buttons and such..but when I make an app within D7 its much older looking and such..
I apologize if my question is hard to understand.. and I appreciate any help on this.
Thank you in advance.. I appreciate it.
If I understand your question correctly, you're asking about the native control appearance changes that were added by the addition of Windows Themes in Windows XP.
Delphi 7 supported themes by use of the XPManifest component, which does nothing but add a manifest to your application which tells Windows your app is theme-aware and therefore it should load a more recent version of the common controls library. You can find the XPManifest component in the VCL component palette on the Win32 tab, or simply add the XPMan.pas unit to your uses clause. Note that the themed drawing does not work for all controls (grids, for instance, are not drawn using themes, and IIRC neither is TSpeedButton - it's been a long time since I used D7, so I'm not sure exactly what is and isn't supported, but the support is limited).
Starting with Delphi 2007, there is built-in support for Windows Themes, which is available by default in new projects. It can also be enabled in older projects using a checkbox in the Project->Options->Application dialog.
(Of course the real answer is that if you want your app to have the features included in modern versions of Windows, you should upgrade from your Windows-95 era version of Delphi to one that is more recent.)
I currently have an SDI application that is build with Delphi 7, I want the final user to choose the type of interface between SDI and MDI at runtime. my question is how can I change the behavior of the application between SDI and MDI at runtime?
Currently I know a couple of applications build with delphi that allow this: EMS SQL Manager and TOAD.
thanks in advance.
Download the Jedi JVCL and install it and look at the Demos for JvDocking "docking in code". They do this exactly.
They mean that you do not actually use the FormStyle=fsMDIChild unless you want lots of problems. MDI is "emulated" when you need it by docking in code.
Do not convert windows into frames. This is a bad solution.
For an MDI-like environment, that does not have the MDI problems, use a docking solution (components either commercial or open source that support docking). I use JvDocking which is included in the JEDI JVCL, which is free and open source.
You use your forms in both "docked" and "undocked" (floating) modes, and this gives you a docked IDE look and feel (VIsual Studio and RAD Studio), and an undocked IDE Look and feel (RAD Studio in undocked, or classic delphi 7).
I would convert my current windows into frames and put these frames with align=alClient into either mdi child windows or normal windows as configured.
But beware: I have never actually done this, so there might be problems that I don't know about.
At runtime set TForm.FormStyle either to fsNormal or fsMDIChild depending on if you want SDI or MDI.
Like #WarrenP's solution, I strongly recommend a docking-based solution. It should be said that you don't need to use Jedi VCL to achieve this. As an example, here's a very simple (all-native-vcl) component I've produced which allows you to simply drop on as many instances to your form(s) and set their alignment to enable docking (and tabbed docking) in those regions.
MDI itself is an accident waiting for a place to happen. There are solutions available to achieve the "MDI look and feel" without using MDI itself, though I've yet to encounter one I'd consider "neat" (probably for a lack of looking).
Ultimately you should probably question the wisdom in providing MDI as an option. Docking (with or without the ability to undock, and especially when Tabbed Docking is a user-determined choice) feels more modern, and (done properly) can be far more flexible and intuitive than MDI ever was.
Just my 2-pence worth.