Visual Basic Helper Routines
IsOs: Windows OS and OS Features Info
     
Posted:   Wednesday August 20, 2008
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP, Windows Vista
OS restrictions:   None
Author:   VBnet - Randy Birch
     

Related:  
 

GetVersionEx: Windows Version Info (Wrapper Routines)
GetVersionEx: Windows Version, Service Pack and Platform Info
GetFileVersionInfo: Handy Routines for Identifying Shell32 Versions
GetSystemInfo: System Processor Information

NetServerGetInfo: Configuration Info for Domain/Workgroup Servers and Machines
     
 Prerequisites
None.

No, this isn't deja vous.

Although the demo form image appears similar to that used in GetVersionEx: Windows Version Info (Wrapper Routines), it is in fact a demo based on an entirely different API.

Since Windows 95, shlwapi.dll has exposed ordinal 437 which in Vista was finally given a real API name - IsOs.  This function takes a constant representing various flavours of Windows, or specific Windows features, and returns non-zero if the passed value represents a supported/active feature, or zero if it doesn't.

If you closely look at the labels in the illustration you'll see quite a few differ from the information returned using the GetVersionEx code. Perhaps most interesting is a value that will indicate whether the OS has its settings biased for server administration, whether fast user switching is enabled -- some apps don't behave nicely if a user can leave it running while switching users, and whether the current app is running under a Terminal Server session rather than on a real desktop.

The load event sets up the form controls - all that's needed is a command button, and a label and text box with their index property set to 0 to create control arrays. The command event calls a wrapper around IsOs or ordinal #437 passing the listing of available values representing the operating system or operating system feature to check for.

Although the MSDN states IsOs is available by name starting with Windows XP, I have discovered that my XP boxes only support the ordinal API; the named API returns 'not found'.  Vista supports the named API, as does, according to MSDN, Windows Server 2003.  You can confirm this for me.

The MSDN shows a specific linage to operating systems that this API follows.  As developers we already know the linage, but to ensure understanding, its:

Win32s-> Windows 95-> Windows 95 OSR2-> Windows 98-> Windows 98 SE-> Windows Me->
Windows NT 3.1-> Windows NT 4-> Windows 2000-> Windows XP-> Windows Vista-> Windows Server 2003

In the code comments, when a dwOS value specifies, for example, "Windows NT 4.0 or one of its successors", this means Windows NT 4.0, Windows 2000, Windows XP, Windows Vista, or Windows Server 2003. For the purpose of determining lineage for this function, Windows XP Tablet PC Edition and Windows XP Media Center Edition are considered Windows XP. When referring to server products, "Windows Server" refers only to the Standard Edition server. If all server products are covered by a particular flag, it is called out explicitly in the description under the constant.

Note that OS_VISTA is not defined by Microsoft for this API, but my testing has revealed that passing 37 to IsOs returns 1 if the operating system is Vista. I have therefore added that constant to the list, and again users can let me know if it fails on other Vista boxes, or returns a value on non-Vista machines.

Finally, a word about Vista and calling this API. To me a good coder uses a named API over an ordinal API whenever possible to mitigate confusion. But when dealing with an API that is defined only as an ordinal pre-Vista (or pre-XP if you believe the MSDN), then something is needed to ensure only the named version is called under supporting OS versions. My solution was to create a wrapper routine (IsThisOsVista), and call it whenever the wrapper IsThisOs() routine was called.  If IsThisOsVista returned True, IsThisOs would call the named API, otherwise the routine would call the aliased ordinal instead.  Another means of achieving this same thing would be to use GetVersionEx in a IsWinVista() wrapper from the referenced code page above; I have included this code below although the calling line is commented out. Also, to make the label strings fit the window I've abbreviated a few terms. The full terms are in the definitions under each constant.

Revision History

August 20.2008     Code first posted.

 BAS Module Code
None.

 Form Code
On a form, add a command button, a textbox (Text1) and a label (Label1). Set the Index property of both the text box and label to 0 to establish each as a control array. The load event takes care of creating and positioning the required controls and resizing the form (as coded the positioning works for for a small-font system; some adjustment may be needed for non-standard display attributes).

Add the following code to the form:


Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const OS_NT As Long = 1
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows NT or later.
 
Private Const OS_WIN95ORGREATER As Long = 2
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 95 or later.
 
Private Const OS_NT4ORGREATER As Long = 3
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows NT 4.0 or later.
 
'obsolete: Private Const OS_WIN2000ORGREATER_ALT As Long = 4
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 2000 or later.
'Obsolete: Use private const OS_WIN2000ORGREATER instead.
 
Private Const OS_WIN98ORGREATER As Long = 5
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 98 or later.
 
Private Const OS_WIN98_GOLD As Long = 6
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 98 exactly.
 
Private Const OS_WIN2000ORGREATER As Long = 7
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 2000 or later.
 
Private Const OS_WIN2000PRO As Long = 8
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 2000 Professional or Windows XP Professional.
 
Private Const OS_WIN2000SERVER As Long = 9
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 2000 Server (Standard) or Windows
'Server 2003 Standard.
 
Private Const OS_WIN2000ADVSERVER As Long = 10
'Windows 2000/Windows XP/Windows Server 2003
'The program running on Windows 2000 Advanced Server or
''Windows Server 2003 Enterprise.
 
Private Const OS_WIN2000DATACENTER As Long = 11
'Windows 2000/Windows XP/Windows Server 2003
'The program running on Windows 2000 Datacenter Server or
'Windows Server 2003 Datacenter.
 
Private Const OS_WIN2000TERMINAL As Long = 12
'Windows 2000/Windows XP/Windows Server 2003
'The program running on Windows 2000 TS in either
'Remote Administration mode or Application Server mode, or
'Windows Server 2003 (or later) in Terminal
'Server mode or Remote Desktop for Administration mode.
 
Private Const OS_EMBEDDED As Long = 13
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows Embedded, any version.
 
Private Const OS_TERMINALCLIENT As Long = 14
'Windows 2000/Windows XP/Windows Server 2003
'The program running as a TS client.
'Equivalent to GetSystemMetrics(SM_REMOTESESSION).

Private Const OS_TERMINALREMOTEADMIN As Long = 15
'Windows 2000/Windows XP/Windows Server 2003
'The program running Windows 2000 TS in Remote
'Administration mode or Windows Server 2003 (or later)
'in Remote Desktop for Administration mode.

Private Const OS_WIN95_GOLD As Long = 16
'Windows 2000/Windows XP/Windows Server 2003
'Windows 95 exactly.

Private Const OS_MEORGREATER As Long = 17
'Windows XP/Windows Server 2003
'The program running Windows Millennium
'(Windows Me) or later.

Private Const OS_XPORGREATER As Long = 18
'Windows XP/Windows Server 2003
'The program running Windows XP or later.

Private Const OS_HOME As Long = 19
'Windows XP/Windows Server 2003
'The program running on the Home of Windows XP
'or later.

Private Const OS_PROFESSIONAL As Long = 20
'Windows XP/Windows Server 2003
'The program running Windows NT Workstation or Windows 2000
'(or later) Professional.

Private Const OS_DATACENTER As Long = 21
'Windows XP/Windows Server 2003
'The program running Windows Datacenter Server or
'Windows Server Datacenter,
'any version.

Private Const OS_ADVSERVER As Long = 22
'Windows XP/Windows Server 2003
'The program running Windows Advanced Server or
'Windows Server Enterprise,
'any version.

Private Const OS_SERVER As Long = 23
'Windows XP/Windows Server 2003
'The program running Windows Server (Standard) or
'Windows Server Standard,
'any version.

Private Const OS_TERMINALSERVER As Long = 24
'Windows XP/Windows Server 2003
'The program running Windows 2000 TS
'in Application Server mode, or Windows Server 2003
'(or later) in TS mode.
 
Private Const OS_PERSONALTERMINALSERVER As Long = 25
'Windows XP/Windows Server 2003
'The program running Windows XP (or later),
'Home or Professional.
 
Private Const OS_FASTUSERSWITCHING As Long = 26
'Windows XP/Windows Server 2003
'Fast user switching enabled.
 
Private Const OS_WELCOMELOGONUI As Long = 27
'Windows XP/Windows Server 2003
'The Welcome screen used for logon.
 
Private Const OS_DOMAINMEMBER As Long = 28
'Windows XP/Windows Server 2003
'The computer joined to a domain.
 
Private Const OS_ANYSERVER As Long = 29
'Windows XP/Windows Server 2003
'The program running on any Windows Server product.
 
Private Const OS_WOW6432 As Long = 30
'Windows XP/Windows Server 2003
'The program a 32-bit program running on Microsoft Win64.
 
Private Const OS_WEBSERVER As Long = 31
'Windows XP Service Pack 2 (SP2)/Windows Server2 003 Service Pack 1 (SP1)
'The program running Windows Server 2003, Web, or later.
 
Private Const OS_SMALLBUSINESSSERVER As Long = 32
'Windows XP SP2/Windows Server 2003 SP1
'The program running on Microsoft Small Business Server with
'restrictive client license in force.
 
Private Const OS_TABLETPC As Long = 33
'Windows XP SP1/Windows Server 2003
'The program running Windows XP Tablet PC, or later.
'Equivalent to GetSystemMetrics(SM_TABLETPC).
 
Private Const OS_SERVERADMINUI As Long = 34
'Windows XP SP2/Windows Server 2003
'The program should bias its defaults towards those
'suitable for server administrators.

Private Const OS_MEDIACENTER As Long = 35
'Windows XP SP1/Windows Server 2003
'The program running Windows XP Media Center,
'or later. Equivalent to
'GetSystemMetrics(SM_MEDIACENTER).
 
Private Const OS_APPLIANCE As Long = 36
'Windows XP SP2/Windows Server 2003 SP1
'The program running Windows Appliance Server.

Private Const OS_VISTA As Long = 37
'Windows Vista
'The program running Windows Vista. (My constant)


Private Declare Function IsOS Lib "shlwapi.dll" _
   (ByVal dwOS As Long) As Long

Private Declare Function IsOSAsOrdinal Lib "shlwapi.dll" _
   Alias "#437" _
  (ByVal dwOS As Long) As Long

'additional code required if IsWinVista() used instead of IsThisOsVista()
Private Const VER_PLATFORM_WIN32_NT As Long = 2

Private Type OSVERSIONINFO
  OSVSize            As Long
  dwVerMajor        As Long
  dwVerMinor         As Long
  dwBuildNumber      As Long
  PlatformID         As Long
  szCSDVersion       As String * 128
End Type

Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" _
  (lpVersionInformation As Any) As Long


Private Sub Form_Load()

   Dim cnt As Long
   Dim nControls As Long
   Dim nRows As Long
   Dim nCols As Long
   Dim nMaxCtrlsPerCol As Long
   Dim hOffset As Single
   Dim vOffset As Single
   
   nControls = 36  '0-based
   nRows = 2
   nCols = 2
   nMaxCtrlsPerCol = nControls \ 2
   
   For cnt = 0 To nControls - 1
   
     'control(0) already exists; don't try to load it!
      If cnt > 0 Then
         Load Label1(cnt)
         Load Text1(cnt)
      End If
      
     'position and show
     If cnt < nMaxCtrlsPerCol Then
         hOffset = 1
         vOffset = cnt
     Else
        hOffset = 2.4
        vOffset = (cnt - nMaxCtrlsPerCol)
     End If
         
      With Text1(cnt)
         .Move (3300 * hOffset), 200 + (vOffset * 300), 1300, 285
         .Visible = True
      End With
      
      With Label1(cnt)
         .Alignment = vbRightJustify
         .AutoSize = True
         .Move Text1(cnt).Left - 200, (230 + (vOffset * 300)), 0, 195
         .Visible = True
      End With
              
   Next
   
   Command1.Move Text1(0).Left, _
                 Text1(nControls - 1).Top + _
                 Text1(nControls - 1).Height + 230, _
                 Text1(0).Width
                 
   Command1.TabIndex = 0
   
   Me.Move Me.Left, Me.Top, _
          (Text1(nControls - 1).Left + Text1(nControls - 1).Width + 1000), _
          (Command1.Top + Command1.Height + 800)

End Sub


Private Sub Command1_Click()

Dim cnt As Long

   Label1(0).Caption = "Win95 exactly?"
   Label1(1).Caption = "Win95 or later?"
   
   Label1(2).Caption = "Win98 exactly?"
   Label1(3).Caption = "Win98 or later?"
   
   Label1(4).Caption = "WinME or later?"
   
   Label1(5).Caption = "Win XP or successor?" 
   Label1(6).Caption = "Win XP Home or successor?" 
   Label1(7).Caption = "Win XP Pro or successor?"
   Label1(8).Caption = "Win XP Home or Pro, or successor?"
   Label1(9).Caption = "Win XP Media Center or successor?"
   Label1(10).Caption = "Win XP Tablet PC or successor?"
   
   Label1(11).Caption = "Win Vista?"
   Label1(12).Caption = "Windows Embedded, any version?"
   
   Label1(13).Caption = "Windows Server Standard, any version?"
   Label1(14).Caption = "Any Windows Server product?"
   
   Label1(15).Caption = "WinNT or any successor?"
   Label1(16).Caption = "WinNT 4.0 or any successor?"
   
   Label1(17).Caption = "Win2000 or successor?"
   Label1(18).Caption = "Win2000 Pro or XP Pro?"
   Label1(19).Caption = "Win2000 TS/2003 TS/Remote Desktop?" 
   Label1(20).Caption = "Win2000 TS/2003 or later in TS mode?" 
   Label1(21).Caption = "Win2000 TS in RA/2003 in RDA mode?"
   
   Label1(22).Caption = "Windows Server Datacenter?"
   Label1(23).Caption = "Windows Server 2000 or 2003 Standard?" 
   Label1(24).Caption = "Windows Server 2000 Adv or 2003 E'prise?" 
   Label1(25).Caption = "Windows Server 2000 or 2003 Datacenter?" 
   Label1(26).Caption = "Windows Server 2003, Web, or later?" 
   Label1(27).Caption = "Windows SBS w/restrictive client license?" 
   Label1(28).Caption = "Win Advanced Server or Server Enterprise?" 
   
   Label1(29).Caption = "Bias defaults for server administrators" 
   Label1(30).Caption = "Fast User Switching enabled?" 
   Label1(31).Caption = "Welcome screen used for logon?"  
   Label1(32).Caption = "Win Appliance Server?" 
   Label1(33).Caption = "Computer joined to a domain?" 
   Label1(34).Caption = "Program running as a TS client?" 
   Label1(35).Caption = "32-bit app on Win64"

   Text1(0).Text = IsThisOs(OS_WIN95_GOLD)
   Text1(1).Text = IsThisOs(OS_WIN95ORGREATER)
   
   Text1(2).Text = IsThisOs(OS_WIN98_GOLD)
   Text1(3).Text = IsThisOs(OS_WIN98ORGREATER)
   
   Text1(4).Text = IsThisOs(OS_MEORGREATER)
   
   Text1(5).Text = IsThisOs(OS_XPORGREATER)
   Text1(6).Text = IsThisOs(OS_HOME)
   Text1(7).Text = IsThisOs(OS_PROFESSIONAL)
   Text1(8).Text = IsThisOs(OS_PERSONALTERMINALSERVER)
   Text1(9).Text = IsThisOs(OS_MEDIACENTER)
   Text1(10).Text = IsThisOs(OS_TABLETPC)
   
   Text1(11).Text = IsThisOs(OS_VISTA)
   Text1(12).Text = IsThisOs(OS_EMBEDDED)
   
   Text1(13).Text = IsThisOs(OS_SERVER)
   Text1(14).Text = IsThisOs(OS_ANYSERVER)
   
   Text1(15).Text = IsThisOs(OS_NT)
   Text1(16).Text = IsThisOs(OS_NT4ORGREATER)
   
   Text1(17).Text = IsThisOs(OS_WIN2000ORGREATER)
   Text1(18).Text = IsThisOs(OS_WIN2000PRO)
   Text1(19).Text = IsThisOs(OS_WIN2000TERMINAL)
   Text1(20).Text = IsThisOs(OS_TERMINALSERVER)
   Text1(21).Text = IsThisOs(OS_TERMINALREMOTEADMIN)
   
   Text1(22).Text = IsThisOs(OS_DATACENTER)
   Text1(23).Text = IsThisOs(OS_WIN2000SERVER)
   Text1(24).Text = IsThisOs(OS_WIN2000ADVSERVER)
   Text1(25).Text = IsThisOs(OS_WIN2000DATACENTER)
   Text1(26).Text = IsThisOs(OS_WEBSERVER)
   Text1(27).Text = IsThisOs(OS_SMALLBUSINESSSERVER)
   Text1(28).Text = IsThisOs(OS_ADVSERVER)
   
   Text1(29).Text = IsThisOs(OS_SERVERADMINUI)
   Text1(30).Text = IsThisOs(OS_FASTUSERSWITCHING)
   Text1(31).Text = IsThisOs(OS_WELCOMELOGONUI)
   Text1(32).Text = IsThisOs(OS_APPLIANCE)
   Text1(33).Text = IsThisOs(OS_DOMAINMEMBER)
   Text1(34).Text = IsThisOs(OS_TERMINALCLIENT)
   Text1(35).Text = IsThisOs(OS_WOW6432)

   For cnt = Text1.LBound To Text1.UBound
      If Text1(cnt).Text = "True" Then
         Text1(cnt).BackColor = vbYellow
         Label1(cnt).Font.Bold = True
      End If
   Next
End Sub


Private Function IsThisOs(dwOS As Long) As Boolean

  'Because the API is defined by name (IsOs) only in Vista
  'and later, we have to at least use GetVersionEx
  'to find out if the named or ordinal version of the
  'API needs to be called based on the OS the code
  'is being run on.
  
  'There are at least two ways of doing this:
  '1) attempt calling the ordinal API passing OS_VISTA;
  '   the ordinal-named API called on Vista works for
  '   backwards compatibility with earlier apps, or
  '2) call GetVersionEx using the IsWinVista wrapper function.
  '
  'Code for both methods are included in this demo; the
  'commented out line below would call the second method.
  '
  'If IsWinVista() Then
   If IsThisOsVista() Then
      IsThisOs = IsOS(dwOS)
   Else
      IsThisOs = IsOSAsOrdinal(dwOS)
   End If

End Function


Private Function IsThisOsVista() As Boolean

  'returns True if running Windows Vista
   IsThisOsVista = IsOSAsOrdinal(OS_VISTA)

End Function


Private Function IsWinVista() As Boolean

  'returns True if running Windows Vista
   Dim osv As OSVERSIONINFO

   osv.OSVSize = Len(osv)

   If GetVersionEx(osv) = 1 Then
   
      IsWinVista = (osv.PlatformID = VER_PLATFORM_WIN32_NT) And _
                   (osv.dwVerMajor = 6)

   End If
   
End Function
 Comments
Running the project will populate the appropriate text boxes with True, indicating the current platform tests.

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

 

Hit Counter