What is the difference between the new TFileOpenDialog and the old TOpenDialog?
In my computer (Win 7/DXE), when I run the code, the dialogs look the same.
TOpenDialog executes TFileOpenDialog when the following conditions are met:
the program is running under Vista (and up)
UseLatestCommonDialogs is true (which is the default)
no OnIncludeItem, OnClose or OnShow events are set
So while still using TOpenDialog on your system you may likely end up automagically executing TFileOpenDialog in most cases, which explains why they are looking the same for you.
Remark: TFileOpenDialog does not fall back on older Windows systems (XP and under) - it just raises an exception. On the opposite, TOpenDialog does some sort of "fall forward".
TOpenDialog wraps the traditional GetOpenFileName. It works on all versions of Windows.
TFileOpenDialog wraps the new COM based dialog that was introduced in Vista. It therefore only works on Vista or later. It has more functionality than the older dialogs, most notably the tight integration with search.
Vista common dialog
Compatibility common dialog
The GetOpenFileName API will in fact produce the new dialogs in most situations, if called correctly, so you can't actually tell the difference. That said, historically the VCL's wrapper for GetOpenFileName was implemented imprecisely and always resulted in the compatibility dialog being shown.
But what does the new COM dialog have to offer then?
The new dialog offers a much easier customisation interface at the loss of some generality. If you use the old dialog template based customisation with GetOpenFileName on Vista or later then the dialogs degrade to ugly compatibility versions that lack functionality.
The other big advantage of the new dialogs is the ability to select unlimited number of files. The old GetOpenFileName interface returned multi-select filenames in a fixed size buffer. This can be a real limitation and in my own code I have had to hack the VCL code to make this buffer larger for when my app runs on XP.
TOpenDialog will delegate the work to TFileOpenDialog if possible. The test it uses requires all of the following to be true:
Running on Windows Vista or later.
Dialogs.UseLatestCommonDialogs global boolean variable is true (default is true). This allows you to disable the use of the new COM dialog should you elect to do so.
No dialog template is specified.
OnIncludeItem, OnClose and OnShow events are all not assigned. Presumably these cannot be fired by TFileOpenDialog.
Summary
If you continue to use TOpenDialog then you will reap the benefit of unlimited number of file in multi-select mode. However, if you wish to customise the dialog, and have the new dialogs rather than the ugly compatibilty dialogs, then you need to do the following:
On XP use TOpenDialog and the dialog template method.
On Vista and later use TFileOpenDialog and implement customisation with IFileDialogCustomize.
Related
I'm injecting a number of forms into an existing application using a dll.
I don't control the existing application, nor do I have source code for it.
(I doubt the source code exists any more).
I want to show a TextHint in a TEdit.
In the form designer this works, but in the application it doesn't.
I traced it to the fact that StyleServices (This used to be called ThemeServices (now deprecated)) is not enabled, disabling the TextHint.
Obviously I cannot enable styles for the application, all I have is a dll.
Is there a way to show the texthint?
I prefer to use a stock TEdit.
The dll is written in DX and the old application is written in D7.
BTW I don't care a hood about any additional styling/theming or the like. I just want the texthint to display.
Is there a way to show the texthint?
Standard TextHint functionality in a stock TEdit is dependent on the EM_SETCUEBANNER message, which only works when Visual Styles are enabled:
Note To use this API, you must provide a manifest specifying Comclt32.dll version 6.0. For more information on manifests, see Enabling Visual Styles.
If Visual Styles are not enabled in the app you are injecting your code into, then the only way to do what you are asking for is to subclass the TEdit window and custom-draw it manually when its text is empty.
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.
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);
Delphi7 (cannot use latest). I want to replace (easy way, not making my form) MessageDlg calls with Vista style dialogs (must still work on old OS!). I need buttons Yes/No/YesToAll/NoToAll in this.
How to do it?
MessageBox isn't a way: I need all 4 buttons Yes/No/YesToAll/NoToAll in one form, or maybe checkbox instead of ToAll btns.
On Vista you use the native task dialog, TaskDialogIndirect. This has all the functionality you need. You'll need to translate the headers to Pascal, but if you don't fancy doing that yourself then you can use the JEDI header translations, for instance.
On XP and older there is no task dialog. There is no native system dialog with the functionality that you desire. Therefore you need to implement the dialog yourself. Create a Delphi TForm descendent. Add the necessary text, buttons, styling etc. Show it with ShowModal.
One of the issues with all this is that TaskDialogIndirect must be bound at runtime with GetProcAddress. In fact, use GetProcAddress to determine whether TaskDialogIndirect is available, and if not fall back to the XP code path.
If you don't want to build this yourself you can use one of the many extant libraries that offer such functionality. For instance: http://blog.synopse.info/post/2011/03/05/Open-Source-SynTaskDialog-unit-for-XP,Vista,Seven
I currently use the TOpenTextFileDialog as it has the Encodings option, but under Vista it appears using the older open dialog style. I'd like the new style open dialog, but with an encoding combobox that I can fill with custom strings. Basically I want the exact open dialog that Notepad shows under Vista. Of course I also need the corresponding save dialog as well.
I've done some research and it seems that the OFN_ENABLETEMPLATE flag causes the Vista common dialog to fall back to the old style. Unfortunately that's also the flag that lets the TOpenTextFileDialog modify the window to add the encodings combobox (if I understand things properly.)
Does anyone have a suggestion on how to get what I want under Vista but still have it work under XP? I assume that Windows 7 will have the same issue. I'm using D2009. Thanks for any suggestions or help!
With Vista a new way of dealing with file dialogs has been introduced, for more information google for the IFileDialog interface or have a look at this blog post. As you say yourself, using the OFN_ENABLETEMPLATE flag causes the Vista common dialog to fall back to the old style.
With Delphi 2007 and 2009 you can use the TFileOpenDialog and TFileSaveDialog in the Vista Dialogs components category. To make your application compatible with pre-Vista Windows versions you should keep using the TOpenTextFileDialog for those, and check at runtime whether you are on Vista and can use the new dialogs:
if Win32MajorVersion >= 6 then begin
// use TFileOpenDialog
// ...
end else begin
// use TOpenTextFileDialog
// ...
end;
Now you only need to add the customization to the Vista dialog. The blog post shows how to do this, by adding a handler for OnExecute of the dialog (because at the time when this is called the IFileDialog interface has been set up already), querying the Dialog member of the file dialog for the IFileDialogCustomize interface, and using this to add the additional controls.