Deploying Qt on XP and getting “not a valid Win32 application”

By now Windows XP is getting a bit long in the tooth and Microsoft has dropped support for it. Windows 2003, though, is still supported by Microsoft. If you’ve using Qt together with Visual Studio (and not the MinGW compiler) and you try deploying your app to a Windows XP or Windows Server 2003 computer, chances are you’re seeing this error:

is not a valid Win32 application

Too far from the future?

This error will not occur for Qt with Visual Studio 2010, but it will when using Visual Studio 2012, 2013 or Visual Studio 2015.

Update thanks to comment below: (use QMAKE_LFLAGS_WINDOWS instead of tweaking the project’s setting): There are basically two ways to fix this; the easy way is to add one extra line to your project’s .pro file, or you can be more adventurous and binary-patch your app’s .exe file.
And yes, this has to be applied for every app you develop, until XP is gone gone gone…

Note: This same error (“.. not a valid Win32 application.”) occurs if you try to start a 64-bit app on a 32-bit Windows XP or Windows 2003 system, so make sure your app is really 32-bit flavored. One way to verify the bitness: launch your app in Windows 7 or 10, start Task Manager, in the process tab check that your app’s name has a “* 32” suffix.

Also: This tweaking do not affect or disturb deployment to other, later Windows versions like Windows 7. (In case you’re targeting multiple Windows versions.) I have verified this works on Windows XP Service Pack 3 and Windows Server 2003 Service Pack 1 and 2 systems.

Let’s take them in order:

  • Open the .pro file for your project and insert this line (I usually do it at the end):

    QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01
    

    Why 5.01? Well if you look at the original settings, using for example dumpbin/headers on your .exe file, you see that the SUBSYSTEM:WINDOWS version is set to 6. This means it can run on Windows Vista and later and why Windows XP rejects it. By changing it to 5, we declare XP and Win2k3 as kosher chaps too. (Those numbers 5 and 6 are the internal Windows version numbers.)
    I thought originally it should be enough to specify /SUBSYSTEM:WINDOWS,5 but then the linker complains: LNK4010: invalid subsystem version number, and it resets it back to 6 πŸ™ So 5.01 it is.

    Note: if you’re compiling a 64-bits flavored .exe file (and thus targeting 64-bits Windows XP) you instead should set <VALUE> to /SUBSYSTEM:WINDOWS,5.02

  • I promised you a more thrilling choice as well, it requires you to have a binary/hex file editor. Open your app’s .exe file with it, go to almost the beginning of the file, you’ll see something along the following lines:

    Before binary editing

    Before the binary editing

    Look for the hex sequence 06 00 00 00 00 00 00 00 (repeated one time). In my example above it’s on address 0000130 but it can be slightly different like 0000128 or 0000140.

    After binary editing

    After the binary editing

    There’s two consecutive series, change both of them to 05 00 01 00 00 00 00 00.

    This binary editing is equivalent to the linker setting I mention above, but actually it suffices to change the two 06 numbers to 05. However, the linker complained when I tried SUBSYSTEM:WINDOWS,5, so let’s humor Microsoft here and set the binary numbers equivalent to SUBSYSTEM:WINDOWS,5.01

    Note: if this a 64-bit .exe file, you’re supposed to instead change to 05 00 02 00 00 00 00 00 (two times).

    Save the .exe file, Windows XP and Win2k3 server should run the file fine.

 
Q: “By setting those values, you’re declaring my app and Qt to be fully compatible with Windows XP. How can you be sure of this?”

While I’m not 100% sure, I think Qt does not depend on any feature(s) introduced in Windows Vista or later. (If you’re targeting WinRT Qt has an option to support it, but that’s another story.)
But of course, if your own code depends on other such new stuff, then deployment to Windows XP won’t work.
Also note: the other compiler for Qt in Windows, MinGW, declares apps to be compatible even back to Windows NT4 SP4, because MinGW sets the SUBSYSTEM:WINDOWS value to 4.0. So chances are pretty high no part of Qt (as yet) fails on Windows XP or Server 2003.

 
Q: “I did exactly what you said, but my app still fails on Windows XP with this error:”

Visual Studio 2012 needs an update

Visual Studio 2012 needs an update

This happens if you’re running the RTM version of Visual Studio 2012. Install the Visual Studio 2012 Update 4 and you should be fine.
 

Q: “I installed Update 4, however my app still fails on Windows XP with the same error as above :-(“

This happens if you’re using VS2012 Qt 5.3 or later: even though you’ve applied Update 4 to VS2012, the ICU DLLs icuin52.dll and icuuc52.dll were unfortunately built using VS2012 RTM (i.e. no Update 4 was applied), here’s a bug report, it also contains a workaround.
 

Q: “I also did just as you said, but my app fails anyway on Windows XP, now showing this error:”

InitializeCriticalSectionEx could not be located

Wrong Platform SDK?

This error can occur for either Visual Studio 2012 or 2013, it’s instead related to what flavor of the Platform SDK you have installed, e.g. Windows SDK 8.x instead of Windows SDK 7.1. More info about this can be found here: How to target XP …

TL;DR: to fix this error, define the environment variable _ATL_XP_TARGETING in your project and rebuild.

Thanks to user theysoar on the Qt Project forums for the screen shot!

 
Q: “Why don’t I have to apply this procedure when I am using the MinGW or the Visual Studio 2010 compilers?”

There isn’t any clear-cut technical explanation for this; while Microsoft did tweak the C runtime startup code between Visual Studio 2010 and 2012, and dropped support for XP deployment, they quickly had to back-pedal and release an update that reinstated XP as a valid target, instead requiring this linker setting or patching. I guess we can blame it on the internal political struggles at Microsoft πŸ™‚

Next up: deploying a real application.

Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484 Warning: get_comment(): Argument #1 ($comment) must be passed by reference, value given in /customers/4/5/3/tripleboot.org/httpd.www/wp-includes/class-wp-comment-query.php on line 484

15 thoughts on “Deploying Qt on XP and getting “not a valid Win32 application”

  1. Hi! This was great information, thanks for this! I managed to get past the “not a valid win32 application” problem, but now I’m getting another error similar but a bit different from the other error message you mention about GetTickCount64. The error I get is: “The procedure entry point InitializeCriticalSectionEx could not be located in the dynamic link library KERNEL32.dll.” I googled this, and it looks like it was also an issue with VS 2012, but I’m compiling with Qt5/msvc2013, so it’s not clear why I’m getting this issue. I was just wondering if you had any idea what the problem could be, or how I could isolate where/why it’s happening. Either way, thanks for the great info, it was really helpful getting to this point!

  2. using qt 5.3.2 msvc 2013 build run on xp,
    already set:

    win32 {
    QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01
    QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE,5.01

    DEFINES += _ATL_XP_TARGETING
    QMAKE_CFLAGS += /D _USING_V110_SDK71
    QMAKE_CXXFLAGS += /D _USING_V110_SDK71
    LIBS *= -L”%ProgramFiles(x86)%/Microsoft SDKs/Windows/7.1A/Lib”
    INCLUDEPATH += “%ProgramFiles(x86)%/Microsoft SDKs/Windows/7.1A/Include”
    }

    but still got error:
    The procedure entry point K32GetModuleFilenameExA could not be located in the dynamic link library KERNEL32.dll

    1. Hi, I think you forgot the trailing underscore, i.e. the compiler flag should be _USING_V110_SDK71_

      P.S. Thanks for the QMAKE_LFLAGS_WINDOWS line! This is better than my suggestion above to edit the project’s settings, because such edits are easily lost if you clone your project via GitHub or so. A line in your project’s .pro file though, will survive much longer πŸ™‚

  3. Hi, I use to manage my Qt VS2012 Project with a .pro file, then I use QMake to generate a Visual Studio Project.
    This way, even adding the QMAKE_LFLAGS_WINDOWS line to my .pro file, the generated .exe file does not run on Windows XP, and if I open it using a binary editor I find that the Windows version is 6.0! Any clue on why is that?

    1. Hmm, have you updated your VS2012 to Update 4?
      I seem to remember, VS2012 RTM version didn’t support building for XP using that /SUBSYSTEM:WINDOWS,5.01 linker switch.

  4. Thank you very much.
    I compiled aseprite with XP flags on, but the result was only runnable on Win7.
    Your Hex Hack was successful.
    πŸ™‚

  5. Hi,
    I built a application that based on Qt5.8 and Visual C++ 2013. When run on WinXP, it report that GetUserPreferredUILanguages could not be found in kernel32.dll. I have defined _USING_V110_SDK71_ in precompiler flag and defines 5.01 as minimal target platform. Is there any hint to fix this error?

    Thanks a lot!

    1. To make it detail:
      1, I set “ProjectProperty / Configuration Properties / Linker / System / Minimum Requirement Version” to 5.0.1
      2, I add “ProjectProperty / Configuration Properties/ C/C++ / Preprocessor” Inherited values “_USING_V110_SDK71_”

      Is there something wrongly set?

  6. Hi! I get “api-ms-win-crt-runtime-1.0.0.dll was not found”. Could I install Windows10 Universal C Runtime (it’s only for Vista) or should I try some other c runtime?

Leave a Reply

Your email address will not be published. Required fields are marked *

Prove you're human * Time limit is exhausted. Please reload CAPTCHA.