In this post I'm going to look at Windows Manifest Files, what they do, why we need them and how to use them in Delphi and FinalBuilder.
We often get asked questions about UAC prompts, High DPI settings, Windows Themes etc when compiling Delphi & C++Builder projects in FinalBuilder. In this post we'll dissect windows manifest files, and look at how the project settings in Rad Studio interact with the manifest file, and why you should use a custom manifest file.
What is a manifest file and what's it for?
A manifest is an xml file, which is typically embedded as a resource (it can be a separate file, but it's not a good practice and is not recommended) in your native windows executable (x86 or x64). This file has information that tells windows (vista or later) what parts of windows it supports, what permissions it needs (UAC), what common control dependencies it has (Windows Side-by-Side loading).
Without a manifest resource, windows has no idea what permissions your application needs, and will not treat your application kindly. You will find things like common controls (file dialogs etc) look strange, attempts to write to files failing and other general misery. In fact your application may fail to run at all on some systems.
Ok, so now we know we really need a manifest, what does that look like.
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<description>FinalBuilder is a GUI-based build automation tool for Windows developers.description>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
The above example is actually the manifest file used in the FinalBuilder IDE. Lets break it down.
The assemblyIdentity tells windows about your application and what the system architecture requirements are. This should be unique. Note that the type, name and version attributes are required. Typically, the version field just has the major version info, I guess you could update it with the exact version each time, but I've never found the need to do that.
The description field is pretty self explanatory.
The dependency section is where you describe the side by side dll dependencies, which for Delphi/C++ Builder applications means windows common controls. This is pretty standard stuff, but it's important because without it, your application will have pretty strange looking file dialogs, if it loads at all.
The trustinfo section is all about security, it tells windows what sort of permissions your application should be given. The requestedExecutionLevel level attribute has 3 possible values :
- asInvoker - requesting no additional permissions. This level requires no additional trust prompts.
- highestAvailable - requesting the highest permissions available to the parent process. When a standard user runs the application, it will behave the same as asInvoker, ie no UAC prompt. If an administrator runs the application, they will see a UAC prompt.
- requireAdministrator - requesting full administrator permissions. All users will see a UAC prompt, standard users will be required to enter an administrator password.
The uiAccess attribute Indicates whether the application requires access to protected user interface elements. Most of the time, this should be set to false. The typical use case for setting it to true is when creating remote desktop style application (like teamviewer etc). If you do set it to true, your application needs to be signed - see this post for code signing in FinalBuilder(https://www.finalbuilder.com/resources/blogs/code-signing-changes-for-2016).
High DPI support.
I'm not going go into to detail on this, it's a complex issue with major differences between windows versions, and limited High DPI support in Delphi. I will say, think very carefully before you enable this, High DPI support in Delphi depends very much on the version of delphi, and third party control support. Don't just enable High DPI support without serious testing. See the msdn doco link at the bottom of this post.
The compatibility section tells windows what versions of windows your application supports. It enables windows functionality in your application. Manifests without a compatibility section default to Windows Vista level functionality.
One of the areas where the compatibility section is very important is detecting the windows version. On Windows 8.1 and 10, in applications that do not specify compatibility with them, GetVersion and GetVersionEx will return 126.96.36.199 for the windows version, rather than 6.3.* for Windows 8.1 and 10.0.* for Windows 10. So your application will think it's running on Windows 8 (or Server 2012) and quite possibly disable functionality.
Don't use Rad Studio's default or auto generated manifest!
I'll explain why in a minute, but first lets look at delphi's support for manifests. Delphi's manifest support differs quite a lot depending on which version of Delphi you are using. I don't have every version installed to check on.
The earliest version I have installed at the moment is D2010, which just has a cryptically named check box :
This option will include a default manifest in the projectname.res file. No options to change anything about that manifest. The manifest included is woefully inadequate.
Fast forward to XE7 :
Things got slightly better (not sure in which XE? version though) as you can now point Rad Studio at a custom manifest file (and you should!) to be included with your application. The default manifest included is still woefully inadequate.
Fast forward again, to Seattle:
Things look different again here, now you can set the badly named "Enable High DPI" and "Enable Administrator Privileges" options. I say badly named, because that's not what those options do. Checking "Enable High DPI" won't make your application support High DPI, it just tells windows it does (when really, it doesn't unless embarcadero fixed it while I wasn't looking). The same applies to the "Enable Administrator Privileges" - it won't give your application Administrator Privileges, it just tells windows your application needs them to run. Semantics shemantics... but I know this has confused many a developer.
Note that the auto generated manifest uses a template, default_app.manifest, which lives in the bin folder, which is typically under program files, so you might need admin access to modify. It's probably a bad idea to modify it anyway, as it will result in a "works on my machine" moment. This template is different in Seattle and later, as it has some "variables" that get substituted by the IDE when building, this file can't be used when building with FinalBuilder as we have no way to get at those variables.
The manifest included is slightly better than before, but still inadequate.
Berlin & Tokyo manifest options are the same as Seattle, just some layout/styling changes. The auto generated manifests have the same limitations as Seattle.
So I said earlier, "Don't use Rad Studio's default or auto generated manifest", and said that the auto generated manifests are inadequate, here's why : they are simply missing information.
There's no assemblyIdentity element, which according to microsoft is required. There's no description element. The High DPI option just sets the dpiAware element to "True/PM", or not at all. You should use a manifest file that is specific to and reflects your application.
For the versions of Rad Studio that support specifying a custom manifest file, just do that. For versions without custom manifest support, uncheck the "Enable runtime themes" option, and add a resource to your project that includes the manifest :
1 24 "E:\\Source\\app\\myapp.manifest"
Using Manifests in FinalBuilder
FinalBuilder has had support for manifest files for a long time (2007, in FB 5), way before Delphi mentioned the word manifest! On the resource compiler tab of the Delphi and C++Builder actions, there is a field to specify the manifest file.
That's all there is to it, FinalBuilder will add that manifest to the projectname.res file (along with the icon and version info).
One last thing, don't forget to add your custom manifest file to your version control, it's source code after all.
MSDN - Application Manifests