Wednesday, August 11, 2010

Embedding Application Manifest and Version Information using QtCreator

Modern applications for Microsoft Windows should include an embedded manifest and version information. The version information is used for example by the UAC dialog and it is displayed in Explorer's file properties. The manifest is even more important because without it Vista and Windows 7 will virtualize your application's access to the registry and file system. Unfortunately it is not obvious how to embed such information using QtCreator, so we publish this post in hope it will save you time.

Application Manifest

First, we have to prepare an application manifest file. This one below is for application that does not require administrator rights:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="2.0.2.0" processorArchitecture="X86" type="win32"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>
Second, we need the MT.exe tool from the Microsoft Windows SDK to embed this XML in our executable. To do it use the following command:
mt.exe –manifest MyApp.exe.manifest -outputresource:MyApp.exe;1

Automatic Manifest Embedding

Manually executing the mt command after each compilation is a tedious task. What about convincing qmake to do it for us? After studying the docs it looks like the following line should do the trick:

win32 {
    WINSDK_DIR = C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A
    WIN_PWD = $$replace(PWD, /, \\)
    OUT_PWD_WIN = $$replace(OUT_PWD, /, \\)
    QMAKE_POST_LINK = "$$WINSDK_DIR/bin/x64/mt.exe -manifest $$quote($$WIN_PWD\\$$basename(TARGET).manifest) -outputresource:$$quote($$OUT_PWD_WIN\\${DESTDIR_TARGET};1)"
}
The above code will automatically execute the mt.exe program from WINSDK_DIR and embed a manifest file that is located in the project root directory and named after project's target (ie. MyApp.manifest). That's all to adding a manifest, now let's move on and specify the version information.
Version Information

VERSIONINFO is in fact a resource, so put the following in your resource file (ie. MyApp.rc):

1 VERSIONINFO
FILEVERSION 0,0,0,1
PRODUCTVERSION 0,0,0,1
FILEOS 0x4
FILETYPE 0x0
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904B0"
    BEGIN
      VALUE "CompanyName", "MyCompany"
      VALUE "FileDescription", "My cool app"
      VALUE "FileVersion", "0,0,0,1"
      VALUE "InternalName", "MyApp"
      VALUE "LegalCopyright", "Copyright © 2010 MyCompany"
      VALUE "OriginalFilename", "MyApp.exe"
      VALUE "ProductName", "MyApp"
      VALUE "ProductVersion", "0,0,0,1"
    END
  END 
  
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x0409, 0x04B0
  END
END
The above example should be sufficient in most cases, for more information about version information resource syntax please refer to the official MSDN documentation. Qmake will process your resource file if you add it to your project (.pro) file:
RC_FILE = MyApp.rc
And that's all. Now your application is ready to be deployed to a Windows system.

4 comments:

  1. Thank you for the post, it was the closest thing I found that could be made to work.

    For my configuration ( open source Qt 4.7.2 with Qt Creator 2.4.1 ) under Windows 7, the following changes were required to make it work. I'm barely literate at QMake, so I'm sure there's a better way:

    CONFIG(debug, debug|release) {
    MY_DESTDIR_TARGET = "$$OUT_PWD/debug"
    }
    CONFIG(release, debug|release) {
    MY_DESTDIR_TARGET = "$$OUT_PWD/release"
    }

    win32 {
    WINSDK_DIR = C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A
    WIN_PWD = $$replace(PWD, /, \\)
    DESTDIR_TARGET_WIN = $$replace(MY_DESTDIR_TARGET, /, \\)
    QMAKE_POST_LINK += "$$WINSDK_DIR/bin/x64/mt.exe -manifest $$quote($$WIN_PWD\\$$basename(TARGET).manifest) -outputresource:$$quote($$DESTDIR_TARGET_WIN\\$$basename(TARGET).exe;1)"
    }

    ReplyDelete
  2. Just to add another less-intrusive way with VS2010 and Qt4.8+, from http://www.qtcentre.org/threads/29107-win32-how-to-modify-the-manifest-with-qmake

    win32 {
    CONFIG += embed_manifest_exe
    QMAKE_LFLAGS_WINDOWS += /MANIFESTUAC:level=\'requireAdministrator\'
    }

    That works for a minimal case (just requiring administrative rights)

    ReplyDelete
  3. Of all others this one works. Thanks @Gimble.

    ReplyDelete
  4. Of all others this one works. Thanks @Gimble.

    ReplyDelete