A few years back, I ran some analysis on the shims that were applied to applications (both for commercial applications in sysmain.sdb and for those applications shimmed in our enterprise engagements), and though VirtualRegistry eeked out a victory, if you were to consolidate the version lie shims, they became the clear victor.

This, to me, remains an incredible statement on where we have landed in the world of compatibility. Applications aren’t breaking because of some fundamental change in Windows itself, they’re breaking because the applications themselves don’t believe future versions of Windows will be compatible. In fact, they’re so sure that they are right in their prediction of the future that they flat out refuse to run without even trying.

Now, for shim ninjas, this is the easiest fix you can possibly implement. I can probably whip up a verlie shim with both hands tied behind my back, pecking at they keyboard with my nose. But for normal humans (note: shim ninjas, by definition, are not normal humans), this is very non-trivial. So, what do we do from an OS perspective?

Starting with Windows 7, you probably noticed that we stopped changing the major version of Windows. If you are checking the major version, it remained at 6. It also caught flawed logic in version lies, such as:

if (verMajor >= 5 && verMinor >= 1) {
    // oh, hello, you must be Windows XP or later
   
// (clearly I didn’t test this code on Windows 6.0)
}

So, Windows 7 was 6.1, and Windows 8 was 6.2. For Windows 8.1, we looked for a way to implement something even more compatible, as there were still plenty of checks for equality we wanted to get past. It had been suggested many times in the past that we should just keep the version number the same. Of course, the problem with that is, some people are so desperate to know precisely which version of Windows they are running on that, if we don’t tell them the approved way, they’ll find some other way to find out – and that other way might be harder to version lie to.

But, with Windows 8.1, we had an idea:

We would continue to call ourselves Windows 8.0 … UNTIL you put in a compatibility manifest that says “hey, I’m hip and current and know all about Windows 8.1, so go ahead and tell me the truth.”

Until you put in this manifest, we’ll tell you that you’re running on Windows 8.0 (6.2). Once you do, we’ll stop lying and call ourselves Windows 8.1 (6.3).

Here’s a simple program to test it out:

#include <stdio.h>
#include <Windows.h>

#pragma warning(disable : 4996)

void main(void) {
    OSVERSIONINFO osvi;
    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&osvi);
    printf("\nYou are using Windows %d.%d\n", osvi.dwMajorVersion, osvi.dwMinorVersion);
    printf("\nPress any key to continue...");
    getchar();
    return;
}

Compile and run this without putting in a compatibility manifest, and you’ll be told that you’re running 8.0. Then, add the following to the manifest:

<ms_compatibility:compatibility xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" xmlns="urn:schemas-microsoft-com:compatibility.v1">
    < ms_compatibility:application xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1">
        <!-- Windows 8.1 -->
        < ms_compatibility:supportedOS xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"></ms_compatibility:supportedOS>
    </ms_compatibility:application>
< /ms_compatibility:compatibility>

Once you include this in the manifest, we’ll fess up and tell you that you’re running on Windows 8.1. (Note: In an effort to optimize performance, explorer.exe does caching. A LOT of caching. So, you may need to do some file renames if you want to play around with changing manifests in real-time, or else risk hitting a cached manifest.)

So, it has, indeed, come to this – we’re lying by default now. But the overwhelming compatibility impact of apps refusing to run for no valid technical reason were the motivation. We’ve marked the version check APIs as deprecated (hence the pragma to disable warning 4996 in my code), and replaced them with ones that make it simpler to do the right thing.

The numbers absolutely back this up. The typical organization has received no benefit from version lies (note: that doesn’t mean that nobody has – there are definitely valid reasons for this, many of them regulatory, just that on average you benefit from fewer than 1 of these). However, the aggregate cost of finding and repairing flawed or unnecessary version checks averages well over a million dollars per organization per migration.

So, if you’re wondering why the version check APIs seem to be a bit flaky, hopefully this explains why. And I’ll wonder right back at you – why do you think you need to do a version check? And, are you really, really sure you do?

Note for Nerds: consolidating the version lie shims isn’t really much of a stretch. Each of the individual version lies actually just passes the version numbers into a shared class that performs the version lie magic.