Mendip Data Systems

Database apps for businesses, schools and developers

LogoTransparent

Code Samples for Businesses, Schools & Developers

 

 

Access / Office 365 / Windows Version Check

Return to Code Samples Page

Version 2.55       Updated 26/11/2021


Attached is a utility for checking the following:
a) Access version & bitness
b) Whether Office 365 is installed
c) Windows version & bitness (32/64-bit)

Several functions are available for obtaining the Access version in varying degrees of detail.
- GetAccessVersion                  e.g. 16.0 (for Access 2016/2019/2021/365)
- GetAccessBuildVersion         e.g. 16.0.14701 (for Access 365)
- GetAccessEXEVersion           e.g. Access 365 - Build 16.0.14701.20226
These are combined with another function IsOfficex64 which returns the value 32-bit or 64-bit

The full Windows version is obtained using a GetWindowsVersion function which returns
e.g.
Windows 10 Pro Version 21H2 - Build 10.0.19044.1348 64-bit

Access&WindowsChecker

Click the image to view a larger version ...

 
Detecting Office 365 is more difficult because the same version numbering is used for both retail & subscription versions of Access. Instead the code checks for a ClickToRun registry key - if it exists, you have Office 365

For example, it looks for this key on pure 32-bit or pure 64-bit systems:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\
Microsoft\Office\16.0\Access Connectivity Engine\Engines


For 32-bit Office on 64-bit Windows, it looks for:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\
Wow6432Node\Microsoft\Office\16.0\Access Connectivity Engine\Engines


However, it gets even more complicated.
If a retail version of Office 2013/2016/2019 is installed but the user enters their Microsoft account information either during installation or at a later time, this triggers the ClickToRun registry structure to be created!

In other words, it is then treated as Office 365 even though it is still a retail product.
However, the software is NOT updated with new features as is the case with a true Office 365 subscription product

CODE:

Three versions are provided (zipped) :      
1. ACCDB for Access 2010 or later:                   AccessVersionChecker2010

2. ACCDB version for Access 2007:                    AccessVersionChecker2007

3. MDB version (Access 2000 format):               AccessVersionChecker2000

Save the selected version to a trusted location or click Enable Content
It will then automatically collect info similar to that in the screenshot.
It may take a few seconds to complete

A PDF Help file can also be downloaded separately: Access/Windows/Office 365 Help



CODE:


Function GetAccessVersion()
   'get Access version number e.g. 14.0 for Access 2010
   GetAccessVersion = SysCmd(acSysCmdAccessVer)
End Function

'=======================================

Function GetAccessBuildVersion() As String
   'Gets full Access version number including program updates / service packs
   'e.g. 14.6024 for Access 2010 SP1
   GetAccessBuildVersion = Nz(SysCmd(acSysCmdAccessVer) & "." & SysCmd(715), "None") & " " & IsOfficex64
   'Debug.Print GetAccessBuildVersion
End Function

'=======================================

Function GetAccessEXEVersion() As String
   'Valid for use with Access 2000 or later.
   'Original version may have been by Tom van Stiphout

   On Error Resume Next
   Dim sAccessVerNo As String

   sAccessVerNo = SysCmd(acSysCmdAccessVer) & "." & SysCmd(715)

   Select Case sAccessVerNo
       'Access 2000
       Case "9.0.0.0000" To "9.0.0.2999": GetAccessEXEVersion = "Access 2000 " & sAccessVerNo & ""
       Case "9.0.0.3000" To "9.0.0.3999": GetAccessEXEVersion = "Access 2000 SP1 " & sAccessVerNo & ""
       Case "9.0.0.4000" To "9.0.0.4999": GetAccessEXEVersion = "Access 2000 SP2 " & sAccessVerNo & ""
       Case "9.0.0.6000" To "9.0.0.6999": GetAccessEXEVersion = "Access 2000 SP3 " & sAccessVerNo & ""

       'Access 2002
       Case "10.0.2000.0" To "10.0.2999.9": GetAccessEXEVersion = "Access 2002 " & sAccessVerNo & ""
       Case "10.0.3000.0" To "10.0.3999.9": GetAccessEXEVersion = "Access 2002 SP1 " & sAccessVerNo & ""
       Case "10.0.4000.0" To "10.0.4999.9": GetAccessEXEVersion = "Access 2002 SP2 " & sAccessVerNo & ""

       'Access 2003
       Case "11.0.0000.0" To "11.0.5999.9999": GetAccessEXEVersion = "Access 2003 " & sAccessVerNo & ""
       Case "11.0.6000.0" To "11.0.6999.9999": GetAccessEXEVersion = "Access 2003 SP1 " & sAccessVerNo & ""
       Case "11.0.7000.0" To "11.0.7999.9999": GetAccessEXEVersion = "Access 2003 SP2 " & sAccessVerNo & ""
       Case "11.0.8000.0" To "11.0.8999.9999": GetAccessEXEVersion = "Access 2003 SP3 " & sAccessVerNo & ""

       'Access 2007
       Case "12.0.0000.0" To "12.0.5999.9999": GetAccessEXEVersion = "Access 2007 " & sAccessVerNo & ""
       Case "12.0.6211.0" To "12.0.6422.9999": GetAccessEXEVersion = "Access 2007 SP1 " & sAccessVerNo & ""
       Case "12.0.6423.0" To "12.0.9999.9999": GetAccessEXEVersion = "Access 2007 SP2 " & sAccessVerNo & ""

       'Access 2010
       Case "14.0.0000.0000" To "14.0.6022.1000": GetAccessEXEVersion = "Access 2010 " & sAccessVerNo & ""
       Case "14.0.6023.1000" To "14.0.7014.9999": GetAccessEXEVersion = "Access 2010 SP1 " & sAccessVerNo & ""
       Case "14.0.7015.1000" To "14.0.9999.9999": GetAccessEXEVersion = "Access 2010 SP2 " & sAccessVerNo & ""

       'Access 2013
       Case "15.0.0000.0000" To "15.0.4569.1505": GetAccessEXEVersion = "Access 2013 " & sAccessVerNo & ""
       Case "15.0.4569.1506" To "15.0.9999.9999": GetAccessEXEVersion = "Access 2013 SP1 " & sAccessVerNo & ""

      'Access 2016/2019/2021 - updated v2.55
      'The following is based on info from Microsoft - but it only applies to volume licenses
      'A2016 up to build 16.0.5224.1000
      'A2019 from 16.0.10374.20040 - 16.0.10379.20043
      'A2021 from 16.0.14332.20145 onwards
      'A365 can be any of these (if not updated but likely to be the latest version!

        Case "16.0.0000" To "16.0.99999"
             'for consumer versions, the same code base is used ... so write as
              GetAccessEXEVersion = "2016/2019/2021 " & " - Build " & sAccessVerNo & ""
        Case Else
              GetAccessEXEVersion = " - Unknown Version"
        End Select

        If CheckAccess365 Then GetAccessEXEVersion = "365 - Build " & sAccessVerNo & ""

        If SysCmd(acSysCmdRuntime) Then GetAccessEXEVersion = GetAccessEXEVersion & " Run-time"

        GetAccessEXEVersion = GetAccessEXEVersion & " " & IsOfficex64

        GetAccessEXEVersion = "Access " & GetAccessEXEVersion

       End Function

'=======================================

Function IsOfficex64()
  'checks if Office is 32 or 64 bit

 #If Win64 Then
    IsOfficex64 = "64-bit"
 #Else
    IsOfficex64 = "32-bit"
 #End If

End Function

To obtain the Windows version and bitness, the following code is used:

CODE:


Public Function GetWindowsVersion() As String

On Error GoTo Err_Handler

'Get full Windows info including build & bitness
'e.g. Windows 10 Pro Version 21H1 - Build 10.0.19043.1288 64-bit

Dim oShell As Object, sRegKey As String, strWinVer As String

Set oShell = CreateObject("WScript.Shell")

registryKey = "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
KeyName = "ProductName"
strWinVer = GetStringValFromRegistry(HKEY_LOCAL_MACHINE, registryKey, KeyName)

sRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DisplayVersion" 'e.g. 21H1
strWinVer = strWinVer & " Version " & oShell.RegRead(sRegKey)

sRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMajorVersionNumber" 'e.g. 10
strWinVer = strWinVer & " - Build " & oShell.RegRead(sRegKey)

sRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMinorVersionNumber" 'e.g 0
strWinVer = strWinVer & "." & oShell.RegRead(sRegKey)

sRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentBuild" 'e.g. 19043
strWinVer = strWinVer & "." & oShell.RegRead(sRegKey)

sRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UBR" 'e.g. 1288
strWinVer = strWinVer & "." & oShell.RegRead(sRegKey)

'Determine if operating system is 32-bit or 64-bit
'-------------------------------------------------
GetWindowsVersion = strWinVer & " " & IsWin32OrWin64

Exit_Handler:
       Set oShell = Nothing
       Exit Function

Err_Handler:
       MsgBox "Error " & Err & " " & Err.Description & " in GetWindowsVersion function", vbExclamation, "ERROR"
       Resume Exit_Handler

End Function

'=======================================

Function IsWin32OrWin64()

  'Determine if operating system is 32-bit or 64-bit
   '-------------------------------------------------
   'Modified from code provided at:
   '  http://www.vb-helper.com/howto_get_os_name.html
   Dim proc_query As String
   Dim proc_results As Object
   Dim Info As Object

   proc_query = "SELECT * FROM Win32_Processor"
   Set proc_results = GetObject("Winmgmts:").ExecQuery(proc_query)
   For Each Info In proc_results
       IsWin32OrWin64 = Info.AddressWidth & "-bit"
   Next Info

   'Debug.Print IsWin32OrWin64

 End Function


 Function CheckAccess365() As Boolean

 On Error GoTo Err_Handler

   'If Access version <16.0 then NOT A365
   'However in case of dual Office installation, this step will be bypassed
 '  If CInt(GetAccessVersion) < 16 Then
 '      CheckAccess365 = False
 '       Debug.Print "Access 365 : " & CheckAccess365
 '        Exit Function
 '  End If

   'Check Windows bitness
   If IsWin32OrWin64 = "32-bit" Then
           registryKey = "SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Office\16.0\Access Connectivity Engine\Engines"
   Else '64-bit Windows
       'check Office bitness
       If IsOfficex64 = "32-bit" Then
          'check in Wow6432Node
           registryKey = "SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Wow6432Node\Microsoft\Office\16.0\Access Connectivity Engine\Engines"
       Else '64-bit Office
           registryKey = "SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Office\16.0\Access Connectivity Engine\Engines"
       End If
   End If

   KeyName = "SystemDB" 'look for specific string value

   ' check string value exists in registry
    If GetStringValFromRegistry(HKEY_LOCAL_MACHINE, registryKey, KeyName) <> "" Then
           CheckAccess365 = True
   End If

  ' Debug.Print "Access 365 : " & CheckAccess365

 Exit_Handler:
      Exit Function

 Err_Handler:
     MsgBox "Error " & Err.Number & " in CheckAccess365 procedure: " & Err.Description
     Resume Exit_Handler

 End Function

NOTE:

I have successfully tested the Office 365 code on several PCs including:
- Windows/Access both 32-bit
- Windows/Access both 64-bit
- 64-bit Windows & 32-bit Access
- dual installation of Access 2010 & Access 365

Many thanks to several other users who kindly tested this code on their own computer systems.
Particular thanks are due to Utter Access forum member Jeff Holm for repeatedly testing different versions in 'mixed bitness' systems and for helping to solve issues related to reading the Wow6432Node registry area

Despite the extensive testing already done, it is possible that some Office 365 users may have different registry keys to those being referenced. If so, the code will NOT detect Office 365

I would be grateful for feedback from any Office 365 users who find that the check does not work correctly
If that is the case, please email me with the following information:

a) Access/Windows versions & bitnesses
b) the full registry key path in HKEY_LOCAL_MACHINE containing the ClickToRun key for the Access Connectivity       Engines\Engines folder


 Public Function GetStdRegProv() As Object

  'http://msdn.microsoft.com/en-us/library/aa394600(VS.85).aspx
  'code updated by Jeff Holm to manage mixed mode systems

 On Error GoTo ErrHandler:

   Dim strComputer As String

   strComputer = "."

   If IsWin32OrWin64 = IsOfficex64 Then
       
'Office & Windows bitness match, no need to force 64-bit
       Set GetStdRegProv = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
   Else
       'Office 32-bit & Windows 64-bit, so have to elevate GetStdRegProv to 64-bit
       Dim objCtx As Object
       Dim objLocator As Object
       Dim objServices As Object
       Dim objStdRegProv As Object

       Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
       objCtx.Add "__ProviderArchitecture", 64
       objCtx.Add "__RequiredArchitecture", True
       Set objLocator = CreateObject("Wbemscripting.SWbemLocator")
       Set objServices = objLocator.ConnectServer(strComputer, "root\default", "", "", , , , objCtx)
       Set GetStdRegProv = objServices.Get("StdRegProv")

       Set objServices = Nothing
       Set objLocator = Nothing
       Set objCtx = Nothing
   End If

 Exit_ErrHandler:
   On Error Resume Next
   Exit Function

 ErrHandler:
   If Err.Number >= 0 Then
       MsgBox "Error " & Err.Number & " in GetStdRegProv procedure: " & Err.description, vbOKOnly + vbCritical
   End If

   Resume Exit_ErrHandler

 End Function

When using 32-bit applications in 64-bit Windows, registry entries are made to the Wow6432Node.
Windows uses a process called registry redirection to manage this area.
However, that causes issues when trying to view those entries from a 32-bit version of Access.

This area cannot be read from or written to using standard code as used on 'pure' 32-bit or 64-bit systems.
Instead, I have used 'special' code which is elevated to 64-bit as and when required

CODE:

Our JET ShowPlan Manager application also includes the functions used in this utility.

 

Its purpose is to manage the registry settings needed to enable the JET ShowPlan feature and view the execution plans of Access queries and SQL statements.

Version History

13/12/2019 - Version 2.2 - Initial release
06/03/2019 - Version 2.3 - Minor correction to API in modSysInfo - no new functionality
24/02/2021 - Version 2.4 - Updated for Access 2021
26/11/2021 - Version 2.55 - Updated version info for A365/2016/2019/2021