Making Delphi programs Vista-Ready
- DelphiVistaTools and Solway's TaskDialog -
On this page I will try to sum-up the different things you can do to make your Delphi programs work better on Windows Vista, as well as providing source code, files, and helpful links.
Much of what is on this page is a summary of information that available elsewhere on the web.
While most Delphi applications will work under Vista without any major issue, quite a bit can be done to make them fit-in with Vista more seamlessly.
We will look at:
- Accessing Vista's user interface theme (fonts, buttons, etc).
- Allowing the application to minimize with an animation.
- Displaying a thumbnail correctly (when you press Alt-Tab or Windows-Tab, or hover over the application's taskbar icon).
- Handling Vista's User Account Control (UAC)
- Accessing Vista's Task Dialogs
- Accessing Vista's File Dialogs
- Where to save your application data?
- Help files on Vista
- Creating a project template for creating Vista applications quickly.
Download DelphiVistaTools (free)
The User Interface (fonts, buttons, etc)
Windows Vista uses a new default font for user interfaces: Segoe UI, and the default font size has increased to 9 point (whereas XP used Tahoma 8). This font and size has been optimized for clarity on LCD monitors using Cleartype. If you want to use these new fonts you will need to go through all your dialogs and make sure the larger text still fits okay in your dialog, and making more room available where necessary. You will probably need to set "ParentFont" to true for all your forms and labels.In DelphiVistaTools you will find the unit "uVista". There is a function there to tell us whether the program is running on Windows Vista, IsWindowsVista.
To use Vista fonts in your application, put uVista in your "uses" statement, then call SetVistaFonts(Self) in the OnCreate procedure of every form in which you want to use the Vista fonts.
Vista uses a different default font for things like memos. It uses Calibri 10pt by default. So you can call SetVistaContentFonts(memo1.font) to set the font of your memo to the Vista default.
Use XPTheme so as to include a manifest file which will enable your application to use updated user interface controls (glass-type buttons, etc).
In your project's .dpr file, add XPTheme to the top of the "uses" list.
If you are using a recent version of Delphi, you may have TXPManifest, and you can use that instead, since it does the same job.
Allowing the application to minimize with an animation
Delphi applications compiled on older compilers have an invisible "application form" which is hidden from the Vista user interface. So when you minimize your application in Vista it will simply disappear rather than visibly shrinking to the Taskbar with an animation like other applications in Vista do. Also, when you hover your cursor over its icon in the taskbar you only see the program's icon in the thumbnail which appears, and not an image thumbnail of its main window. Likewise when you press Alt-Tab or Windows-Tab (Vista's new Flip-3D).We need Vista to recognize our mainform as the application window. You can achieve this by taking the following steps:
- Your project source (.dpr) file must be edited to contain the following:
uses windows, // ie, "windows" must be in the list of used units uVista; var ExtendedStyle : Integer; begin . . . Application.Initialize; // vista compatibility if IsWindowsVista then begin ExtendedStyle := GetWindowLong(Application.Handle, GWL_EXSTYLE); SetWindowLong(Application.Handle, GWL_EXSTYLE, ExtendedStyle OR WS_EX_TOOLWINDOW AND NOT WS_EX_APPWINDOW); end; // end vista stuff
- Add the following procedure declaration in your main form (eg, in Form1):
// vista compatibility procedure AppMinimize(Sender: TObject); // end vista stuff
On Application.OnMinimize we execute this procedure so that if our application is minimized from a shortcut, the correct form will get minimized.
- In the protected section of your main form class declaration (add a protected section if you need to):
protected // vista compatibility procedure CreateParams(var Params: TCreateParams); override; procedure wm_SysCommand(var M: TMessage); message WM_SYSCOMMAND; // end vista stuff
- Then in the implementation section of your main form, the actual functions:
uses uVista; // vista compatibility procedure TForm1.wm_SysCommand(var M: TMessage); begin if IsWindowsVista then begin case (M.WParam and $FFF0) of SC_MINIMIZE, SC_RESTORE, SC_MAXIMIZE: begin M.Result := DefWindowProc(self.Handle, M.Msg, M.WParam, M.LParam); ShowWindow(Application.Handle, SW_HIDE); end; else inherited; end; end else inherited; end; procedure TForm1.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); if IsWindowsVista then Params.ExStyle := Params.ExStyle and not WS_EX_TOOLWINDOW or WS_EX_APPWINDOW; end; procedure TForm1.AppMinimize; begin // draw the main form before we minimize it ShowWindow(Handle, SW_SHOW); // so Vista can get a thumbnail at startup application.processmessages; // allow time for form to be drawn ShowWindow(Handle, SW_MINIMIZE); end; // end vista stuff
- Then, in the FormCreate procedure of your main form:
uses uvista; // vista compatibility if IsWindowsVista then begin SetVistaFonts(self); Application.OnMinimize := AppMinimize; end; // end vista stuff
- Then, in the FormCreate procedure of each subform:
uses uvista, pointerform; // vista compatibility if IsWindowsVista then SetVistaFonts(self); // end vista stuff
- Finally, copy the PointerForm unit into the folder containing your project files. Use the Pointerform unit and make each of your sub-forms of the type "TPointerForm" (e.g., TForm2 = class(TPointerForm) ). Then, importantly, set the parent, in PointerForm.pas, to the main form of your application. For example:
Params.WndParent := form1.handle;
We must ensure that each subform is associated with the mainform, otherwise, if it is shown modally, and you switch between tasks (eg, with Alt-Tab), the modal window will end up behind the main form, and you won't be able to do anything.
Displaying a thumbnail correctly
Take the above steps and you will also get the thumbnails to appear correctly.
Handling Vista's User Account Control
- Vista makes a lot more security checks by default than previous versions of
Windows. If your program needs to take actions that require administrator
privileges then you should declare this in a manifest file. If you do this, then
as soon as they execute your program they will then be asked whether they want
to proceed (if the user has User Account Control turned on), and then
your program will have full administrative rights.
To achieve this, insert the following line at the top of the implementation section of your main form:
{$R UAC.RES}
Make sure that the UAC.RES file is available on the search path to be included in your application.
If you want to use UAC.RES at the same time as XPTHEME, then include the unit XPTHEMEUAC at the top of the uses list in your project file instead of including both UAC.RES and XPTHEME. XPTHEMEUAC combines both functions into the one unit. Otherwise you may have a clash of two different manifest files.
If your application doesn't use administrator privileges, but you want to run another program with administrator privileges, use ShellExecute with 'runas' as the second parameter, to elevate the privileges of the program you want to run.
Accessing Vista's Task Dialogs
Vista provides highly customizable "task dialogs".A basic task dialog is available in the uVista unit, with the function name TaskDialog. This type of dialog will only display on Vista.
More complex dialogs require the use of something like my own Solway's TaskDialog. This library will automatically emulate the same complex Vista dialogs on earlier operating systems, like Windows XP, so you only have to write one set of code.
Accessing Vista's File Dialogs
The unit uVista includes the function OpenSaveFileDialog for accessing Vista's new file open and file save dialogs.Example of use:
uses commdlg var filename : string; OpenSaveFileDialog(self, '', // default extension for saving files '*.*', // show all files extractfilepath(paramstr(0)), // use path of app 'Open file', // either opening a file or saving filename, // the chosen filename is stored in this variable true, // true means file must exist true, // true to allow overwrite prompt false, // false to allow change dir true) // true for open file, false for save
Where to save your application data?
As a security measure, Vista doesn't like you to write to files in the Program Files folder. On Vista, your application data files should go in the user's AppData folder. Normally, they will go in the "Roaming" folder (within the "Appdata" folder), unless they contain computer-specific information, in which case they should go in the "Local" folder.Inside either the Roaming or Local folder you should create a folder with the name of your software company or publisher name, and inside that, another folder with the name of your application, which will hold your application's data files.
It's a good idea, somewhere in your application (possibly in your "About" dialog) to let your user know the location of the application's data files.
The following function will return the Roaming Appdata path:
uses shellapi function GetRoamingUserAppDataPath : string; // works so long as people have at least IE 4. (and Win95 or better) var r: Bool; path: array[0..Max_Path] of Char; begin r := ShGetSpecialFolderPath(0, path, CSIDL_APPDATA, False) ; if r then result := path else result := ''; end;
Help files on Vista
The old .hlp files will not work on Vista, so you will need to supply the new html help files with your application (i.e., .chm files).For Delphi versions less than v6 you can use the UseHtmlHelp unit by Jan Goyvaerts to display the .chm files.
Delphi 2006 is the first version of Delphi that has built-in support for HTML Help, and you can use the HTMLHelpViewer unit.
Creating a template for a Vista application
Inside the DelphiVistaTools package you'll find DelphiVistaApp.zip. This project contains most of the changes mentioned earlier on this page. Unpack the contents of this zip file into a new folder (which might be called "Default Vista App"). Then open the project in Delphi and make sure it compiles. Next, go to "Project - Add to repository", where you are presented with a dialog to fill in. The title can be something like "Vista Application". For the "page", select "Projects".
Now, when you want to start a new Vista application, you simply go to "File - New", clicking on the "Projects" tab, then "Vista Application". You will then be asked which new folder name you want to use for the new project. That's a lot quicker than copying and pasting all those bits of text, and there's less chance of mistakes.
In addition to the application template you can add a "Vista Dialog" to your repository by right-clicking on Form2 (from our default Vista application), then "Add to Repository". Select form2, then give it a title "Vista Dialog". The "page" will be "Dialogs".
Credits: Thanks to Nathanial Woolls for much of the information on Vista fonts and on minimizing Delphi applications.
Kevin Solway: email: software@theabsolute.net
- In the protected section of your main form class declaration (add a protected section if you need to):