Skip to main content
Thoughts from David Cornelius

Category

You can (and should) have complete control over all aspects of the version information, application icon, operating system compatibility, requested user access, Windows theming dependencies, and more in your Delphi projects!

For the better part of a week, I struggled to get some of these aspects configured properly for a suite of programs that are all configured similarly and for which I was building a script to migrate and manage. I had to learn about Microsoft Manifest files and how they are linked into Delphi projects, where to list a common application icon and get it to show up in the Windows TaskBar consistently regardless of individual form settings, and how to manage version info centrally for these programs needing common information such as company and copyright but also per-project data like product name and version number. I've been programming for a long time in Delphi but had just been letting Delphi manage most of this information--sometimes with frustrating consequences.

It was past time to take control!

This blog lists three different types of resources that can be linked into your Windows application. It serves as both a reminder to my future self and a tutorial for others and pulls together a couple weeks' worth of research, trial and error, and scouring the web for bits of information.

APPLICATION ICON

In many VCL programs, simply selecting and assigning an .ICO file to the main form's Icon property, is all you need to set the icon of the application and to see it show up on the TaskBar when running. There are also project properties to set an icon but a main form's icon will override that; if your main form does not have an icon set, the project's icon will show on both the form and the TaskBar.

However, if you need to override any defaults set by the project or a form, you can set the Application.Icon property in code at runtime. The two simplest ways to assign the icon is to call one of the Icon property's methods, such as LoadFromFile or LoadFromResourceName. The latter requires the icon to be stored either in the .EXE or in a loaded resource file such as a DLL. In my applications, I want to store the icon in the EXE itself to keep things simple. A convenient way to do that is to select Project > Resources and Images... from the Delphi menu, click Add, then select your .ICO file, set the Resource Type to ICON, and give it a good Resource Identifier (I chose "APPICON").

Now, when your application is running simply pass in HInstance (the handle to your application) and 'APPICON' (or the name you chose for your Resource Identifier) to override the default icon:

Application.Icon.LoadFromResourceName(HInstatnce, 'APPICON');

The inclusion of this icon as a resource in your executable is recorded in the .DPROJ file for your project and the icon filename shows in the IDE's project manager alongside your code units; it triggers the resource compiler at compile time to generate and build a special resource file with the same base name as your project and with a ".dres" extension. When resources are added to your project like this, a line is also added to the .DPR file for your project:

{$R *.dres}

VERSION INFO

There have been several blogs over the years mentioning the poor version management in the Delphi IDE. The advice is to never allow Delphi to control the version information but to always manage it yourself externally. How do you do this? First, in the project options, make sure "Include version information in project" is unchecked for all configurations. Then, create a resource source file (.rc) with your version information specified in the right format, call the resource compiler to build this resource, and add a $R compiler directive to link it in.

That may sound like a lot of work but I would invite you to read Thomas Müller's blog and download his dzPrepBuild utility. Not only will it build your resource file in the right format for you but it is built to be used in automation scripts to keep it updated with incrementing version numbers and copyright years.

Following the guidelines for using this tool, my version info resource filename was <ProjectName>_Version.rc. Thus, I added a Pre-Build event to the project to build the resource just before compilation:
"$(BDS)\bin\brcc32.exe" $(OUTPUTNAME)_Version.rc

Finally, I added one line to the project's .DPR:
{$R *_Version.RES}

Correction--I actually replaced one line in my project's .DPR: I replaced the {$R *.RES}, incorrectly thinking I no longer needed that line. My belief was that since I cut out the automatic version info and replaced it with my own manually built version info resource, this line was no longer needed. However, that's when I noticed a visual change in my VCL applications and started studying manifest files.

MANIFEST

I had spent a bunch of time researching resources and version info and setting up a script and was feeling pretty good about how projects were being upgraded from Delphi 5 to Delphi 12 with new, more standardized configurations and a modern look and feel. I had been showing progress to my colleagues each week and how much time we would be saving. Then, suddenly, I noticed a visual change in the toolbar of all the programs that had been compiled with these new automated scripts and linked resources.

We're using the RzToolbar from the Konopka Signature VCL Controls package and set a gradient style on the toolbar to go from clBtnFace on the left to clBtnShadow on the right. With all the buttons set to transparent, the icons floated on the toolbar with no borders until you hover your mouse over them, giving a nice, clean and responsive look to the application. But now, the buttons had lost their transparency--all the buttons had a white-ish box, the ones on the far left closely matched the toolbar color but it was very obvious on the right side.

Without Windows themes, buttons are not transparent.

I tried everything I could think of, double-checking the Transparency property of the buttons, checking and unchecking "Enable Runtime Themes" in the manifest section of Delphi's project options, changing DPI awareness, looking through form properties--all to no avail. My research led to a couple of articles about manifest management in Delphi and, like project management, read that I should create my own manifest file--the blog by Vincent Parrett was especially helpful with explanations and examples.

I had written a sample program to test the gradient toolbar and set the project properties to use a custom manifest file that I gleaned from the examples and modified. After lots of trial-and-error testing I finally got to the point where I could break, then fix the transparency issue with the toolbar buttons by simply changing a section of the XML in the manifest. By this time, I had learned the manifest is treated like other resources and linked in--and it uses the default project resource name which I had thought was only for version information. By simply adding that default {$R *.RES} line back in the .DPR, everything was working again. (I wish the documentation on Delphi's support for manifest files had mentioned that.)

With Windows themes supported in the manifest, transparency works fine.

So, what was the key to getting transparency working in the program? It turns out that enabling support for Windows Themes (which is what this transparency feature needed) was simply requiring a dependency on Microsoft Common Controls so that it would use a newer version of the visual controls. This is mentioned on an obscure page in the DocWiki where it shows the default manifest provided by Delphi for Windows targets. I would not have had to create a custom manifest if I had simply left that $R directive in place; however, I now know a lot more about what you can do with a manifest file by having read through the Microsoft documentation on Application Manifests. For example, you can require admin privileges for a program (in <requestedPrivileges>) and you can require Windows 10 or above (in <compatibility>); there are other fine-grained constraints you can add to your applications if you need by crafting a custom manifest.

Sample Project

To preserve my research and make permanent use of the sample program that helped me figure this out, I put it up on Github. It's called RzToolbarTest and includes a project file with associated icon, a resource source (.rc) file to specify the version info, and a manifest file, all linked in using three $R directives. 

I hope to save you--and my future self--some time with better control of Delphi projects!

david Sat, 06/22/2024 - 06:42

I only found it a couple of weeks ago. It all started from a conversation on Delphi PRAXiS when Jim McKeeth mentioned the reFind utility which got me started down the path of automating Delphi project migration. I had a large script filled with regular expressions and it was going well but there was a hole in the process that required manual editing after converting a Delphi 5 project (with no .dproj) up to Delphi 12. I didn't want to rely on programmers setting up the version info manually as it would surely result in inconsistencies. Besides, it's just text and the script had so much of the project information available already--surely that could be automated as well? So, I went looking for a tool to fill that gap and found the perfect solution with yours! And it will also fit in nicely with plans to set up a build server. I just hadn't gotten around to mentioning it on the forum yet because I just finished it late yesterday. Thanks for writing that utility--and blogging about it!

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
Please enter the characters shown; no spaces but it is case-sensitive.
Image CAPTCHA
Enter the characters shown in the image.