It can be useful at times to determine the bitness (32, 64, who knows what will be next!) of the installed Operating System (OS). This can be useful for your error reporting for instance.
Is the OS 64-bit or Not?
Below are a couple approaches to that allow us to determine, with relative ease, whether we are dealing with a 64-bit system or not. In most cases, this is what is of importance to us.
Testing for an Environment Variable
This approach, we simple test for the existence of the %ProgramW6432% environment variable. If it exist then we are dealing with a 64-bit system.
'---------------------------------------------------------------------------------------
' Procedure : Environ_IsOS64Bit
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine if the OS is 64-bit, or not
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Usage:
' ~~~~~~
' ? Environ_IsOS64Bit
' Returns -> True :: Is 64-bit OS
' False :: Is not 64-bit OS
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2018-08-30 Initial Release
'---------------------------------------------------------------------------------------
Function Environ_IsOS64Bit() As Boolean
'https://docs.microsoft.com/en-us/windows/desktop/winprog64/wow64-implementation-details
' If Environ("ProgramW6432") Exist Then x64 - 64-bit
' If Environ("ProgramW6432") Does Not Exist Then x86 - 32-bit
Environ_IsOS64Bit = Len(Environ("ProgramW6432")) > 0
End Function
Validating Folder/Directory Existence
We could also create a procedure that would check for %ProgramFiles(x86)% and/or the ‘C:\Windows\syswow64’ folder (s) existence, if they exits then it is a 64-bit system.
'---------------------------------------------------------------------------------------
' Procedure : Folder_IsOS64Bit
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine if the OS is 64-bit, or not
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
' References: GA_FolderExist()
' https://www.devhut.net/vba%E2%80%93determine-folder-directory-exists/
'
' Usage:
' ~~~~~~
' Folder_IsOS64Bit
' Returns -> True :: Is 64-bit OS
' False :: Is not 64-bit OS
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-02-11 Initial Public Release
'---------------------------------------------------------------------------------------
Function Folder_IsOS64Bit() As Boolean
If GA_FolderExist(Environ("WinDir") & "\syswow64") _
And GA_FolderExist(Environ("SystemDrive") & "\Program Files (x86)") Then
Folder_IsOS64Bit = True
End If
End Function
be sure to get a copy of the GA_FolderExist() from my VBA – Determine if a Folder/Directory Exists or Not article.
WScript
Another option available to us would be to employ WScript.Shell.
'---------------------------------------------------------------------------------------
' Procedure : WSS_IsOS64Bit
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine if the OS is 64-bit, or not
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Usage:
' ~~~~~~
' ? WSS_IsOS64Bit
' Returns -> True :: Is 64-bit OS
' False :: Is not 64-bit OS
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-02-11 Initial Public Release
'---------------------------------------------------------------------------------------
Function WSS_IsOS64Bit() As Boolean
If InStr(CreateObject("WScript.Shell").Environment("System") _
.Item("Processor_Architecture"), "64") > 0 Then
WSS_IsOS64Bit = True
End If
End Function
PowerShell
If you wish, we could use PowerShell to do the job by doing:
'---------------------------------------------------------------------------------------
' Procedure : PS_IsOS64Bit
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine whether the OS is 64-bit, or not.
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Late Binding -> none required
' References: PS_GetOutput()
' https://www.devhut.net/vba-run-powershell-command/
'
' Usage:
' ~~~~~~
' ? PS_IsOS64Bit()
' Returns -> True :: Is 64-bit OS
' False :: Is not 64-bit OS
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-02-11 Initial Public Release
'---------------------------------------------------------------------------------------
Function PS_IsOS64Bit() As Boolean
Dim sRetVal As String
sRetVal = PS_GetOutput("& {[Environment]::Is64BitOperatingSystem;}")
'RetVal = PS_GetOutput("[Environment]::Is64BitOperatingSystem")
PS_IsOS64Bit = (InStr(sRetVal, "TRUE") > 0)
End Function
and you can grab a copy of the PS_GetOutput() from VBA – Run PowerShell Command article.
Using APIs
Note, I have not had time to perform extensive testing of the APIs.
GetNativeSystemInfo API
This approach was brought to my attention by Xavier Batlle and originates from How to detect if the computer is 32-bit or 64-bit?.
Type SYSTEM_INFO
wProcessorArchitecture As Integer 'The processor architecture of the installed operating system.
wReserved As Integer
dwPageSize As Long
lpMinimumApplicationAddress As Long
lpMaximumApplicationAddress As Long
dwActiveProcessorMask As Long
dwNumberOrfProcessors As Long
dwProcessorType As Long
dwAllocationGranularity As Long
wProcessorLevel As Integer
wProcessorRevision As Integer
End Type
Private Declare Sub GetNativeSystemInfo Lib "kernel32" (lpSystemInfo As SYSTEM_INFO)
Public Function Is64BitProcessor() As Boolean
Const PROCESSOR_ARCHITECTURE_AMD64 As Integer = 9 'x64 (AMD or Intel)
Const PROCESSOR_ARCHITECTURE_IA64 As Integer = 6 'Intel Itanium Processor Family (IPF)
' Const PROCESSOR_ARCHITECTURE_INTEL As Long = 0 'x86
' Const PROCESSOR_ARCHITECTURE_UNKNOWN As Long = &HFFFF& 'Unknown architecture
' Const PROCESSOR_INTEL_386 As Long = 386
' Const PROCESSOR_INTEL_486 As Long = 486
' Const PROCESSOR_INTEL_PENTIUM As Long = 586
' Const PROCESSOR_INTEL_IA64 As Long = 2200
' Const PROCESSOR_AMD_X8664 As Long = 8664
Dim si As SYSTEM_INFO
' call the API
GetNativeSystemInfo si
' check the struct
Is64BitProcessor = (si.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64 _
Or _
si.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64)
End Function
IsWow64ProcessAPI
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long '()
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function IsWow64Process Lib "kernel32" (ByVal hProcess As Long, ByRef Wow64Process As Long) As Long
Function Wow64_IsOS64Bit() As Boolean
Dim lHwnd As Long
Dim lRetVal As Long
lHwnd = GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process")
If lHwnd > 0 Then
IsWow64Process GetCurrentProcess(), lRetVal
End If
If lRetVal <> 0 Then
Wow64_IsOS64Bit = True
End If
End Function
Using the WMI Win32_OperatingSystem Class
WMI is a wonderful tool! It has so many classes that cover pretty much every aspect of a computer and luckily for me that includes the Operation System using the Win32_OperatingSystem class.
'---------------------------------------------------------------------------------------
' Procedure : WMI_IsOS64Bit
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine if the OS is 64-bit, or not
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sHost : Name/IP Address of the PC to query assuming you have the rights to do so
' optional, so by leaving it blank it will query the local computer
'
' Usage:
' ~~~~~~
' ? WMI_IsOS64Bit
' Returns -> True :: Is 64-bit OS
' False :: Is not 64-bit OS
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2018-08-30 Initial Release
'---------------------------------------------------------------------------------------
Function WMI_IsOS64Bit(Optional sHost As String = ".") As Boolean
'Win32_OperatingSystem -> https://msdn.microsoft.com/en-us/library/aa394239%28v=vs.85%29.aspx
On Error GoTo Error_Handler
Dim oWMI As Object 'WMI object to query about the PC's OS
Dim oOSs As Object 'Collection of OSs
Dim oOS As Object 'Individual OS
Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sHost & "\root\cimv2")
Set oOSs = oWMI.ExecQuery("SELECT OSArchitecture FROM Win32_OperatingSystem")
For Each oOS In oOSs 'Enumerate each OS provided by WMI
If oOS.OSArchitecture = "64-bit" Then WMI_IsOS64Bit = True
Next
Error_Handler_Exit:
On Error Resume Next
If Not oOS Is Nothing Then Set oOS = Nothing
If Not oOSs Is Nothing Then Set oOSs = Nothing
If Not oWMI Is Nothing Then Set oWMI = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: WMI_IsOS64Bit" & vbCrLf & _
"Error Description: " & Err.Description, _
vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
Get OS Bitness Details
Since we’re on the subject, it can be useful to get the actual textual bitness string (32-bit, 64-bit). This can be done quite easily by modifying either of the above, so here is one example in case it can help some of you out there.
'---------------------------------------------------------------------------------------
' Procedure : WMI_GetOSBitness
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Return the OS Architecture/bitness -> 32-bit, 64-bit
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sHost : Name/IP Address of the PC to query assuming you have the rights to do so
' optional, so by leaving it blank it will query the local computer
'
' Usage:
' ~~~~~~
' ? WMI_GetOSBitness
' Returns -> 64-bit
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2018-08-30 Initial Release
'---------------------------------------------------------------------------------------
Public Function WMI_GetOSBitness(Optional sHost As String = ".") As String
'Win32_OperatingSystem -> https://msdn.microsoft.com/en-us/library/aa394239%28v=vs.85%29.aspx
On Error GoTo Error_Handler
Dim oWMI As Object 'WMI object to query about the PC's OS
Dim oOSs As Object 'Collection of OSs
Dim oOS As Object 'Individual OS
Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sHost & "\root\cimv2")
Set oOSs = oWMI.ExecQuery("SELECT OSArchitecture FROM Win32_OperatingSystem")
For Each oOS In oOSs 'Enumerate each OS provided by WMI
WMI_GetOSBitness = oOS.OSArchitecture
Next
Error_Handler_Exit:
On Error Resume Next
If Not oOS Is Nothing Then Set oOS = Nothing
If Not oOSs Is Nothing Then Set oOSs = Nothing
If Not oWMI Is Nothing Then Set oWMI = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: WMI_GetOSBitness" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
Optimizing Things!
In the case of WMI and WScript since we are working with Objects, these are prime candidates to use Self-Healing Object Variables.
If you haven’t already, review Self-Healing Object Variables to learn all about them. That being said, below are examples of how this could be implemented.
I know it is more coding initially, but this truly does payoff in performance improvement, especially the more you need to use the Object!
WScript SHOV
' Req'd Refs: Late Binding -> None required
' Early Binding -> Windows Script Host Object Model
#Const WSH_EarlyBind = False
#If WSH_EarlyBind = True Then
Private pWshShell As IWshRuntimeLibrary.WshShell
#Else
Private pWshShell As Object
#End If
#If WSH_EarlyBind = True Then
Public Function oWshShell() As IWshRuntimeLibrary.WshShell
#Else
Public Function oWshShell() As Object
#End If
If pWshShell Is Nothing Then
Debug.Print "*** Setting oWshShell ***"
#If WSH_EarlyBind = True Then
Set pWshShell = New IWshRuntimeLibrary.WshShell
#Else
Set pWshShell = CreateObject("WScript.Shell")
#End If
End If
Set oWshShell = pWshShell
End Function
Public Sub oWshShell_Clear()
'Be sure to always run this when closing your Form/DB to avoid
' hidden instances from running in the background!
Set pWshShell = Nothing
End Sub
'---------------------------------------------------------------------------------------
' Procedure : WSS_IsOS64Bit_SHOV
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine if the OS is 64-bit, or not (Using Self-Healing Object Variables)
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Usage:
' ~~~~~~
' ? WSS_IsOS64Bit_SHOV
' Returns -> True :: Is 64-bit OS
' False :: Is not 64-bit OS
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-02-11 Initial Public Release
'---------------------------------------------------------------------------------------
Function WSS_IsOS64Bit_SHOV() As Boolean
If InStr(oWshShell.Environment("System").Item("Processor_Architecture"), "64") > 0 Then
WSS_IsOS64Bit_SHOV = True
End If
End Function
WMI SHOV
' Req'd Refs: Late Binding -> None required
' Early Binding -> Microsoft WMI Scripting VX.X Library
#Const WMI_EarlyBind = False
#If WMI_EarlyBind = True Then
Private pWMI As WbemScripting.SWbemServices
#Else
Private pWMI As Object
#End If
'Self-healing oWMI property
#If WMI_EarlyBind = True Then
Public Function oWMI(Optional sHost As String = ".") As WbemScripting.SWbemServices
#Else
Public Function oWMI(Optional sHost As String = ".") As Object
#End If
On Error GoTo Err_Handler
If pWMI Is Nothing Then
Debug.Print "*** Setting oWMI ***"
'Set pWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sHost & "\root")
Set pWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sHost & "\root\cimv2")
End If
Set oWMI = pWMI
Exit_Procedure:
DoEvents
Exit Function
Err_Handler:
MsgBox "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: Property Get oWMI" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Exit_Procedure
End Function
Public Sub oWMI_Clear()
'Be sure to always run this when closing your Form/DB to avoid
' hidden instances from running in the background!
Set pWMI = Nothing
End Sub
'---------------------------------------------------------------------------------------
' Procedure : WMI_IsOS64Bit_SHOV
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Determine if the OS is 64-bit, or not (Using Self-Healing Object Variables)
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sHost : Name/IP Address of the PC to query assuming you have the rights to do so
' optional, so by leaving it blank it will query the local computer
'
' Usage:
' ~~~~~~
' ? WMI_IsOS64Bit_SHOV
' Returns -> True :: Is 64-bit OS
' False :: Is not 64-bit OS
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2018-08-30 Initial Release
'---------------------------------------------------------------------------------------
Function WMI_IsOS64Bit_SHOV(Optional sHost As String = ".") As Boolean
'Win32_OperatingSystem -> https://msdn.microsoft.com/en-us/library/aa394239%28v=vs.85%29.aspx
On Error GoTo Error_Handler
Dim oOSs As Object 'Collection of OSs
Dim oOS As Object 'Individual OS
Set oOSs = oWMI.ExecQuery("SELECT OSArchitecture FROM Win32_OperatingSystem")
For Each oOS In oOSs 'Enumerate each OS provided by WMI
If oOS.OSArchitecture = "64-bit" Then WMI_IsOS64Bit_SHOV = True
Next
Error_Handler_Exit:
On Error Resume Next
If Not oOS Is Nothing Then Set oOS = Nothing
If Not oOSs Is Nothing Then Set oOSs = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: WMI_IsOS64Bit_SHOV" & vbCrLf & _
"Error Description: " & Err.Description, _
vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
'---------------------------------------------------------------------------------------
' Procedure : WMI_GetOSBitness_SHOV
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Return the OS Architecture/bitness -> 32-bit, 64-bit
' (Using Self-Healing Object Variables)
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sHost : Name/IP Address of the PC to query assuming you have the rights to do so
' optional, so by leaving it blank it will query the local computer
'
' Usage:
' ~~~~~~
' ? WMI_GetOSBitness_SHOV
' Returns -> 64-bit
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2018-08-30 Initial Release
'---------------------------------------------------------------------------------------
Public Function WMI_GetOSBitness_SHOV(Optional sHost As String = ".") As String
'Win32_OperatingSystem -> https://msdn.microsoft.com/en-us/library/aa394239%28v=vs.85%29.aspx
On Error GoTo Error_Handler
Dim oOSs As Object 'Collection of OSs
Dim oOS As Object 'Individual OS
Set oOSs = oWMI.ExecQuery("SELECT OSArchitecture FROM Win32_OperatingSystem")
For Each oOS In oOSs 'Enumerate each OS provided by WMI
WMI_GetOSBitness_SHOV = oOS.OSArchitecture
Next
Error_Handler_Exit:
On Error Resume Next
If Not oOS Is Nothing Then Set oOS = Nothing
If Not oOSs Is Nothing Then Set oOSs = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: WMI_GetOSBitness_SHOV" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
Speed Comparisons
I decided to test these approaches by timing their execution speed. The test is singular in nature, as this shouldn’t be a function you need to run over and over and over. Instead, it should be run once and saved for reuse (TempVar, Global Var, Static Variable, …). Here were my results.
| Technique | Execution Time | % Diff vs Environ |
|---|---|---|
| Directory Check | 0.0001080000 | 175.00% |
| Environ | 0.0000072000 | 0.00% |
| GetNativeSystemInfo | 0.0000078000 | 8.00% |
| PowerShell | 0.7625699000 | 200.00% |
| WMI | 0.0131925000 | 199.78% |
| WMI (SHOV) | 0.0200134000 | 199.86% |
| IsWow64Process | 0.0000098000 | 30.59% |
| WScript | 0.0010874000 | 197.37% |
| WScript (SHOV) | 0.0014494000 | 198.02% |
So we have a clear winner, using the Environ approach! Close behind are the 2 API approaches. PowerShell is orders of magnitude slower than every other method. WMI is also majorly lagging.
A Quick Word Of Caution
Win64 Conditional Compilation Constant
I’ve seen suggestions that we could simply use the Win64 conditional compilation constant to determine the bitness by doing something like:
Function IsOS64Bit() As Boolean
#If Win64 Then
IsOS64Bit= True
#End If
End Function
NO!
This is not true. Don’t ask me who at Microsoft thought of that label for the constant, but that does not represent the bitness of Windows! My best guess would be it represents the ‘Current Window’ executing the script/code. So basically, it returns the bitness of the program running the VBA code. So if run in Excel, it’s Excel’s bitness. If run in Access, it’s Access’ bitness.
So we could use it to easily determine the bitness of the current application by doing:
Function IsApp64Bit() As Boolean
#If Win64 Then
IsApp64Bit = True
#End If
End Function
Just be careful not to make that false assumption and misinterpret what Win64 is actually validating.
Excel’s OperatingSystem Property
Excel has an convenient OperatingSystem property to get this information.
Sadly, in my testing it is incorrect!!!
On my ‘Microsoft Windows 10 Home (10.0.19045.3930) 64-bit’ , Application.OperatingSystem reports ‘Windows (32-bit) NT :.00’
So, moral of the story, steer clear of Application.OperatingSystem as it is flaky at best.