Why does my setup program detect the operating system incorrectly the second time I run it?


A customer reported that when their application called the Get­Version­Ex function, it sometimes reported incorrect values. Specifically, the logs collected from clients shows that the first time the program was run on a Windows 7 machine, the operating system was correctly reported as 6.1.7600 (Windows 7), but the second time it was run, the operating system was erroneously reported as 6.0.6000 (Windows Vista).

This was definitely strange behavior, and upon further questioning, the customer admitted that their application was a setup program.

The fact that it was a setup program was the missing ingredient.

What happened is that the setup program ran, correctly detected the version as Windows 7, and then started installing its pre-requisite components. The installer for one of the pre-requisites failed, causing the entire setup to fail.

The Program Compatibility Assistant noticed that the initial attempt to install the program failed, and it guessed (based on its internal heuristics) that the problem was that the program had an incorrect operating system version check. After the first setup failed, the Program Compatibility Assistant puts up a dialog box saying, "Hey, I think I know what went wrong. This setup program has a bad operating system version check. Do you want to give it another shot?" If the client says, "Go for it", then it will run the setup program again, but with a false operating system version.

Unfortunately, the heuristic that the Program Compatibility Assistant used was a false positive in this case, so saying "Go for it" was the wrong answer. (Not like the client had any idea. This was a case of the computer asking the user a question they cannot answer.)

The fix is to add a manifest to the setup program specifying whether it needs to run as administrator. It doesn't matter what the manifest says as its requirements; the fact that the manifest said anything at all means that the setup program understands the new rules introduced in Windows Vista and doesn't need the Program Compatibility Assistant's help.

(You can read the Excluding Programs from PCA section for other ways to disable the Program Compatibility Assistant for a program.)

Comments (65)
  1. Maurits says:

    Public service announcement: prefer using VerifyVersionInfo msdn.microsoft.com/…/ms725492(v=vs.85).aspx or the helper functions like IsWindows7OrGreater() msdn.microsoft.com/…/dn424959(v=vs.85).aspx rather than GetVersionEx().

  2. Billy O'Neal says:

    Actually, this only works on Vista. On Windows 7, just adding the manifest is not sufficient, you must also add the specific OS version to the manifest. (And apparently you'll need to continue updating your manifest with each OS release)

    Win7 reference:

    blogs.msdn.com/…/manifesting-for-compatibility-on-windows-7.aspx

    Win 8.1 reference:

    msdn.microsoft.com/…/dn302074.aspx

  3. Cesar says:

    In fact, you should always add a manifest with that entry to all your Win32 executables. We had problems with non-setup executables being detected as setup executables, which broke them. Disabling the bogus auto-detection and marking it explicitly (either as a setup or non-setup executable) is always better.

  4. Joshua says:

    So, GetVersionEx is now tainted.

    If MS doesn't undo that brain-damage, I'm going to have to start reading the version number of kernel32.dll.

  5. Ben says:

    "(And apparently you'll need to continue updating your manifest with each OS release)"

    Well of course. If you don't update on every release there is no reason to assume you have re-tested on the new release, so there is no reason for the heuristics to exempt you.

  6. Simon Farnsworth says:

    @Billy O'Neal

    It makes sense to say that you should update your manifest with each new tested OS release; that way, when Microsoft release a new Windows version, it can know that you tested against Windows 7 but not against Windows 8.1. This lets the new version limit which shims PCA considers; if you marked it as Windows 7 tested only, it can consider all shims for apps that worked on Windows 7 (excluding shims that don't make sense if you didn't use Windows 8 features), while if you mark it as tested against 8.1, it can consider all shims for apps that work on Windows 8.1, ignoring ones that fix up the differences between Windows 7 and Windows 8.1.

  7. George says:

    Ugh. Why does the OS need to lie about its age? It is not a middle-aged lady on a dating site.

    There are often legitimate needs to know the real version. Sometimes different components need to be installed depending on the version. Sometimes the code needs to behave differently to work around known bugs in specific versions. A manifest is not always an option. If you have a DLL that is loaded in an unknown EXE (like if you are a shared component or a shell extension) then you are at the mercy of the hosting process.

    For example I had a self-registering DLL that had to set different registry keys depending on the version. GetVersion tells lies because regsvr32 doesn’t have a manifest. I had to resort to undocumented ways of getting to the truth (I shall not mention them here).

    Maybe Vista telling old programs that they are running on XP was warranted, because there was a big difference between the two OSs. But since then the changes have been mostly evolutionary. Even differences between Windows 7 and Windows 8 were not that big for desktop APIs. So there can be a new function GetVersionNoLiesPlease, which only programs written post-Vista would know about.

  8. Andrey says:

    "The fix is to add a manifest to the setup program specifying whether it needs to run as administrator."

    Can you please provide the sample snippet of such manifest? Thank you!

  9. Rick C says:

    @George, if you're not sure why Windows lies about the version number, read this Old New Thing article http://blogs.msdn.com/b/oldnewthing/archive/2004/02/13/72476.aspx .

  10. Antonio 'Grijan' says:

    #George: To maintain backwards compatibility, of course! Windows has to lie about its version because of the myriads of (setup) programs that do not check correctly. Windows 5.x (2000 and XP) had been around for about seven years (from late 1999 to late 2006), and many programmers that have forgotten there would be a later version got used to write their version checks as (dwMajorVersion == 5), instead of (dwMajorVersion >= 5). When Windows 6.x (Vista, 7, 8, 8.1) came, those checks started failing, and those programs crashed telling they needed at least Windows 2000! The solution? Detect those programs and lie to them, tell them they are running Windows XP (5.1). The program now runs correctly, and the customer is happy.

  11. George says:

    @Rick – sure, let GetVersion lie, particularly about 5 vs 6 (it's its own fault for returning the bytes in the wrong order). I personally do MAKEWORD(HIBYTE(ver),LOBYTE(ver)) and use the version as a single number.

    But why should GetVersionEx lie? Or why not have a new function that tells the truth?

    [People test the version number with GetVersionEx incorrectly also. And what is the value of telling you "You are running a version of Windows from the future"? You don't know what to do with that information. -Raymond]
  12. technets says:

    There are often legitimate needs to know the real version. Sometimes different components need to be installed depending on the version. Sometimes the code needs to behave differently to work around known bugs in specific versions. A manifest is not always an option. If you have a DLL that is loaded in an unknown EXE (like if you are a shared component or a shell extension) then you are at the mercy of the hosting process.

  13. Gabe says:

    One perfectly legitimate (and perhaps the best) reason to need the actual OS version is for diagnostics. You don't want your telemetry to tell you that most users are on Vista when really they're on Win7, or that the crashes that all seem to be happening on Win7 are actually due to Win8 differences!

    [This I accept since the program is not actually acting on the information, just reporting it. -Raymond]
  14. Joshua says:

    [And what is the value of telling you "You are running a version of Windows from the future"? You don't know what to do with that information. -Raymond]

    Don't bet on it.

    [In practice, what happens is that the program puts up an error message that says "This program is not supported on your version of Windows. You lose." -Raymond]
  15. dave says:

    It seems to me that the situation boils down to "should there be a compatibility mode on Windows version N that offers the application an environment that looks like a specific version less than N?"

    If the answer to that is "yes", then of course the application should be told it's running on the less-than-N version. Otherwise it's in some bizarre nowhere-land that in some places resembles version N, in other places version less than N.

    My answer to "should there be…" is "no, let the damn app programmer fix their bugs".  But this attitude probably explains why I don't have a few billion dollars in the bank.

  16. Joshua says:

    [In practice, what happens is that the program puts up an error message that says "This program is not supported on your version of Windows. You lose." -Raymond]

    Bad programmer. Only display that error message if you know it's not going to work.

    [This I accept since the program is not actually acting on the information, just reporting it. -Raymond]

    So now we can imagine the tech support call. How do I write an API call to check the current Windows version to report it that does not fail on future Windows. In the Windows 2000 era, it would have gone GetVersionInfoEx. I wonder how it would go now. GetFileVersionInfo("kernel32.dll") starts to look attractive.

    ["Bad programmer." And that fixes the problem how? -Raymond]
  17. arghhhhhhhhhhh says:

    Bad logic in pca. If the problem was setup denying install because of incorrect version check, the the version check would be immediately followed by a message box saying so, and then terminating. In this case the installer does no such thing.

    [PCA does not have natural language processing. It doesn't know how to read the error message and interpret it. -Raymond]
  18. Myria says:

    We've given up on GetVersionExW and now use a bunch of VerifyVersionInfoW calls to determine the OS version if we need it.  For survey-type information, we use WMI, which doesn't lie; however, such information is never used to make decisions by the programs themselves, only to provide us statistical information, because future Windows versions' compatibility fixes would not help our program run on those new versions.

    I recently caught an open source product (libcurl) using VerifyVersionInfoW incorrectly right after they committed the change and asked them to change it.  Thankfully, they did. =)

  19. Maurits says:

    > use a bunch of VerifyVersionInfoW calls to determine the OS version if we need it

    Why a bunch? Why not one?

  20. Rick C says:

    Maurits, one possible reason is that "To verify a range of system versions, you must call VerifyVersionInfo twice. For example, to verify that the system version is greater than 5.0 but less than or equal to 5.1, first call VerifyVersionInfo to test that the major version is 5 and the minor version is greater than 0, then call VerifyVersionInfo again to test that the major version is 5 and the minor version is less than or equal to 1."

    I don't know that you'd want to specifically do this but it's the first thing that comes to mind.

  21. Joshua says:

    ["Bad programmer." And that fixes the problem how? -Raymond]

    Taking it away from everybody because somebody misused it just causes other problems.

    Just be glad nobody's written an installer that says "GetVersionInfoEx lies! Giving up."

    [Given that there are problems no matter how you slice it, the question is which set of problems is worse. -Raymond]
  22. Joshua Ganes says:

    I've come to respect the lengths and measures Raymond and the rest of Microsoft take to fix compatibility issues. Having made a few compatibility hacks on some of my own projects, I know how challenging and frustrating this can be.

    Perhaps the solution is to focus on an API for version comparison, rather than providing a multiple-piece version number. Something along the lines of:

    int WindowsVersionGreaterThanMinimal( VERSION_INFO minimal );

    [This is such a great idea, we added that API 14 years ago. -Raymond]
  23. Ian Boyd says:

    When i read the solution (use an assembly manifest with a **requestedExecutionLevel** attribute), i instinctively wanted to up-vote the correct answer.

    Bonus Chatter: [GetVersionEx](msdn.microsoft.com/…/ms724451.aspx) is deprecated.

  24. Matt says:

    @RickC, @Maurits:

    This will call VerifyVersionInfo a bunch of times, and legitimately so:

    HRESULT RunProgramInAwesomeSandbox(VARIOUS_PARAMETERS* params)

    {

     if(IsWindows8OrLater())

       return RunProgramUsingAppContainerAndUACLockdown(params);

     if(IsWindowsVistaOrLater())

       return RunProgramUsingUACPermissionRestrictions(params);

     else

       return JustRunTheDamnProgram();

    }

  25. Maurits says:

    Sure, something like that makes sense. I would add that a general approach would be to check for the existence of the specific features that you're using in a more direct fashion, rather than inferring the existence of the features from the OS version.

    I was worried that they were doing something like

    DWORD dwRealMajorVersion, dwRealMinorVersion;

    for (each combination of major, minor) { VerifyVersionInfo(…); }

    return dwRealMajorVersion, dwRealMinorVersion;

    Doing so would miss the point of why GetVersionEx was deprecated in the first place.

  26. yuhong2 says:

    What is fun about VerifyVersionInfo BTW is with things like XP SP2/Server 2003 SP1.

  27. Dylan says:

    Honestly I don't think this is a case of asking the user a question they cannot answer.  If the user was asked up front whether to fake the version number, that's clearly a question they couldn't answer.  But here the intent of the question is "do you want to try again with some weird settings that might help?".  The user is able to answer that.

  28. Joshua says:

    [Given that there are problems no matter how you slice it, the question is which set of problems is worse. -Raymond]

    Do you really want do encourage people to not trust the APIs in the first place?

    If this is how MS is going to play, than the guy who detected NT by looking at an obscurity in memory mapped files was doing it right.

    [You trust the API. If the API lies to you, go along with the lie. Because the API is telling you "Windows is emulating version N for this process." So you should do things the N way. -Raymond]
  29. Myria says:

    @Yuhong: I checked for 8.1 because I needed to use rdgsbase.  It led to finding a Visual Studio compiler bug, where it generated incorrect assembly code for rdgsbase >.<

    I have a feeling that the reason Windows 7 is NT 6.1 rather than NT 7.0 is because of too many programs "checking" for UAC by looking for dwMajorVersion == 6 rather than >= 6, like that incorrect libcurl commit I mentioned.  Too many programs would think Windows 7 isn't Vista, even though most of the time they'd be better off assuming it were.

  30. Ken Hagan says:

      "checks as (dwMajorVersion == 5), instead of (dwMajorVersion >= 5)"

    Hmm. Yes, that's pretty much what it would take but … I've been writing Windows version checks for a couple of decades now and I *still* can't believe that significant numbers of programmers are *that* stupid. I mean, to know that the past happened (and therefore a version check is required) but to not know that the future will happen (so >= is the correct operator)? Really? Are these people constantly surprised to see the Sun rising *every* morning?

    On the other hand, presumably MS have the data and I certainly haven't. So just how prevalent is this problem? And is it many isolated instances of idiocy, or did someone manage to slip "==" into a major application framework? And is it still happening in today's world, where fairly high-profile browser vendors issue major version updates on a seemingly weekly basis?

    [The more common mistake is if (dwMajorVersion >= 5 && dwMinorVersion >= 1) /* test for 5.1 or higher */. Browsers don't have this issue as much because most people don't check the browser minor version. -Raymond]
  31. Crescens2k says:

    [The more common mistake is if (dwMajorVersion >= 5 && dwMinorVersion >= 1) /* test for 5.1 or higher */. Browsers don't have this issue as much because most people don't check the browser minor version. -Raymond]

    History repeating itself. IIRC, this was the same reason that Windows 95 didn't report its version as 4.00, because of the same kind of bad check for Windows 3.1.

  32. ErikF says:

    The compatibility shims aren't really for the programmer's benefit, but the *user's*. If you're trying to use a 10-year-old program it doesn't matter why the program suddenly stopped working in Windows version Y, but simply that it did. And if a user wants to force your program into thinking that it's running in Windows 95, you shouldn't second-guess them!

    (Similar issues happen in pure virtualization environments too: when I run a VM in VirtualBox it hides the fact that my CPU has SSE4.1 and 4.2 because there are currently issues when those are used. Should I use them because I know they're there?)

  33. Yuhong Bao says:

    [The more common mistake is if (dwMajorVersion >= 5 && dwMinorVersion >= 1) /* test for 5.1 or higher */. Browsers don't have this issue as much because most people don't check the browser minor version. -Raymond]

    What is funny is that if Win7 was actually NT 7.0 and Win8 was actually NT 8.0, people would need to check the minor version less often. And how many programs are testing for Win8.1 right now?

  34. Neil says:

    As another example of this, Firefox used to owner-draw its own title bar. If you installed the desktop experience on Windows Server 2003 then Firefox would draw incorrectly because it only special-cased Windows XP. Fortunately when they switched to using VerifyVersionInfo two months ago they made the test !IsVistaOrLater().

  35. Azarien says:

    @George: there can never be any sort of GetVersionNoLiesPlease, because people would start (mis)using it instead of GetVersionEx (which can lie). Then future versions of Windows would have to lie in GetVersionNoLiesPlease for backward compatibility, and then what? GetVersionNoLiesPleaseNoReally? GetTheRealVersionExExEx? GimmieDaVershunNoSh_t?

    It already happened several times.

  36. Deduplicator says:

    Walls and Ladders is such a nice game …

    Just frustrating for the API-maintainer.

  37. Joker_vD says:

    Apparently, Joshua just refuses to accept the fact that Windows always comes with sorta-kinda "emulators" of its previous versions that are turned on automatically, and are pretty much unconfigurable. I'd assume there is no such thing in the *nix ecosystem (I vaguely recollect that some minor version changes of Linux kernel broke binary compatibility, though I am not sure about it) — and if there is some OS-level trait which is not in *nix, and is in Windows, some people will automatically declare it "stupid", or "evil".

    And "Only display that error message if you know it's not going to work" is… well. What's worse:

    a) Launch the installation of a program, see "Installed successsfully!", try to launch the program and oops, it crashes/terminates instantly without saying a thing — now what?

    b) Launch the installation of a program, see "The OS version is so far from the future that I am afraid to install this", re-launch the installation again with "Run in Windows XP compatibility mode", … and hopefully it will work (BTW, will the installed exe-s be marked with the same compatibility flags?). If not, well, apparently the current Windows can't emulate Windows XP accurately enough.

  38. Joshua says:

    @Joker_vd: I have 100% reliability of the emulator NOT working for my code. It would be better if I could tag my code "never apply compatibility fixes".

  39. Mc says:

    I remember my old Mustek scanner,  when you tried to install it would say "Requires XP SP2".  Of course I was running SP3 by then.  I seem to remember I reinstalled XP, applied service pack 2,  installed the driver then installed service pack 3 and everything was happy again.  I think I was over due a reinstall anyway so it wasn't a huge issue for me.  Today the scanner would go in the bin.

  40. RP7 says:

    It's something of a disgrace how many developers are incapable of checking version numbers correctly.

    It's not a new problem.  I heard that a lot of the difficulties people had with MS-DOS 4.0 arose because developers had got used to checking whether the DOS version number equalled 3.  With DR DOS, a major feature was that by default the OS reported itself to applications as being DOS 3.31 (or 3.41, I forget).  With MS-DOS 5 Microsoft added the ability to lie to MS-DOS.

    Similarly when Vista was introduced, loads of people had trouble because imbecilic developers were checking whether the Windows version was 5.  The problem was so severe that ever since, Microsoft hasn't dared increase the Windows version number, and so Vista, Win7, Win8 and Win8.1 have the version numbers 6.0, 6.1, 6.2, and 6.3 respectively.

  41. ErikF says:

    In any case, having the ability to lie to an application about the version of the OS is nothing new: DOS had it for years in the setver.exe program: support.microsoft.com/…/96767. Which leads me to believe that Santayana's quote that "Those who forget the lessons of history are doomed to repeat it" applies equally well to programming as to other vocations!

  42. jader3rd says:

    It's my understanding (and Raymond can always correct me given he's closer to the source) that the reason why Windows 7 is version 6.1 (which should be Vista SP1) is because so many applications broke when ran as a non-admin (which was way more feasible to do on Vista than on XP), that app installers started checking the upper bounds of the OS version info. They didn't want to run on Vista+1 without double checking on their side that everything worked. This of course screwed up the Windows teams backwards compatibility checks because apps were no longer installing internal builds of Windows 7, so they had to roll the major version back to 6 to do back compat testing.

    Also, does VerifyVersionInfo work if you check for Windows 8.1 without the manifest declaration? I ask because if you don't declare the 8.1 Guid in the exe manifest, GetVersionEx would return the values for 8.0.

    Is there a .Net version of VerifyVersionInfo?

  43. alegr1 says:

    Now, Raymond, tell me please, why does Windows 7, when a program crashes UNDER VISUAL STUDIO DEBUGGER, invokes the compatibility dialog?

    [You seem to assume that I know the answer. -Raymond]
  44. Random User 81947228 says:

    jader3rd,

    The closest that comes to mind is System.Environment.OSVersion which returns a System.Version object based on GetVersionEx. The System.Version class is Comparable.

  45. Cesar says:

    Let me be That Guy and tell a Linux story…

    Some years ago, the Linux kernel had two branches: the "even" branches were stable (2.0.x, 2.2.x, 2.4.x, and 2.6.x), and the "odd" branches were unstable (2.1.x, 2.3.x, and 2.5.x). Due to a new workflow enabled by the use of a DVCS, they ended up with a single stable branch (2.6.x).

    One day, Linus decided to change the version scheme. The versions were in the 2.6.30+ range already, and everyone could see there wouldn't be a 2.7.x or 2.8.x anymore. So the version was changed to 3.x (starting with 3.0).

    Readers to this blog can guess there was some breakage; the Linux kernel had been at the 2.x.y version for way too long (I started using Linux the last millennium, and it was already a 2.x.y kernel). One I recall was the Python build system, which used "linux2" as the operating system in the build scripts, and was not prepared to deal with a "linux3" (later versions fixed it to use just plain "linux"). As is common in the open source/free software world, the wrong parties are the ones which get fixed, so the kernel kept the 3.x version and the userspace programs got fixed.

    Except, of course, for binary-only programs ;-) For these, a personality flag was added to the kernel, which when enabled for a process changes the reported version to be "2.6.(40+x)" instead of "3.x".

    So, yeah, even Linux has a built-in "version lie". Only that it's manual instead of automatic.

  46. dave says:

    >It's something of a disgrace how many developers are incapable of checking version numbers correctly.

    Makes you wonder about the quality of the rest of the code, doesn't it?

    Rule of thumb: if the installer is that screwed up, you probably don't want whatever it is refusing to install.

  47. Joshua says:

    [You seem to assume that I know the answer. -Raymond]

    I do. The PCA is too stupid to check if a debugger is attached. Turning on fault tolerant heap on newly compiled applications running under the debugger is brain-damaged, but PCA does so anyway. If anytime you want to crash on heap corruption, this is it.

    [I have no inside knowledge of the PCA. -Raymond]
  48. Maurits says:

    > does VerifyVersionInfo work if you check for Windows 8.1 without the manifest declaration?

    Yes.

  49. ender says:

    @Engywuck: how else do you think the developer could charge you to run his program on your newfangled OS?

  50. Engywuck says:

    Most insidious are the setup programs that don't even work with all sort of shims attached that pretend the version to be XP. We had to replace an older PC with some Simatic software on it and the installer not only refused to be run at a 64bit OS but also on Win7-32bit, because "this version of windows is not supported, please upgrade". I managed to convince the setup program to start installing, but somewhere in the middle of it it broke again with "hey, I checked, you lied, it's a nonsupported version" – that's when I gave up. I would have understood if it shows a "not supported" warning, but not even *trying* to work…

  51. Marc K says:

    No it doesn't.  The dialog is more along the lines of "Did this application install correctly?"  The user is either sitting there thinking "Duh! Of course it did!"  or "Duh! Of course it didn't!"  A little "Details" link  that explains what the PCA found would be helpful for the more advanced users…or the Help Desk staff the less advanced users call because of the message.

  52. Marc K says:

    "You trust the API. If the API lies to you, go along with the lie. Because the API is telling you "Windows is emulating version N for this process." So you should do things the N way."

    I once found a backup application was failing because it was marked with "Run this program in compatibility mode for Windows Vista".  It was getting the Vista version back and trying to do things the Vista way.  Once the setting was removed, it started doing things the Windows 7 way and worked.  I doubt that Windows is actually able to back up its version lies with full emulation of version N.  Maybe in the future it'll be able to run all the old versions transparently in VMs, but it's not doing anything like that today.

  53. jader3rd says:

    I just finished coding up my first sample program using VerifyVersionInfo (in C# btw), and what a royal pain. No wonder most developers don't use it. I'm sure most of the time devs just want to know if they're running at least a certain version of the OS. But VerifyVersionInfo is trying to solve every possible version gymnastics that anyone might ever stumble across. While I understand the technical purpose behind the dwlConditionMask, it starts to feel like it's more of then problem than the solution.

    If Windows wants developers to only check for minimum version info they write a IsOsVersionAtLeast(DWORD major, DWORD minor, DWORD build, DWORD whateverThisFourthOneIs). That way I can just call IsOsVersionAtLeast(6,3,0,0) to find out if the program is running on Windows 8.1 or something greater.

  54. jader3rd says:

    I just read Maurits's "or the helper functions " part of his comment. Sweet, I'm glad that IsWindowsVersionOrGreater exists.

  55. Anon says:

    This is also irreversible in many cases without requiring Users to MANUALLY REMOVE ALL OF THE CREATED ENTRIES FROM THE REGISTRY.

    Frankly, unless the target application was written pre-WinXP, "Compatibility Mode" is garbage for garbage software written by garbage developers., and it does nothing but break working software.

  56. Klimax says:

    @Anon:

    As for second paragraph: First part is LOL, still have things to see… Second part: Garbage is certain comment not what it describes…

  57. Anon says:

    @Klimax

    I've yet to encounter an application "fixed" with AppCompat that was not poorly written.

    VERY few of the AppCompat shims are anything more than emulations of bugs or the poor security model of previous Windows versions. Developers abusing these issues should never be allowed near an IDE. They're the reason Windows has a garbage reputation for security in the first place.

    The primary difference between Windows, OSX, and *n*x-alikes is that Windows developers are unwilling to outright tell third-party devs when they're writing garbage code.

    [It doesn't matter if you tell them that they are writing garbage code. They don't care. They got their money from the contract job and are off doing something else now. The guy holding the bag is the corporation who paid a contractor to develop some in-house software. They have no in-house expertise to maintain the software (because that's why they hired the contractor after all). -Raymond]
  58. Neil says:

    For some reason GetThemeBackgroundContentRect isn't telling me what the border width of a edit field is on Windows 7. I keep wondering whether I should do a version check…

  59. John Doe says:

    @Raymond, your assumption that we don't know what to do with future versions of Windows is quite unimaginative, not to say condescendingly depreciative.

    Here's a legitimate version check in a setup program without a manifest. Assume that the program was made in the year 2000, so it uses GetVersionEx. When it runs, it looks at the operating system's version. Then, it downloads on-demand the full installation package for this version of Windows, and runs it.

    What could possibly go wrong?

    Now, imagine any program which may download a component on demand. It doesn't have to be a setup program, it could be e.g. a service you run in a cluster. To be shimmed, it only has to have, anywhere in its name, one of the strings "setup" "install" "patch" "update" et al. So, I can't just name my programs as I want, e.g. mail-queue-dispatcher.exe. Or I must include a manifest.

    But from Windows 8.1 on, I have to include the GUIDs of all Windows versions, and keep updating every time a new version of Windows is released, just because.

    Quite frankly, this version shim seems completely arbitrary. It smells like Microsoft doesn't love desktop developers anymore.

  60. Katie says:

    @John Doe

    Those shims are only added once the PCA sees something that makes it think the installation has failed, and has had the user confirm that it should try with new settings. If your installer and your mail-queue-dispatcher program run properly, then that won't happen, and everything will work like it should.

  61. John Doe says:

    @Katie, the simple fact that the program has "setup" or "patch" in its name is enough to ask the user for credentials to install something even before the program runs.

    In the first case, the heuristic wins. But then, the program doesn't have a Windows 8.1 GUID in the manifest, because it doesn't have a manifest. So Windows 8.1 will lie to it. By what you're saying, if the installation fails, the next time it'll ahve shims for an older version of Windows.

    In the second case, it's quite bad, because the program doesn't even purport to "install" anything in the sense of registering what it fetches to appear in Control Panel's "Add or Remove Programs" or "Programs and Features" (or whatever the name).

    But note that I'm quite more upset about the GetVersionEx issue.

  62. Katie says:

    @John Doe

    I don't think it will lie to it that first time around, even without a manifest – the version lie is one of the shims that gets put in place if Windows thinks the install failed and pops up a dialog asking the user if they want to try with some compatibility settings in place. Note that in this article, the customer noted that it detected the version properly on the first run.

    I don't know what all can trigger the failed installation detection, I know I've seen plenty of false positives there. It's annoying, but it does at least make sure the user approves of applying the compatibility settings.

    I had forgotten about the automatic UAC trigger, and I can see that being problematic on systems with older software with the right executable names. However, there does seem to be a little more intelligence to it – I just played around with renaming a file. Although things with "patch" in them trigger it, "dispatch" seems to disable it again. As long as you have a manifest saying it doesn't need to run as administrator the system will honor it – that doesn't need to be updated with each version of the OS.

  63. Anon says:

    @Katie

    There is no intelligence to it. "Setup" is enough to trigger it, but many "setup" programs are simply self-extracting installers.

    Just like determining file contents by file extension, this is a thing that shouldn't exist in the 21st century.

    I also have several setup programs here that, when forced to run as non-admin via manifest, fail because PCA tries to elevate them anyway and collapses in on itself because the system doesn't allow it. That means that, for our installation program, we have to be careful not to use ANY indicator that it installs or sets up software, or we run the risk of file permissions and ownership being set improperly, security holes, the inability to install/update in a non-Admin environment, the inability to see mapped network shares during setup, […]

  64. John Doe says:

    @Katie, I'm sure that was done with the best of intentions. It seems "dispatch.exe" and "dispatcher.exe" are hard-coded exceptions. Anything else will fall in the "patch" case, e.g. "dispatching.exe", "foo-dispatch.exe", "dispatch-foo.exe".

    As for the version shim, I think there are two separate subjects here: the failed installation shim and the Windows 8.1 shim for the lack of the Windows 8.1 GUID in the manifest. I think you're talking about the former. I was talking about the latter, then the former.

    That is, a "setup.exe" without a manifest (remember, it was the year 2000) executed in Windows 8.1 will call GetVersionEx, which tells "this is Windows 8" due to the latter. Then, it'll proceed to download files for Windows 8 and run them. When Windows asks if the installation was successful and the user says "no", the former shim will lower GetVersionEx's answer. In effect, "setup.exe" will never really succeed, even if it doesn't error or if the user says "yes", because it didn't download and install the Windows 8.1 specific binaries.

    To be fair, I haven't actually tested this.

  65. Katie says:

    @John Doe

    Ah, that clears things up – I didn't realize that 8.1 lied about the version automatically unless there is a manifest. Now I see that the there has been a decent amount of discussion above related to that. I know I read it all when it was posted, so I'm blaming my misunderstanding on trying to jump into the discussion on a Monday morning.

    For a newer projct, you could make something that takes requirements from the server and passes them to VerifyVersionInfo in order to determine which installer to download, but of course there would have been no reason to expect GetVersionEx to lie back in 2000 for your example.

    I do agree with everyone that the auto-UAC for setup programs is annoying and a hackish solution, but not including it would also cause problems for end users that aren't aware of compatibility settings. I'm not sure why it wasn't implemented the same way as the failed installation shim.

    Generally in these cases I tend to give Microsoft the benefit of the doubt, due to the pains they go through to ensure backwards compatibility as documented in many posts on this blog.

Comments are closed.