Old 14th February 2014, 14:20   #1
Lenge
Member
 
Join Date: Oct 2007
Posts: 64
Question Windows 8.1 detection

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?
Lenge is offline   Reply With Quote
Old 14th February 2014, 14:31   #2
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
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...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 14th February 2014, 18:22   #3
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
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

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 14th February 2014, 19:48   #4
Lenge
Member
 
Join Date: Oct 2007
Posts: 64
Quote:
Originally Posted by Anders View Post
Why do you care, Win8 and 8.1 should be the same for any desktop app.
We need to distinguish due to corporate policies.
Quote:
Originally Posted by Anders View Post
I don't think there are any plans for a 2.47 update but the current 3.0 alpha is pretty stable...
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...
Lenge is offline   Reply With Quote
Old 14th February 2014, 19:57   #5
Lenge
Member
 
Join Date: Oct 2007
Posts: 64
Quote:
Originally Posted by LoRd_MuldeR View Post
Yes, 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 [...]
So GetVersionEx has become useless as it does no longer reliably deliver the real Windows version. Too bad!

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 is offline   Reply With Quote
Old 15th February 2014, 04:41   #6
stass
Senior Member
 
Join Date: Nov 2012
Posts: 145
Lenge
Quote:
System::Call "kernel32.dll::GetVersion() i .r0"
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 "
or

Quote:
ClearErrors
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "CurrentVersion"
MessageBox MB_OK "ver : $R0 "
or

Quote:
;http://nsis.sourceforge.net/WMI_header
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
or

WinVer.nsh in nsis-3.0a2
Quote:
<version> can be replaced with the following values:
;
; 95
; 98
; ME
;
; NT4
; 2000
; XP
; 2003
; Vista
; 2008
; 7
; 2008R2
; 8
; 2012
; 8.1
; 2012R2
stass is offline   Reply With Quote
Old 15th February 2014, 07:27   #7
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,434
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
code:
!define RequestExecutionLevel user
!include Packhdr.nsh

Stu
Afrow UK is offline   Reply With Quote
Old 15th February 2014, 08:32   #8
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
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...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 15th February 2014, 13:18   #9
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
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:
http://sourceforge.net/projects/muld...5.zip/download


My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI

Last edited by LoRd_MuldeR; 15th February 2014 at 15:12.
LoRd_MuldeR is offline   Reply With Quote
Old 15th February 2014, 17:05   #10
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Small update:
http://sourceforge.net/projects/muld...2.zip/download

Added the VerifyOSVersion() function, for convenience. See the docs for details!

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 15th February 2014, 17:36   #11
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,434
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
Afrow UK is offline   Reply With Quote
Old 15th February 2014, 18:46   #12
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
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

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 16th February 2014, 01:10   #13
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
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.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 16th February 2014, 12:42   #14
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
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.
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...

Quote:
Originally Posted by Anders View Post
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.
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.

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.

Quote:
Originally Posted by Anders View Post
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.
But if they stick with the current behavior, it might become a "big problem" in the (near) future.

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI

Last edited by LoRd_MuldeR; 16th February 2014 at 13:43.
LoRd_MuldeR is offline   Reply With Quote
Old 16th February 2014, 18:50   #15
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by LoRd_MuldeR View Post
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...
I did not mean revert, I was thinking that the 8.1 guid could be a switch that unlocks GetVersion for all future releases.


Quote:
Originally Posted by LoRd_MuldeR View Post
But if they stick with the current behavior, it might become a "big problem" in the (near) future.
Desktop is dead (Has anything useful been added since Win7?) and they want to force WinRT on everyone.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 16th February 2014, 19:51   #16
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
I did not mean revert, I was thinking that the 8.1 guid could be a switch that unlocks GetVersion for all future releases.
That would make even less sense. But yes, doesn't mean it couldn't happen.

Quote:
Originally Posted by Anders View Post
Desktop is dead (Has anything useful been added since Win7?) and they want to force WinRT on everyone.
I don't think that is yet decided

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.

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 16th February 2014, 22:14   #17
Lenge
Member
 
Join Date: Oct 2007
Posts: 64
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?
Lenge is offline   Reply With Quote
Old 16th February 2014, 22:27   #18
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
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


My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 16th February 2014, 23:08   #19
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
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 ...
WinRT=The new COM-like API at the bottom of the "Metro stack", WindowsRT=Windows on ARM (WOA)

I think 8.2 comes out in April but probably no big changes for Desktop apps, not even charms support?

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 17th February 2014, 00:05   #20
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
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...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 17th February 2014, 00:15   #21
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
I think 8.2 comes out in April but probably no big changes for Desktop apps, not even charms support?
Windows 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 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.

Quote:
Originally Posted by Anders View Post
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...
I can't see any mention of Windows 8 in the docs for that function:
http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

But even Windows Vista and Windows 7 are explicitly not supported:
Quote:
Values are not provided for Windows Vista and Windows 7. To determine whether either of those operating systems are present, use VerifyVersionInfo.

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 17th February 2014, 01:30   #22
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by LoRd_MuldeR View Post
Windows 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.
But there are no useful API changes, all those other things are explorer.exe changes.

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...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 17th February 2014, 12:05   #23
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
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.

Also, the isOS() function has some rather strange behavior:
code:
OS_WIN2000ORGREATER 7 The program is running on Windows 2000 [or later].
OS_XPORGREATER 18 Always returns FALSE.


So we can check for Win2k+, but the check for WinXP+ is going to fail always

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 17th February 2014, 16:42   #24
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by LoRd_MuldeR View Post
So we can check for Win2k+, but the check for WinXP+ is going to fail always
Guess what? The XP check works fine and the docs are wrong.

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:
code:
!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


IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 17th February 2014, 21:42   #25
Lenge
Member
 
Join Date: Oct 2007
Posts: 64
Quote:
Originally Posted by LoRd_MuldeR View Post
Doesn't look like it can be fooled by "compatibility mode"
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).

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.

Quote:
Originally Posted by LoRd_MuldeR View Post
but feel free to play around with it yourself
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.
Lenge is offline   Reply With Quote
Old 17th February 2014, 22:10   #26
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Lenge View Post
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.
Nope. My test app was built with Unicode NSIS v2.46.5

Quote:
Originally Posted by Lenge View Post
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.
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.

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

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 18th February 2014, 04:47   #27
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by Lenge View Post
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).
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.

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)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 18th February 2014, 11:07   #28
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
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".

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 18th February 2014, 15:01   #29
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by LoRd_MuldeR View Post
Restricting VerifyVersionInfo() to only accept what would have been accepted by the older Windows version obviously doesn't aid the golad to improve compatibilty.
Well, I don't agree with this at all.

Imagine this program:
Quote:
if (IsVistaOrLater())
DoVistaThing();
else
DoXPThing();
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.

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:
Quote:
if (major >= 5 && minor >= 1)
DoXPThing();
else
MessageBox("Not supported on this version of Windows");
(This is broken on Vista and would think it is < XP but works correctly again on 7)
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.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 18th February 2014, 16:55   #30
Lenge
Member
 
Join Date: Oct 2007
Posts: 64
Quote:
Originally Posted by Anders View Post
Well, I don't agree with this at all. [...]
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.

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.
Lenge is offline   Reply With Quote
Old 18th February 2014, 17:46   #31
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by Lenge View Post
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.
What you are saying does not make any sense to me. The reason the compatibility shims exist in the first place is so people can apply them on broken applications. If you are asking for a way around that then you are just going to end up causing extra pain for end users down the road unless you write perfect bug free software.

For diagnostics, sure, include kernel32 version, registry version or a GetRealWindowsVersion based on VerifyVersionInfo but for decisions made at run-time I don't think it is wise to fight whatever shims someone has applied to your process.

Before 8.1, things in the manifest only unlocked new features and it is sad that MS has decided to change that. I still think it is a good idea to wait for 8.2 to see if the 8.1 guid is enough to unlock GetVersion before we start thinking about ways to bypass everything...


Quote:
Originally Posted by Lenge View Post
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.
When you say vendor, do you mean NSIS or MS?

As a user I feel that it is my machine and if I want to put your application in compatibility mode then that should be my decision and there should not be anything you can do about it. Sadly because the version functions are implemented differently, Win8.1 leaves us in nowhere land where all of this depends on which function the developer chose to use.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 18th February 2014, 19:28   #32
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
Well, I don't agree with this at all.

Imagine this program:

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.

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:

(This is broken on Vista and would think it is < XP but works correctly again on 7)
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.
Well, I think we can agree that for any possible behavior of the "compatibility mode" we could probably find a program that (still) won't behave as intended with the "compatibility mode" enabled. I think it's just not possible to fix any broken program out there with just a single "compatibility mode" switch - simply because we cannot know what the programmer had originally in mind or what bugs are present in the program. The actual "compatibility mode", as it exists today, has probably been designed to hack around the most common issues.

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 19th February 2014, 02:13   #33
Lenge
Member
 
Join Date: Oct 2007
Posts: 64
Quote:
Originally Posted by Anders View Post
When you say vendor, do you mean NSIS or MS?
I mean Microsoft (the OS vendor that controls the APIs). NSIS is more like a partner that helps me work around some of their OS design decisions. After all, the entire NSIS concept is a way to avoid the "official standard" (which is MSI).

Quote:
Originally Posted by Anders View Post
As a user I feel that it is my machine and if I want to put your application in compatibility mode then that should be my decision and there should not be anything you can do about it.
Good point, yet still:

1.) While I agree that "GetWindowsVersion" should be the "normal" method to use in most cases, I still sometimes need "GetRealWindowsVersion". And when I do so, I know what I'm doing and why I'm doing that. (And, I promise, it's not for the purpose of insulting the user or making the application break. More of the opposite.) So if there is no cleanly defined "GetRealWindowsVersion" API, I'm forced to use some hack, which in turn is more likely to cause problems than any clean solution.

2.) In the case of Windows 8.1, you (as a user) just cannot decide to not run an application in compatibility mode. Microsoft has already decided that you must run every app in Win8 compatibility mode, unless the app has an explicit 8.1 manifest (which you as a user cannot influence).
Lenge is offline   Reply With Quote
Old 2nd October 2014, 23:01   #34
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Just for the notes: I had a chance to look at the "Windows 10" preview today. The NT version is 6.4 and the build number is 9841. The workaround I used to get the real Windows version under Windows 8.1 still works in Windows 10. Anyway, I have put up an new build here, so we also get the correct "friendly name" on Windows 10.


My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 4th October 2014, 05:31   #35
JasonFriday13
Major Dude
 
JasonFriday13's Avatar
 
Join Date: May 2005
Location: New Zealand
Posts: 877
Nice .

I'll be checking out the preview as well pretty soon.

"Only a MouseHelmet will save you from a MouseTrap" -Jason Ross (Me)
NSIS 3 POSIX Ninja
Wiki Profile
JasonFriday13 is offline   Reply With Quote
Old 19th March 2015, 21:16   #36
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Exclamation Public service announcement:

Win10 TP 10041 now also lies to the VerifyVersionInfo function unless you have the Windows 10 GUID in the manifest.

With no GUIDs in the manifest it tells you that you are on 6.2 and on 6.3 if you have the Win8.1 GUID...

The ManifestSupportedOS instruction in NSIS v3 supports GUIDs as parameters:
Quote:
ManifestSupportedOS Win7 Win8 Win8.1 {8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}
(The latest beta supports Win10 as a parameter so you don't need a guid until Windows 11)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 14th June 2015, 18:36   #37
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
Win10 TP 10041 now also lies to the VerifyVersionInfo function unless you have the Windows 10 GUID in the manifest.
I can confirm this. So they brought it to yet another level of idiocy

Also, at one point, "Windows 10" changed from identifying itself as NT v6.4 to NT v10.0, following the motto "hey, let's establish the most stupid versioning scheme ever, and once everybody has gotten used to this insane mess and implemented the required workarounds, let's break everybody's code once again by making the versioning sane again". Sorry, but is Satya Nadella secretly payed by Apple to piss off the Windows developer community as much as possible? Makes me even less confident that Windows has a future. In the past every "borked" Windows release was followed by a "good" one. But after the Windows 8 disaster, we got the Windows 8 disaster part two (aka Windows 8.1). And with "Windows 10", which was supposed to make it all so much better again, things are just getting worse and worse...

Anyway, that's enough grumbling for now. Here is an updated version of StdUtils, in order to take account for the Windows 10 madness:
https://github.com/lordmulder/stduti...eases/tag/1.06

(The new solution doesn't depend on some obscure GUID that's guaranteed to break with the next Windows version, but uses GetFileVersionInfo() directly on kernel32.dll. Yes, it's ugly, but it works. If, in the next Windows version - provided that there will be a next Windows version - they break GetFileVersionInfo() too or they ship a kernel32.dll with "wrong" version number in its resource section, I'll just throw my Windows PC out of the window)

Have a nice Sunday

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 14th June 2015, 21:34   #38
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by LoRd_MuldeR View Post
The new solution doesn't depend on some obscure GUID that's guaranteed to break with the next Windows version
The GUID is guaranteed to give you forward compatibility for the exact versions you specify, that's the whole point of them in the first place. (You can only test on versions you know the GUID for so your app should not break in the future because it still thinks it's on the older version of Windows)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 14th June 2015, 21:45   #39
LoRd_MuldeR
Major Dude
 
LoRd_MuldeR's Avatar
 
Join Date: Sep 2005
Location: Somewhere over the Slaughterhouse
Posts: 797
Quote:
Originally Posted by Anders View Post
The GUID is guaranteed to give you forward compatibility for the exact versions you specify, that's the whole point of them in the first place. (You can only test on versions you know the GUID for so your app should not break in the future because it still thinks it's on the older version of Windows)
By definition, we now need to include the specific GUID for Windows version "xyz" in order to make Windows version "xyz" identify itself faithfully. Any Windows, for which the specific GUID is not included in the program's Manifest, will lie to us and give invalid result. But it's impossible to know and include the GUID's for any Windows version that will exist in the future - they simply are not known yet!

But the whole purpose of a version getter API is to report the exact system version that we running on - including any future version that may not even have existed by the time we compiled the program! With that GUID nonsense, even if I include all the GUID's that existed by the time I compiled my program, the API still will only report those Windows versions correctly that existed by the time I compiled my program. Any future Windows version would lie to my program! It would report the Windows version my program was compiled for, not the "true" Windows version we are running on. But it's especially interesting/important to get the correct Windows version in this case!

An API that just reports an information that I already know at compile time - the highest Windows version for which I have included the corresponding GUID - effectively is a NOP(*). Which makes the "official" version getter API of Windows totally pointless now




(*) Yes, it's not entirely a NOP, because I can still distinguish those Windows version for which I explicitly have included the corresponding GUID's. But that's clearly not sufficient. And it's certainly not what you'd expect from a proper version getter API! It's a crippled version getter API that you cannot rely on!

My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
My source of inspiration: http://youtu.be/lCwY4_0W1YI
LoRd_MuldeR is offline   Reply With Quote
Old 14th June 2015, 23:14   #40
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,105
Quote:
Originally Posted by LoRd_MuldeR View Post
...and give invalid result.
It is not a invalid result, it is just that your app is running in compatibility mode. If you include the GUID for Windows 10 today in 2015 then your app is supposed to work without changes on Windows 11 assuming you are not doing undocumented stuff. It is of course impossible to test on Windows 11 now so your app is just supposed to pretend that it is still on 10 which is why the API lies.

Your are not really supposed to check the version number anyway, you are supposed to check if a feature exists before using it or whatever fallback mode you might have. Granted, it sucks for logs etc but MS has decided that compatibility for crappy programs is more important than keeping developers happy...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump