Hello world,
just to be sure: What exactly is required to make installers created by NSIS 2.46 detect newer Windows versions such as 8/8.1 or 2012/2012R2?
I used to include an updated WinVer.nsh and thought that was enough, but now I came across http://forums.winamp.com/showthread.php?p=2949897 and http://nsis.sourceforge.net/Using_!packhdr, which made me unsure. What's the story behind that compatibility header stuff and which exact code do I need to put into my scripts to make them successfully detect Win8 and above?
Also, will there be a 2.47 update to "officially" include support for newer Windows versions "out of the box" until the final NSIS 3 is released?
Windows 8.1 detection
64 posts
Why do you care, Win8 and 8.1 should be the same for any desktop app.
To detect Win8.0 you can just copy the Win8 line from WinVer.nsh in NSIS 3.
Windows lies and reports the wrong version when calling GetVersion[Ex] so you need a manifest that declares 8.1 support if you need to know about 8.1. For 2.4x that means !packhdr.
There are a couple of other ways to check. You can check the registry or get the dllversion of kernel32.dll.
I don't think there are any plans for a 2.47 update but the current 3.0 alpha is pretty stable...
To detect Win8.0 you can just copy the Win8 line from WinVer.nsh in NSIS 3.
Windows lies and reports the wrong version when calling GetVersion[Ex] so you need a manifest that declares 8.1 support if you need to know about 8.1. For 2.4x that means !packhdr.
There are a couple of other ways to check. You can check the registry or get the dllversion of kernel32.dll.
I don't think there are any plans for a 2.47 update but the current 3.0 alpha is pretty stable...
Yes, Windows 8.1 broke the GetVersion[Ex] API and will still identify itself as Windows 8.0 - unless you add a special Manifest (UUID) to your executable that "ensures" Windows 8.1 compatibility. But you obviously cannot add such Manifest for future Windows versions (because the UUID of future versions is not known yet), so even with the proper Manifest, your application is going to break in future Windows versions! This was a completely braindead decision by Microsoft! Only to make some completely broken applications work under Windows 8.1, they made GetVersion[Ex] API useless - instead of just having those completely broken applications fixed 👎
Anyway, here is an implementation of GetVersion() that will work correctly on Windows 8.1 as well as on all older versions (at least since Windows 2000) - and it should also continue to work on future Windows versions, as long as they don't break even more Win32 API's:
http://pastie.org/private/2lnfacwakl8opqpnhl2w3q
Anyway, here is an implementation of GetVersion() that will work correctly on Windows 8.1 as well as on all older versions (at least since Windows 2000) - and it should also continue to work on future Windows versions, as long as they don't break even more Win32 API's:
http://pastie.org/private/2lnfacwakl8opqpnhl2w3q
We need to distinguish due to corporate policies.Originally Posted by Anders View PostWhy do you care, Win8 and 8.1 should be the same for any desktop app.
We'll probably go for 3.x once a non-beta version has been released. But if that is not going to happen too soon, another 2.4x update would be very welcome. See, 3.x is not even beta yet...Originally Posted by Anders View PostI don't think there are any plans for a 2.47 update but the current 3.0 alpha is pretty stable...
So GetVersionEx has become useless as it does no longer reliably deliver the real Windows version. Too bad! 😠Originally Posted by LoRd_MuldeR View PostYes, Windows 8.1 broke the GetVersion[Ex] API and will still identify itself as Windows 8.0 [...] you obviously cannot add such Manifest for future Windows versions [...]
Does this also hold for the newer GetProductInfo API? The MSDN page does not mention anything about it, and I have no machine at hand to try.
Doe anybody know (or would be so kind and try)?
Lenge
WinVer.nsh in nsis-3.0a2
System::Call "kernel32.dll::GetVersion() i .r0"or
IntOp $4 $0 & 0xFF ;main ver
IntOp $5 $0 & 0xFF00 ;sub ver
IntOp $5 $5 >> 8
Push $5
Push $4
MessageBox MB_OK "ver : $4.$5 "
ClearErrorsor
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "CurrentVersion"
MessageBox MB_OK "ver : $R0 "
;http://nsis.sourceforge.net/WMI_headeror
OutFile "OperatingSystemInfo.exe"
!include MUI2.nsh
!include WMI.nsh
!include LogicLib.nsh
!insertmacro MUI_LANGUAGE "English"
Section
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem Caption callback_Function
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem Version callback_Function
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem CSDVersion callback_Function
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem ServicePackMajorVersion callback_Function
${WMIGetInfo} root\CIMV2 Win32_OperatingSystem ServicePackMinorVersion callback_Function
SectionEnd
Function callback_Function
#$R0 = result number, $R1 = total results, $R2 = result name
System::Call "user32::OemToChar(t R2, t. r2)"
detailprint "$2"
FunctionEnd
WinVer.nsh in nsis-3.0a2
<version> can be replaced with the following values:
;
; 95
; 98
; ME
;
; NT4
; 2000
; XP
; 2003
; Vista
; 2008
; 7
; 2008R2
; 8
; 2012
; 8.1
; 2012R2
That registry method is the simplest way to correctly get 6.3 on Windows 8.1 but it isn't the recommended way. The WMI method probably also works but I would avoid WMI whenever possible. The other methods will return 6.2 (i.e. ${If} ${IsWin8.1} will never be true).
You need to follow the instructions on http://nsis.sourceforge.net/Using_!packhdr
You need to follow the instructions on http://nsis.sourceforge.net/Using_!packhdr
Stu!define RequestExecutionLevel user
!include Packhdr.nsh
Just to make this clear, using WinVer.nsh from NSISW v3.0 will not work for Win8.1 because v3.0 adds the required 8.1 supported OS GUID to the manifest when you use RequestExecutionLevel...
OS GUID + GetVersion[Ex] doesn't do solve the issue at all!
As explained before, adding the "proper" OS GUID to the application's Manifest doesn't solve the underlying problem at all. They have changed the API to return "the latest OS version supported by the calling application" (according to Manifest), instead of what the actual OS version is! So adding the GUID is just a temporary workaround to get the GetVersion[Ex] API working correctly on Windows 8.1 - but it's almost certainly going to break on any future Windows! That's because you cannot know the GUID's of future Windows versions now.
So, when building an installer today, you might be able to get GetVersion[Ex] to report Windows 8.1 correctly by adding the GUID, yes! But a future Windows 8.2 or Windows 9.0 (whatever they will call it) is going to identify itself still as Windows 8.1 - because the "new" OS GUID, which you could impossibly know at the time when building your installer, is missing in the Manifest. So Windows 8.2/9.0 thinks your application requires Windows 8.1 and thus will identify itself like that. But IMO it is very important to detect also future Windows versions! For example, when I need to ensure that we are running specifically on Windows 8.1, my installer would get fooled on Windows 8.2 😠
On the other hand, the code I posted above does not rely on any OS GUID's in the Manifest, it will (hopefully) continue to give the correct result in future Windows versions and it doesn't use any undocumented Registry hacks or unreliable DLL version checks...
[UPDATE]
Here is a new StdUtils plug-in version with GetRealOsVersion() function:

As explained before, adding the "proper" OS GUID to the application's Manifest doesn't solve the underlying problem at all. They have changed the API to return "the latest OS version supported by the calling application" (according to Manifest), instead of what the actual OS version is! So adding the GUID is just a temporary workaround to get the GetVersion[Ex] API working correctly on Windows 8.1 - but it's almost certainly going to break on any future Windows! That's because you cannot know the GUID's of future Windows versions now.
So, when building an installer today, you might be able to get GetVersion[Ex] to report Windows 8.1 correctly by adding the GUID, yes! But a future Windows 8.2 or Windows 9.0 (whatever they will call it) is going to identify itself still as Windows 8.1 - because the "new" OS GUID, which you could impossibly know at the time when building your installer, is missing in the Manifest. So Windows 8.2/9.0 thinks your application requires Windows 8.1 and thus will identify itself like that. But IMO it is very important to detect also future Windows versions! For example, when I need to ensure that we are running specifically on Windows 8.1, my installer would get fooled on Windows 8.2 😠
On the other hand, the code I posted above does not rely on any OS GUID's in the Manifest, it will (hopefully) continue to give the correct result in future Windows versions and it doesn't use any undocumented Registry hacks or unreliable DLL version checks...
[UPDATE]
Here is a new StdUtils plug-in version with GetRealOsVersion() function:

I thought this was fairly obvious but why would you be trying to detect a future version of Windows before it has been released anyway? Once the new Windows OS is available, you can add the compatibility GUID and then test your application still works with any changes as necessary (e.g. OS detection changes). Microsoft will not publish/confirm the GUID or Windows version until it has gone gold anyway.
This seems a non-issue to me. We only have this small issue because official NSIS 2.46 has not been updated since 2009. NSIS 3.0 is the answer.
Edit: Hypothetically, lets say they released 8.2. As far as your application is now concerned, it is still running on 8.1. What is the problem with this? You should not have written any code specifically for 8.2 because it has only just been released. Therefore the answer is just to add the new GUID and then update your code to deal with changes in 8.2, and finally release the new version of your software.
Stu
This seems a non-issue to me. We only have this small issue because official NSIS 2.46 has not been updated since 2009. NSIS 3.0 is the answer.
Edit: Hypothetically, lets say they released 8.2. As far as your application is now concerned, it is still running on 8.1. What is the problem with this? You should not have written any code specifically for 8.2 because it has only just been released. Therefore the answer is just to add the new GUID and then update your code to deal with changes in 8.2, and finally release the new version of your software.
Stu
This doesn't quite hit the point. The point is that the GetVersion() API has been changed from an API that tells you the actual version of the installed operating system to an API that just returns the latest OS version that your application is compatible with (according to its Manfest) - which probably has been done to "satisfy" some horribly broken programs. This means that GetVersion() is pretty much a NOP function now, because you already know which version(s) you have written into the Manifest at compile time - no need to ask the Win32 API again.
And of course I do need to reliably detect "future" versions too! Detetcing older versions is only one side of the medal. We need both, as that's how any sane GetVersion() has to work! For example, in Debug logs I want to put a FAT WARNING, if the user runs the application on a Windows version I had never tested before. Having to "repair" my installer for every new Windows version in order to workaround API restrictions is the most horrible idea I have ever heard! What a maintenance nightmare and the most braindead decision by Microsoft ever.
Consequently, I recommend that the code I have suggested above (or a similar solution) gets incorporated into NSIS 3.0, so we can have a reliable working Windows version detection "out of the box" again. That code has been successfully committed into the Qt framework already in order to fix their version detection, by the way. Don't see why NSIS wouldn't want that too, as it's a pretty simple/clean solution.
If the version detection in NSIS remains "broken", I (and probably other dev's too) will be forced to stick with an external plug-in 😐
And of course I do need to reliably detect "future" versions too! Detetcing older versions is only one side of the medal. We need both, as that's how any sane GetVersion() has to work! For example, in Debug logs I want to put a FAT WARNING, if the user runs the application on a Windows version I had never tested before. Having to "repair" my installer for every new Windows version in order to workaround API restrictions is the most horrible idea I have ever heard! What a maintenance nightmare and the most braindead decision by Microsoft ever.
Consequently, I recommend that the code I have suggested above (or a similar solution) gets incorporated into NSIS 3.0, so we can have a reliable working Windows version detection "out of the box" again. That code has been successfully committed into the Qt framework already in order to fix their version detection, by the way. Don't see why NSIS wouldn't want that too, as it's a pretty simple/clean solution.
If the version detection in NSIS remains "broken", I (and probably other dev's too) will be forced to stick with an external plug-in 😐
NSIS follows the official MS recommended way of doing things and I don't know if we should add a hack like this to the exehead. At this point we don't even know if GetVersion in 8.2 is going to lie when you have the 8.1 manifest.
I have already written some code for the system plugin that uses VerifyVersion but I have not decided what to do with it yet. The only valid reason I see for doing this is for logging/debugging, a installer should not use this information for its normal logic and you should just accept the lies that Windows tells you because it will probably be more compatible that way.
Is it insane/annoying/silly that MS decided to lie to everyone because of a few bad applications..yes but there are basically no changes for Desktop apps since 8.0 so it is not really a big problem.
I have already written some code for the system plugin that uses VerifyVersion but I have not decided what to do with it yet. The only valid reason I see for doing this is for logging/debugging, a installer should not use this information for its normal logic and you should just accept the lies that Windows tells you because it will probably be more compatible that way.
Is it insane/annoying/silly that MS decided to lie to everyone because of a few bad applications..yes but there are basically no changes for Desktop apps since 8.0 so it is not really a big problem.
You are right, we don't know for sure. We can only make an educated guess at this point. But since they have just introduced this new "mechanism" with Windows 8.1, I highly doubt they're going to revert it with the next version. The intention seems clear: Tell applications what they want to hear (most likely), so customers won't bother our support team with compatibility issues...Originally Posted by Anders View PostNSIS follows the official MS recommended way of doing things and I don't know if we should add a hack like this to the exehead. At this point we don't even know if GetVersion in 8.2 is going to lie when you have the 8.1 manifest.
I'm not so sure about "more compatible". If I write an installer and, e.g., make it refuse to install on future/untested Windows versions, I probably do this for a reason! And if it doesn't work in the way that any sane person expects, I will blame NSIS for the "wrong" behavior. And for applications that are really broken with respect to the version detection Windows had (and still has) the "compatibility mode" since Windows XP. No reason for another "compatibility" layer, which you cannot even turn off and which interferes with "proper" applications.Originally Posted by Anders View PostI have already written some code for the system plugin that uses VerifyVersion but I have not decided what to do with it yet. The only valid reason I see for doing this is for logging/debugging, a installer should not use this information for its normal logic and you should just accept the lies that Windows tells you because it will probably be more compatible that way.
Furthermore, I think the solution ("hack") based on VerifyVersion() doesn't have any drawbacks, provided that Microsoft doesn't make VerifyVersion() go rampage in future versions. If GetVersion() works as expected - as is the case in older Windows versions and might also apply to some hypothetical future versions - the additional VerifyVersion() checks don't do anything. It might be a tiny performance overhead, yes. But honestly, if querying the Windows version is a performance bottleneck of your program/installer, then your problem is elsewhere.
But if they stick with the current behavior, it might become a "big problem" in the (near) future.Originally Posted by Anders View PostIs it insane/annoying/silly that MS decided to lie to everyone because of a few bad applications..yes but there are basically no changes for Desktop apps since 8.0 so it is not really a big problem.
I did not mean revert, I was thinking that the 8.1 guid could be a switch that unlocks GetVersion for all future releases.Originally Posted by LoRd_MuldeR View PostYou are right, we don't know for sure. We can only make an educated guess at this point. But since they have just introduced this new "mechanism" with Windows 8.1, I highly doubt they're going to revert it with the next version. The intention seems clear: Tell applications what they want to hear (most likely), so customers won't bother our support team with compatibility issues...
Desktop is dead (Has anything useful been added since Win7?) and they want to force WinRT on everyone.Originally Posted by LoRd_MuldeR View PostBut if they stick with the current behavior, it might become a "big problem" in the (near) future.
That would make even less sense. But yes, doesn't mean it couldn't happen.Originally Posted by Anders View PostI did not mean revert, I was thinking that the 8.1 guid could be a switch that unlocks GetVersion for all future releases.
I don't think that is yet decided 😉Originally Posted by Anders View PostDesktop is dead (Has anything useful been added since Win7?) and they want to force WinRT on everyone.
Actually "Windows RT", the one that runs on ARM and that is limited to the "Metro" UI, is dead, because it was a complete failure on the Tablet market - while the "normal" Windows 8 with "Metro" and Desktop is still around. Surely, Windows 8 is all about the new "Metro" UI, because they eagerly wanted to push Windows on Tablet computers. They even forced the "Metro" UI on Desktop computers, in an attempt to get as many developers as possible making "Metro" apps. Still, many Desktop users are unhappy with Windows 8 and will stick with Windows 7 (just like they did with Windows XP during the "Vista era"), which is not very surprising. But most important Windows 8 is completely out of the question for companies to install on their Desktop workstations - they all are skipping Windows 8. Even Microsoft now admits that Windows 8 didn't bring the intended success. So in the next "major" version they need to deliver something for Desktop again. Not only to address all the Windows 7 Desktop users, but to deliver something that has a realistic chance to be adopted by companies.
I definitely support the opinion that there must be a reliable way to detect the exact true Windows version that my application is actually running on, without any compatibility lies or guesses. The 8.1 change to GetVersionEx renders it useless for this purpose, so I welcome any addition to NSIS that enables a "real" version detection.
With respect to MuldeR's approach to check a (potentially false) version using VerifyVersion , I'd like to ask how VerifyVersion behaves if the app was run in compatibility mode? Even before the 8.1 change, GetVersionEx was telling lies about the Windows version if the app was run in compatibility mode (instead of the "real" Windows version, it reported the version that was set in the compatibility options). So, how does the VerifyVersion approach behave in this respect?
With respect to MuldeR's approach to check a (potentially false) version using VerifyVersion , I'd like to ask how VerifyVersion behaves if the app was run in compatibility mode? Even before the 8.1 change, GetVersionEx was telling lies about the Windows version if the app was run in compatibility mode (instead of the "real" Windows version, it reported the version that was set in the compatibility options). So, how does the VerifyVersion approach behave in this respect?
Doesn't look like it can be fooled by "compatibility mode", but feel free to play around with it yourself:
WinVer.2014-02-17.zip

WinVer.2014-02-17.zip

WinRT=The new COM-like API at the bottom of the "Metro stack", WindowsRT=Windows on ARM (WOA)Originally Posted by LoRd_MuldeR View Post
Actually "Windows RT", the one that runs on ARM and that is limited to the "Metro" UI, is dead, because it was a complete failure on the Tablet market ...
I think 8.2 comes out in April but probably no big changes for Desktop apps, not even charms support?
There is also shlwapi::IsOS but somebody would have to debug it on 8.1 to figure out the value to use for ISOS_81ORGREATER...
Windows 8.1 and 8.2 are more like Service Packs to Windows 8.0, not really a new Windows.Originally Posted by Anders View PostI think 8.2 comes out in April but probably no big changes for Desktop apps, not even charms support?
Still there have been some tiny Desktop improvements in 8.1, like options for booting directly to the Desktop, having your Desktop wallpaper on the Start screen and having Desktop programs displayed before Metro apps on the Start screen. AFAIK, in 8.2 it will be possible to pin Metro apps to the taskbar. And for 9.0 there are rumors about a Startmenu and Metro apps in "windowed" mode. Just rumors, of course.
I can't see any mention of Windows 8 in the docs for that function:Originally Posted by Anders View PostThere is also shlwapi::IsOS but somebody would have to debug it on 8.1 to figure out the value to use for ISOS_81ORGREATER...
But even Windows Vista and Windows 7 are explicitly not supported:
Values are not provided for Windows Vista and Windows 7. To determine whether either of those operating systems are present, use VerifyVersionInfo.
But there are no useful API changes, all those other things are explorer.exe changes.Originally Posted by LoRd_MuldeR View PostWindows 8.1 and 8.2 are more like Service Packs to Windows 8.0, not really a new Windows.
Still there have been some tiny Desktop improvements in 8.1, like options for booting directly to the Desktop, having your Desktop wallpaper on the Start screen and having Desktop programs displayed before Metro apps on the Start screen. AFAIK, in 8.2 (or maybe it's called "8.1 Update 1") it will be possible to pin Metro apps to the taskbar.
IsOS has checks for Vista+, 7+ and 8+ but they are not documented. This is one of those functions that MS did not really want to document but they were forced to document some of it, probably only the parts used by IE and the active desktop bits. The actual implementation is in shcore.dll IIRC if someone wants to find the 8.1 value...
Interesting. Though I don't see what would be the advantage in using the isOS() function. Especially because relying on undocumented behavior isn't very safe, the function was not even exported by name or declared in a public header before Windows Vista (could only be used via GetProcAddress with some magic number) and - most important - with VerifyVersionInfo() we have a more powerful/flexible alternative that also is officially documented. Finally, even if we did figure out the value to check for Windows 8.1 with isOS(), it would still not be able to detect any future version (unless we update it with every release), leading to the same dilemma as using Manifest GUID's.Originally Posted by Anders View PostIsOS has checks for Vista+, 7+ and 8+ but they are not documented. This is one of those functions that MS did not really want to document but they were forced to document some of it, probably only the parts used by IE and the active desktop bits. The actual implementation is in shcore.dll IIRC if someone wants to find the 8.1 value...
Also, the isOS() function has some rather strange behavior:
So we can check for Win2k+, but the check for WinXP+ is going to fail always 😕OS_WIN2000ORGREATER 7 The program is running on Windows 2000 [or later].
OS_XPORGREATER 18 Always returns FALSE.
Guess what? The XP check works fine and the docs are wrong.Originally Posted by LoRd_MuldeR View PostSo we can check for Win2k+, but the check for WinXP+ is going to fail always 😕
I know this cannot be used for future detection but it can probably help with detecting 8.1 if that is all you need and you don't want to mess with the manifest.
Here is some code I wrote a while ago but never tested:
!include LogicLib.nsh
push $0
push $9
System::Call '*(i148,i,i,i,i,&w128,i,i)p.r0'
!if "${NSIS_PTR_SIZE}" <= 4
System::Call 'kernel32::GetVersionExA(pr0)i.r9' ; OSVERSIONINFOA for Win95
System::Call '*$0(i,i.r1,i.r2)'
System::Call 'kernel32::VerifyVersionInfoW(pr0,i 3,l 20)i.r9'
${If} $9 == 0 ; GetVersionEx lied (Must use string test, if VerifyVersionInfoW does not exist the string will be "error" and that converts to 0 for number testing)
!endif
StrCpy $1 3 ; NT4.SP4 has VerifyVersionInfo
${Do}
IntOp $1 $1 + 1
System::Call '*$0(i276,ir1,i0)'
System::Call 'kernel32::VerifyVersionInfoW(pr0,i 2,l 16)i.r9'
${LoopWhile} $9 = 0
StrCpy $2 -1
${Do}
IntOp $2 $2 + 1
System::Call '*$0(i,i,ir2)'
System::Call 'kernel32::VerifyVersionInfoW(pr0,i 3,l 20)i.r9'
${LoopWhile} $9 = 0
!if ${NSIS_PTR_SIZE} <= 4
${EndIf}
!endif
System::Free $0
pop $9
pop $0
DetailPrint WinVer=$1.$2
I came across this article that says that, if your app includes an 8.1 manifest, it can no longer be run in compatibility mode (see 6th paragraph of the "Update" section).Originally Posted by LoRd_MuldeR View PostDoesn't look like it can be fooled by "compatibility mode"
If your version test application is made with NSIS 3.x (is it?), it probably does include an 8.1 manifest, and so the compatibility mode might not be in effect.
I will, as soon as I have according machines at hand. Currently I have only access to XP machines. In the meantime, it would be great if somebody could verfiy if an application with an explicit 8.1 manifest can be run in compatibility mode or not.Originally Posted by LoRd_MuldeR View Postbut feel free to play around with it yourself
Nope. My test app was built with Unicode NSIS v2.46.5 🙂Originally Posted by Lenge View PostIf your version test application is made with NSIS 3.x (is it?), it probably does include an 8.1 manifest, and so the compatibility mode might not be in effect.
Seems like they can. I have a simple C++ app for testing my get_real_os_version() function. Without Windows 8.1 GUID in the Manifest, the result of GetVersionEx() is wrong and we need to fix it via VerifyVersionInfo(). By adding the GUID, we get the correct value right away. But I can still enable the "compatible mode", which will still make GetVersionEx() return a wrong value - but again VerifyVersionInfo() will fix it.Originally Posted by Lenge View PostI will, as soon as I have according machines at hand. Currently I have only access to XP machines. In the meantime, it would be great if somebody could verfiy if an application with an explicit 8.1 manifest can be run in compatibility mode or not.
BTW: You can get an evaluation edition of Windows 8.1 Enterprise for free and install it in VirtualBox/VMWarePlayer. That's what I do 😉
When you have a Supported OS Guid in your manifest you will not get automatic compatibility fixes for <= that version of Windows. Changes in 8.1 are listed here.Originally Posted by Lenge View PostI came across this article that says that, if your app includes an 8.1 manifest, it can no longer be run in compatibility mode (see 6th paragraph of the "Update" section).
The compatibility mode you can select in the properties tab are additional shims added on top of this. The fact that VerifyVersionInfo is not affected by the changes you make here is a serious bug in Windows (VerifyVersionInfo was added in some NT4 service pack so it is a pretty old function)
Well, it only means that "compatibility mode" doesn't resamble the behavior of the older Windows versions accurately - and it doesn't have to. If you think of "compatibility mode" as something that has the goal to get old/broken applications working under up-to-date Windows (rather than something that has the goal to emulate the older Windows version as accurate as possible), then it makes sense that GetVersionEx() will return the older Windows version (as selected in "compatibilty mode" options) and - at the same time - VerifyVersionInfo() accepts everything up to the actual Windows version. Restricting VerifyVersionInfo() to only accept what would have been accepted by the older Windows version obviously doesn't aid the golad to improve compatibilty. After all it's "compatibility mode", not "emulator mode".Originally Posted by Anders View PostThe compatibility mode you can select in the properties tab are additional shims added on top of this. The fact that VerifyVersionInfo is not affected by the changes you make here is a serious bug in Windows (VerifyVersionInfo was added in some NT4 service pack so it is a pretty old function)
Well, I don't agree with this at all.Originally Posted by LoRd_MuldeR View PostRestricting VerifyVersionInfo() to only accept what would have been accepted by the older Windows version obviously doesn't aid the golad to improve compatibilty.
Imagine this program:
if (IsVistaOrLater())With this code, what happens when you choose a compatibility option in the .exe properties depends on the implementation of the IsVistaOrLater() function in this program. If GetVersion[Ex] was used then the program will fall back to XP behavior like the user requested but if VerifyVersionInfo was used then the users choice is ignored. You could argue that this is not a compatibility issue since the program knows about Vista but perhaps DoVistaThing() stopped working in 7 and you need to fall back to XP behavior for the program to work at all.
DoVistaThing();
else
DoXPThing();
Imagine another scenario: A program uses VerifyVersionInfo but one of the 3rd party DLLs it depends on uses GetVersion, the combined program logic will now be out of sync!
VerifyVersionInfo was invented because people wrote broken comparison code like:
if (major >= 5 && minor >= 1)(This is broken on Vista and would think it is < XP but works correctly again on 7)
DoXPThing();
else
MessageBox("Not supported on this version of Windows");
IMHO VerifyVersionInfo should not act like some backdoor that ignores the requested compatibility mode and should just report the same results as GetVersion.
I also don't understand your compatibility != emulation argument. Emulation is exactly what it does, when the program is started the loader replaces standard Windows functions with a different function that is designed to work like it did in the older OS ( http://blogs.technet.com/b/askperf/a...new-stuff.aspx ). A couple of the shims even have Emulate in their name ( http://technet.microsoft.com/en-us/l...=ws.10%29.aspx )
A real world scenario where the version lie is not even about compatibility but the desire to emulate older behavior is/was MSN messenger. On 7 if you want it to use the tray icon mode you have to emulate a OS that does not have the new taskbar api.
I respectfully disagree. I fully agree with MuldeR in this respect. As a developer, I definitely need a reliable way to detect the exact true Windows version that my application is running on, regardless of whatever manifest or compatibility options have been set.Originally Posted by Anders View PostWell, I don't agree with this at all. [...]
What I do not need is a vendor that tries to tell me that I wouldn't want to know (or am not even allowed to know). Of course, we're all trying to make our apps as compatible with different versions of Windows as possible. But if I decide to query the real version, I do that for a reason, and I want to be sure that the result is correct.
However, I have no objections against having separate functions for "GetWindowsVersion" and "GetRealWindowsVersion", where the second one is not affected by whatever compatibility setting.