Skip to content
⌘ NSIS Forum Archive

Windows version detection reloaded

18 posts

Lenge#

Windows version detection reloaded

In generalization of the Windows 8.1 detection issues, I have examined the WinVer.nsh and StdUtils.GetRealOSVersion functions under various compatibility mode settings. Some results:
  • On a WinXP-32-SP3 host, the "Windows NT 4.0 (Service Pack 5)" compatibility mode makes WinVer.nsh detect Windows NT 4.0 with Service Pack 3 (instead of 5).
  • On a Win7-64-SP1 host, the same compatibility mode makes WinVer.nsh detect Windows NT 4.0 with Service Pack 5 (as expected).
  • On a Win7-64-SP1 host, the "Windows Server 2003" and "Windows Server 2008" compatibility modes make WinVer.nsh detect non-server versions (WinXP and Vista).

Not sure if these are shortcomings of the respective compatibility modes, the GetVersionEx API, or anything specific to WinVer.nsh. But it obviously fails to reliably detect the exact Windows version it is intended to see by the compatibility mode setting.

StdUtils.GetRealOSVersion aims to detect the "real" Windows version, regardless of any compatibility mode setting or any potentially missing OS support GUIDs in the application manifest. In my tests, the function mostly delivers on that promise, with the following exceptions:
  • On both WinXP-32-SP3 and Win7-64-SP1 hosts, the "Windows 95" and "Windows 98 / Windows Me" compatibility modes make StdUtils.GetRealOSVersion deliver "error" strings instead of the real Windows version.
  • StdUtils currently delivers "real" major and minor version numbers, but neither the "real" build number nor the "real" Service Pack number.

@Mulder: Any chance of according enhancements to StdUtils?
Anders#
Windows 8 does not list server versions!

You can try this:
System::Call '*(i284,i,i,i,i,&w128,i0,i0)p.r0'
System::Call 'kernel32::GetVersionExW(pr0)i.r9'
System::Call '*$0(i,i.r1,i.r2,i.r3,i,&w128,&i2.r4,&i2,&i2.r5,&i1.r6)'
DetailPrint $9=$1,$2,$3|SP=$4|SuiteMask=$5|Product=$6
LoRd_MuldeR#
Originally Posted by Lenge View Post
[*]On both WinXP-32-SP3 and Win7-64-SP1 hosts, the "Windows 95" and "Windows 98 / Windows Me" compatibility modes make StdUtils.GetRealOSVersion deliver "error" strings instead of the real Windows version.[*]StdUtils currently delivers "real" major and minor version numbers, but neither the "real" build number nor the "real" Service Pack number.[/LIST]
@Mulder: Any chance of according enhancements to StdUtils?
GetRealOSVersion() was written primarily to get the real Windows version on Windows 8.1+. It's more a side-effect that it also works around compatibility mode. Therefore it will only work when a Windows NT based system is found - Windows 9x didn't even have the required API's. The "Windows 9x" compatibility mode probably makes GetVersionEx() to report a Non-NT system - so the current code won't go on and fail right away. But I will have to analyze that more closely. As long as VerifyVersionInfo() still behaves correctly with "Windows 9x" compatibility mode enabled, a workaround should be possible. Also I think checks for the service pack version could be added, if required.
Lenge#
Originally Posted by LoRd_MuldeR View Post
As long as VerifyVersionInfo() still behaves correctly with "Windows 9x" compatibility mode enabled, a workaround should be possible. Also I think checks for the service pack version could be added, if required.
That would be great; thanks for your effort on such a useful plugin! 🙂
LoRd_MuldeR#
Here is a test version with "Win9x compat mode" workaround:
Lenge#
Originally Posted by LoRd_MuldeR View Post
Here is a test version with "Win9x compat mode" workaround:
http://sourceforge.net/projects/muld...4.zip/download
Thanks! I can confirm that this version now also works in the "Windows 95" and "Windows 98 / Windows Me" compatibility modes on a WinXP-32-SP3 host! (It'll take a while until I'll be able to also check the Win7-64-SP1 host.)

Would be great if you'd find a way to also verify the "real" service pack numbers and build numbers.
Lenge#
Originally Posted by Anders View Post
Windows 8 does not list server versions!
Win7-64 does. There are compatibility modes called "Windows Server 2003" and "Windows Server 2008". However, these modes make WinVer.nsh detect Windows XP and Vista instead of the server versions.

Originally Posted by Anders View Post
You can try this: (...)
The second line - System::Call 'kernel32::GetVersionExW(pr0)i.r9' - seems to instantaneously quit the installer exe on my WinXP-32-SP3 host. The effect is fully reproducible, so I cannot try further. Am I doing something wrong or do I need a 64-bit host to try this approach?
Anders#
Originally Posted by Lenge View Post
The second line - System::Call 'kernel32::GetVersionExW(pr0)i.r9' - seems to instantaneously quit the installer exe on my WinXP-32-SP3 host. The effect is fully reproducible, so I cannot try further. Am I doing something wrong or do I need a 64-bit host to try this approach?
No, but you need to use NSIS 3. Change all the p's to i's for 2.4x. Anyway, when I tested it but setting it to a server manually it just reported the product as NT workstation so there might be a bug in Windows there.
LoRd_MuldeR#edited
I noticed there is a "major" and "minor" service pack number:
WORD  wServicePackMajor;
WORD wServicePackMinor;
Does anybody know whether the "minor" number has ever been actually used for something?
LoRd_MuldeR#
Here is a new test version that has Service Pack detection enabled:


Only the "major" service pack version is returned currently, but I think that is sufficient.
Lenge#
Originally Posted by LoRd_MuldeR View Post
Here is a new test version that has Service Pack detection enabled: [...]
Great, thanks! Any chances for also checking the Windows build number?
Originally Posted by LoRd_MuldeR View Post
Only the "major" service pack version is returned currently, but I think that is sufficient.
The additional "minor" Service Pack number has been around for a long time (Windows 2000 or so), but I am not aware of any release that actually used the "minor" number.
LoRd_MuldeR#
I probably could add the build number too. But what do you need the build number for?

To my understanding, each Windows NT version (and for some NT version also each Service Pack) has a corresponding build number. So the build number doesn't rally give you any additional benefit over knowing the NT version plus the Service Pack version, right?

Also, using the VerifyVersionInfo "trick" will probably be much more inefficient with such large values, as used for the build numbers...
Anders#
Win95 and NT 4 are both 4.0 but then you can check for NT vs 9x, the only place it matters is for 98 vs 98 SE. Starting with Vista the service pack is part of the build number as well...
LoRd_MuldeR#
GetRealOSVersion() will fail, if a pre-NT system is detected, because it's technically impossible to run StdUtils.dll on systems prior to Windows NT. That's because some of the API's it uses, like VerifyVersionInfo(), were not even available on Win 9x.

Consequently I think the build number doesn't give any additional info over the Windows NT version plus the Service Pack number.

(I can still add detection of the build number, for purely informational purpose)
Lenge#
Originally Posted by LoRd_MuldeR View Post
I probably could add the build number too. But what do you need the build number for?
Please do so, at least for the VerifyOSVersion function. My current usage is verifying the version info reported by WinVer.nsh against the "real" OS version. At the moment WinVerGetMajor, WinVerGetMinor and WinVerGetServicePackLevel can be verified using StdUtils.VerifyOSVersion, but WinVerGetBuild cannot.

Originally Posted by LoRd_MuldeR View Post
Also, using the VerifyVersionInfo "trick" will probably be much more inefficient with such large values, as used for the build numbers...
Probably true, at least for GetRealOSVersion. But I was more thinking of adding the build number to VerifyOSVersion, which should hopefully be more straightforward.
LoRd_MuldeR#
Okay, I have implemented a halfway efficient way to detect the real Windows build number.

New test version here:
Lenge#
Originally Posted by LoRd_MuldeR View Post
Okay, I have implemented a halfway efficient way to detect the real Windows build number. New test version here: [...]
According to my first set of test runs, it seems to work both reliably and acceptably fast. You rock! 🙂