Why Custom Actions get a Windows Vista Version Lie on Windows 7

Those of you who write application installers using Windows Installer may have noticed a bit of a change in the behavior of version checking in Windows 7 – if you happen to be doing your version checking from a custom action. Let’s have a look.

If you’d like to follow along, here’s what you need to do. Open up Compatibility Administrator. Expand the Applications tree (this could take a minute), and then start typing Windows Installer to quickly scroll down to this entry.

First, you’ll notice a few things which we expect. We’re shimming up msiexec.exe (meaning we’re shimming up every MSI package in the world) with WRPDllRegister, WRPMitigation, and WRPRegDeleteKey. These are all of the Windows Resource Protection shims – so if you have an installer that tries to overwrite kernel32 with some really ancient version, for example, it’ll get fixed up instead of failing.

There’s NonElevatedIDriver – that’s an InstallShield fix, for MSIs created by InstallShield. So far, so good.


And there’s VistaRTMVersionLie.

Whazza – huh? (Double takes are completely appropriate here.)

That’s right, we’re shimming up the Windows Installer application to give it a Windows Vista version lie. What does this affect? Any DLL custom action you implement that does a check to GetVersion(Ex) is now going to think it’s getting Windows Vista instead of Windows 7. Do not pass go, do not collect $200, you’ll think you’re on Windows Vista.

However, any application that uses the MSI tables and takes a look at the VersionNT property will be told the correct version of Windows. So, on Windows 7, VersionNT == 601. Just like you’d expect.

From a pragmatic perspective, this improves the overall compatibility of installers on Windows 7 to a huge degree. We did this to systematically fix apps that refuse to install on anything greater than Windows Vista. And it succeeds at this spectacularly.

From a “bonus side effect” perspective (if you like to think that way) – it does serve the effect of pushing people towards using the declarative method of checking versions in the MSI tables, which is our recommended way of checking for specific versions.

Not only is it recommended, it’s the only sensible API we have for checking a version. The others are really hard to get right. How would you check to see if a version is greater than or equal to a specific version? Well, GetVersion returns something really strange until you yank it apart (Windows 98, for example, is 0xC0000A04). How obvious is this?

dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));

OK, so that’s a little silly, and GetVersionEx has a structure that simplifies this. But even with the OSVERSIONINFO structures, you can do things wrong. For example, say you want to check and see if somebody is using at least Windows XP. You could easily do that as:

if (osvi.dwMajorVersion == 5 && osvi.dwMinorVerison == 1) {…

And of course that will do the trick while Windows XP is the only thing around that it works on, but as soon as we release a new version of Windows, it breaks. But let’s say you’re trying to get it right, and you ordered one of those fancy computers whose keyboard actually has a “greater than” key – you could still lose the logic. I’ve seen this many times:

if (osvi.dwMajorVersion >= 5 && osvi.dwMinorVersion >= 1) {…

That’ll work on Windows XP, break on Windows Vista, and work on Windows 7. It’s the wrong logic. Here’s what you’d have to do:

bIsWindowsXPorLater = ( (osvi.dwMajorVersion > 5) || ( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));

And now we’re complex again.

BUT – with the MSI tables, you can actually use the > key with ease. VersionNT >= 501 will work for Windows XP or greater – for anything we release into the future.

It’s declarative, so you can see the check. It’s easy to get it right. It’s got a lot going for it. Nevertheless, I’ve still seen a lot of people doing things like:

VersionNT = 500 OR VersionNT=501 OR VersionNT=502 OR VersionNT=600

I wonder what they’re going to do for Windows 7?

Now, of course, from the ivory tower we’re always saying “don’t check versions” and we don’t hear the cries that you have to. In the end, it’s a business decision, and I don’t begrudge anybody for saying they can’t afford to test and support something indefinitely on every permutation of system. That’s hard to do. I know you’re going to check for versions. But, there’s an arms race between app compat and the people who want to do the checks. There has even been a suggestion that we *never again* change the version of Windows. I think that’d be downright silly. There are valid business reasons to know what you’re running on.

For example, I’ve got a conversation with a customer going on right now where they work on Windows XP, fail on Windows Vista RTM, and work on Windows Vista SP1. Stuff like that happens. (And, since they were checking from a custom action, they were refusing to install on Windows 7, because they thought they were going onto Windows Vista RTM, where they were known to fail. Ouch.) Ideally, this would use the MSI tables to exclude known bad versions, rather than the unknown.

What I’d like to see is a way to declare supported versions in addition to known bad versions. A known bad version should be blocked – let’s be sensible here. But an unknown version, well if you let it install smoothly, then depending on your relationship with the customer would that indicate a suggestion of support? If it could give some sort of warning “note: this operating system is not supported” but still run, then app compat doesn’t need to come along and remove the launch condition or custom action or verlie the entire framework just to keep apps running.

I get what you’re going for, but I also get that people want their apps to work unless there’s a technical reason why they don’t work. Even if they’re unsupported. Because, for some people, that’s OK. Particularly consumers, many of whom don’t have a lot of money right now to be buying new stuff. Just dazzle them with amazing new features, and they’ll buy it, but people don’t like buying stuff just because you said “don’t work on the fancy new OS that your new laptop came with.”

And so it goes.

Comments (10)

  1. ABC says:


    Can you provide me the blogs or forums link where I can get a genuine information on Win 7 features and the comaptibility.( I know this blog also discuss the same but is there any other sites)

  2. Darwin says:

    ping back from: http://csi-windows.com/blog/all/27-csi-news-general/106-why-custom-actions-get-a-windows-vista-version-lie-on-windows-7


    Thanks for the heads up on msiexec.exe shimming.

    Your readers should also note that the conditions you mention should be placed ON the custom actions in the appropriate sequence table – they should not attempt to read these properties WITHIN the custom action.  This is because deferred custom actions cannot see these properties because they are sandboxed.  I have to guess this is also why some software vendors end up coding the version check into their DLL.  A second reason is efficiency – if the condition is on the custom action, MSI never spins up the custom action because it leaves it out of the deferred script – installations run faster – better for everyone!

  3. Danl65 says:

    Thanks for the warning that GetVersionEx will not report back as Vista under Windows 7.

    I agree that this is the correct method for checking for the OS requirements within your installation package. However, I do disagree that this simplifies checking requirements because VersionNT values between Operating Systems can be the same. Thus you cannot rely ONLY on VersionNT values if you are trying to set conditions for installation or custom actions.


    The Operating System Properties indicates that unfortunately Vista and Server 2008 share the same VersionNT value. This means you have to additionally check to see if the MsiNTProductType = 1 (Server 2008) or 3 (Desktop a.k.a Vista).

    Further, if  your installation requirements include different service packs for various operating systems, then I can see the system checks being just as complex if not more complex as the OSVERSIONINFO structure example you gave Chris.

    For example, we must ensure that for Windows XP that SP3 is installed, however, for Vista, we must ensure that it has SP1 installed. Different SP requirements for different operating systems.

  4. In every new version of Windows, Microsoft includes numerous “shims” to improve compatibility with existing

  5. While MSI has LaunchConditions, it lacks LaunchWarnings as I’ve previously implemented and described in my blog.

    Basically I have on occasion put declarative logic in setup that warns users they are installing on an OS that wasn’t available at the time of development and to take care in validating the application in a controlled environment prior to production release.  We also suggest that they contact us to see if a newer release is available (for sale).

  6. Robin says:

    I was trying to follow along and Installed ACT 5.5, but Windows Installer doesn’t appear in the Applications tree. The list jumps from Windows Help to Windows Media Player 7.

    Why might this be? Does it have to be installed on Vista or Windows 7 to appear (I’m running under XP).

  7. cjacks says:

    Robin – yes, you have to be running on Windows 7 to see the Windows 7 changes. Compatibility Administrator just provides a view into the database running on the local system. If you’re running on Windows XP, you’ll see what it has on it, which is different from what Windows 7 has on it.

  8. SEanS says:

    Another MSI k9a2 user with Multi MSI R4870 Cards all going to wast!

    ? Do I have to go back to XP-64? or can it be resolved?

    Thanks in advance, SEanS.

  9. cjacks says:

    @SEanS – I deal with software applicaiton compatibility, and don’t have any information on the driver availability or support status of particular pieces of hardware. I am sorry I am unable to help. Have you contacted MSI?