[Windows] WindowsVersion()

Share your advanced PureBasic knowledge/code with the community.
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

[Windows] WindowsVersion()

Post by Little John »

The return value of the built-in Function OSVersion() is not always reliable, when a program which was compiled with an older PB version runs on newer Windows versions.
For instance, OSVersion() of PB 5.31 returns 90 when running on Windows 8 ... but it also returns 90 when running on Windows 10. So it's not possible for the program to distinguish between Windows 8 and Windows 10. The following code can do so.

//edit 2022-11-14:
See updated version below by ChrisR, which also covers Windows 11.

BTW, in case you wonder at the post below in this thread by that "expert" (who has repeatedly been banned from the forum): In contrast to his belief, it's not me who is responsible for his confusion. :wink:

Code: Select all

; after
; https://msdn.microsoft.com/en-us/library/windows/hardware/ff563620(v=vs.85).aspx
; https://stackoverflow.com/questions/38102565/how-can-a-vb-6-app-determine-if-it-is-running-on-windows-10

; tested with PB 5.31, 5.44 LTS, 5.60

EnableExplicit

Prototype.i protoRtlGetVersion (*ver.OSVERSIONINFOEX)


Procedure.s WindowsVersion()
   Protected ver.OSVERSIONINFOEX
   Protected RtlGetVersion.protoRtlGetVersion
   Protected hDLL.i
   
   ver\dwOSVersionInfoSize = SizeOf(ver)
   
   hDLL = OpenLibrary(#PB_Any, "ntdll.dll")     
   If hDLL   
      RtlGetVersion = GetFunction(hDLL, "RtlGetVersion")
      CloseLibrary(hDLL)       
   EndIf
   
   If RtlGetVersion = 0 Or RtlGetVersion(@ ver) <> 0
      ProcedureReturn "Error: Can't call Windows API function RtlGetVersion()."
   EndIf     
   
   If ver\dwPlatformId <> #VER_PLATFORM_WIN32_NT
      ProcedureReturn "No Windows NT-based operating system"
   EndIf     
   
   Select ver\dwMajorVersion
      Case 3
         If ver\wProductType = #VER_NT_WORKSTATION
            ProcedureReturn "Windows NT 3.5 Workstation"
         Else
            ProcedureReturn "Windows NT 3.5 Server"
         EndIf
         
      Case 4
         If ver\wProductType = #VER_NT_WORKSTATION
            ProcedureReturn "Windows NT 4.0 Workstation"
         Else
            ProcedureReturn "Windows NT 4.0 Server"
         EndIf
         
      Case 5
         Select ver\dwMinorVersion
            Case 0
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 2000 Workstation"
               Else
                  ProcedureReturn "Windows 2000 Server"
               EndIf
            Case 1
               If (ver\wSuiteMask & #VER_SUITE_PERSONAL)
                  ProcedureReturn "Windows XP Home Edition"
               Else
                  ProcedureReturn "Windows XP Professional"
               EndIf
            Case 2
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows XP 64-bit Edition"
               Else
                  ProcedureReturn "Windows Server 2003"
               EndIf
         EndSelect
         
      Case 6
         Select ver\dwMinorVersion
            Case 0
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows Vista"
               Else
                  ProcedureReturn "Windows Server 2008"
               EndIf
            Case 1
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 7"
               Else
                  ProcedureReturn "Windows Server 2008 R2"
               EndIf
            Case 2
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 8"
               Else
                  ProcedureReturn "Windows Server 2012"
               EndIf
            Case 3
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 8.1"
               Else
                  ProcedureReturn "Windows Server 2012 R2"
               EndIf
         EndSelect
         
      Case 10
         If ver\wProductType = #VER_NT_WORKSTATION
            ProcedureReturn "Windows 10"
         Else
            ProcedureReturn "Windows Server 2016"
         EndIf
   EndSelect
   
   ProcedureReturn "Unknown Windows version"
EndProcedure


Debug WindowsVersion()
Last edited by Little John on Mon Nov 14, 2022 5:37 pm, edited 2 times in total.
freak
PureBasic Team
PureBasic Team
Posts: 5929
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: [Windows] WindowsVersion()

Post by freak »

Kindergarden fight deleted. This section is for code snippets, not flame wars.
quidquid Latine dictum sit altum videtur
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Windows] WindowsVersion()

Post by Little John »

Thank you, freak.
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: [Windows] WindowsVersion()

Post by luis »

There is also this older thread discussing the problem of the false version returned by the OS if interested -> http://www.purebasic.fr/english/viewtop ... =5&t=57368

About "my point" for citing the other thread, since someone may angrily ask :lol:

I did that because in that thread there are mentioned the historical reasons why this OS behavior has been implemented with a link to a MS page explaining that. Also the same kernel API is used there with some comments about its relation to other higher lever os API which use it.
Also alternative methods are shown to solve the same problem using WMI and more.
So, if someone is interested in what shown in this thread because he's using an older PB version for whatever reason he may be interested in what shown there too.
Fair enough ?
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
skywalk
Addict
Addict
Posts: 3994
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: [Windows] WindowsVersion()

Post by skywalk »

Thanks Little John.
#ERRORAPI = 0, is already defined in PB's constants.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
RSBasic
Moderator
Moderator
Posts: 1218
Joined: Thu Dec 31, 2009 11:05 pm
Location: Gernsbach (Germany)
Contact:

Re: [Windows] WindowsVersion()

Post by RSBasic »

Hello Little John
Thank you for your code. Image
Image
Image
User avatar
skywalk
Addict
Addict
Posts: 3994
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: [Windows] WindowsVersion()

Post by skywalk »

@Fluid Byte...you require much explanations lately. I use #ERRORAPI with getlasterror_().

Code: Select all

Procedure.s SL_GetLastError(LastError.i)
  ; SetLastError_(#ERROR_ACCESS_DENIED)
  ; Debug SL_GetLastError(#ERROR_ACCESS_DENIED)
  ; or 
  ; SL_GetLastError(GetLastError_())
  Protected.i *e, lene
  Protected.s e$
  lene = FormatMessage_(#FORMAT_MESSAGE_ALLOCATE_BUFFER | #FORMAT_MESSAGE_FROM_SYSTEM, 0, LastError, GetUserDefaultLangID_(), @*e, 0, 0)
  If lene
    e$ = RemoveString(PeekS(*e), #CRLF$)
    LocalFree_(*e)
    e$ = "Error " + Str(LastError) + ": " + e$
  Else
    e$ = "Error " + Str(LastError)
  EndIf
  ProcedureReturn e$
EndProcedure
;// snippet
    Protected SL_RtlGetVersion.SL_RtlGetVersion = GetFunction(hDLL, "RtlGetVersion")
    ri = SL_RtlGetVersion(@ver)
    If ri <> #ERRORAPI
      winVer$ = "ntdll.dll - RtlGetVersion() - " + SL_GetLastError(ri)
    Else
;// snippet
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Windows] WindowsVersion()

Post by Little John »

Hi,

thanks for your replies.

Luis, I appreciate your comments and the link to additional information.
skywalk wrote:Thanks Little John.
#ERRORAPI = 0, is already defined in PB's constants.
Well,
[u]MSDN[/u] wrote:RtlGetVersion returns STATUS_SUCCESS
So I used that. :-) Didn't know about #ERRORAPI, thanks for the information.

RSBasic, please feel free to include this code into your Win API library, if you think it makes sense. :-)
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Re: [Windows] WindowsVersion()

Post by Fluid Byte »

Since freak abused his moderator rights and deleted all my post whilst having valid criticism I need to clarify that this code is still f***** pointless. You couldn't name a single example where you would have to back so many previous releases that would force you to use the broken bulit-in OSVersion() function.

It's a weak, or rather non-existent argument to begin with since by that logic you would have to provide EVERY PB-Command ever introduced as an alternative API solution for the case that they MIGHT not work properly in older versions.

Again, you are confusing new and old users alike by providing a solution to a problem that doesn't exist.
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
User avatar
Rings
Moderator
Moderator
Posts: 1427
Joined: Sat Apr 26, 2003 1:11 am

Re: [Windows] WindowsVersion()

Post by Rings »

Fluid Byte wrote:Since freak abused his moderator rights and deleted all my post whilst having valid criticism I need to clarify that this code is still f****** pointless. You couldn't name a single example where you would have to back so many previous releases that would force you to use the broken bulit-in OSVersion() function.

It's a weak, or rather non-existent argument to begin with since by that logic you would have to provide EVERY PB-Command ever introduced as an alternative API solution for the case that they MIGHT not work properly in older versions.

Again, you are confusing new and old users alike by providing a solution to a problem that doesn't exist.
banned again,

greets
SPAMINATOR NR.1
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: [Windows] WindowsVersion()

Post by ChrisR »

The major and minor version numbers have remained the same between Windows 10 and Windows 11 (10.0).
It is also the same for Windows Server 2016, 2019 and 2022.
Here is a small addition to differentiate them via the Build number:
See:
Windows 10 release information
Windows 11 release information
Windows Server release information

Code: Select all

; after
; https://msdn.microsoft.com/en-us/library/windows/hardware/ff563620(v=vs.85).aspx
; https://stackoverflow.com/questions/38102565/how-can-a-vb-6-app-determine-if-it-is-running-on-windows-10

; tested with PB 5.31, 5.44 LTS, 5.60

EnableExplicit

Prototype.i protoRtlGetVersion (*ver.OSVERSIONINFOEX)


Procedure.s WindowsVersion()
   Protected ver.OSVERSIONINFOEX
   Protected RtlGetVersion.protoRtlGetVersion
   Protected hDLL.i
   
   ver\dwOSVersionInfoSize = SizeOf(ver)
   
   hDLL = OpenLibrary(#PB_Any, "ntdll.dll")     
   If hDLL   
      RtlGetVersion = GetFunction(hDLL, "RtlGetVersion")
      CloseLibrary(hDLL)       
   EndIf
   
   If RtlGetVersion = 0 Or RtlGetVersion(@ver) <> 0
      ProcedureReturn "Error: Can't call Windows API function RtlGetVersion()."
    EndIf
 
   If ver\dwPlatformId <> #VER_PLATFORM_WIN32_NT
      ProcedureReturn "No Windows NT-based operating system"
   EndIf     
   
   Select ver\dwMajorVersion
      Case 3
         If ver\wProductType = #VER_NT_WORKSTATION
            ProcedureReturn "Windows NT 3.5 Workstation"
         Else
            ProcedureReturn "Windows NT 3.5 Server"
         EndIf
         
      Case 4
         If ver\wProductType = #VER_NT_WORKSTATION
            ProcedureReturn "Windows NT 4.0 Workstation"
         Else
            ProcedureReturn "Windows NT 4.0 Server"
         EndIf
         
      Case 5
         Select ver\dwMinorVersion
            Case 0
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 2000 Workstation"
               Else
                  ProcedureReturn "Windows 2000 Server"
               EndIf
            Case 1
               If (ver\wSuiteMask & #VER_SUITE_PERSONAL)
                  ProcedureReturn "Windows XP Home Edition"
               Else
                  ProcedureReturn "Windows XP Professional"
               EndIf
            Case 2
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows XP 64-bit Edition"
               Else
                  ProcedureReturn "Windows Server 2003"
               EndIf
         EndSelect
         
      Case 6
         Select ver\dwMinorVersion
            Case 0
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows Vista"
               Else
                  ProcedureReturn "Windows Server 2008"
               EndIf
            Case 1
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 7"
               Else
                  ProcedureReturn "Windows Server 2008 R2"
               EndIf
            Case 2
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 8"
               Else
                  ProcedureReturn "Windows Server 2012"
               EndIf
            Case 3
               If ver\wProductType = #VER_NT_WORKSTATION
                  ProcedureReturn "Windows 8.1"
               Else
                  ProcedureReturn "Windows Server 2012 R2"
               EndIf
         EndSelect
         
      Case 10
        If ver\wProductType = #VER_NT_WORKSTATION
          ; https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
          ; https://learn.microsoft.com/en-us/windows/release-health/release-information
          If ver\dwBuildNumber >= 22000
            ProcedureReturn "Windows 11"
          ElseIf ver\dwBuildNumber >= 10240
            ProcedureReturn "Windows 10"
          EndIf
        Else
          ; https://learn.microsoft.com/en-us/windows-server/get-started/windows-server-release-info
          If ver\dwBuildNumber >= 20348
            ProcedureReturn "Windows Server 2022"
          ElseIf ver\dwBuildNumber >= 17763
            ProcedureReturn "Windows Server 2019"
          ElseIf ver\dwBuildNumber >= 14393
            ProcedureReturn "Windows Server 2016"
          EndIf  
        EndIf
   EndSelect
   
   ProcedureReturn "Unknown Windows version"
EndProcedure


Debug WindowsVersion()
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Windows] WindowsVersion()

Post by Little John »

Many thanks, ChrisR :!:
I added a link to the first post of this thread, that points to your extended version.
Post Reply