Announcement

Collapse
No announcement yet.

Windows 8.1 detection

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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?

  • #2
    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

    Comment


    • #3
      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

      Comment


      • #4
        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.
        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...

        Comment


        • #5
          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)?

          Comment


          • #6
            Lenge
            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

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

            ;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
            <version> can be replaced with the following values:
            ;
            ; 95
            ; 98
            ; ME
            ;
            ; NT4
            ; 2000
            ; XP
            ; 2003
            ; Vista
            ; 2008
            ; 7
            ; 2008R2
            ; 8
            ; 2012
            ; 8.1
            ; 2012R2

            Comment


            • #7
              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

              Comment


              • #8
                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

                Comment


                • #9
                  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:


                  Last edited by LoRd_MuldeR; 15 February 2014, 15:12.
                  My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
                  My source of inspiration: http://youtu.be/lCwY4_0W1YI

                  Comment


                  • #10
                    Small update:


                    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

                    Comment


                    • #11
                      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

                      Comment


                      • #12
                        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

                        Comment


                        • #13
                          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

                          Comment


                          • #14
                            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...

                            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.

                            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.
                            Last edited by LoRd_MuldeR; 16 February 2014, 13:43.
                            My Plugins: StdUtils | NSISList | CPUFeatures | ExecTimeout | KillProc
                            My source of inspiration: http://youtu.be/lCwY4_0W1YI

                            Comment


                            • #15
                              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.


                              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

                              Comment

                              Working...
                              X