Page 1 Page 2 Page 4 Page 5




First Published 7 Dec 2023                                                Difficulty level :   Moderate

The previous article in this series 32 to 64-bit: Conditional Compilation focused on when and how to use conditional compilation correctly with API declarations.

This article will focus on the use of conditional compilation with other items declared at the module level for use in 32/64-bit

In addition to APIs, the declaration section of code modules may contain Constants, Enums, Variables and Types with scope at the module or project level.
We will now consider what action needs to be taken with each of these when converting your projects to 64-bit



1.   Constants

      Some examples:

Private Const HWND_DESKTOP = 0
Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY = 90
Public Const DefaultMargin = 60 'twips (approx 0.1 cm)


      By definition, constant values do NOT need adjusting for use in 64-bit Access



2.   Enumeration Statements (Enums)

      Enumeration variables are variables declared with an Enum type. Both variables and parameters can be declared with an Enum type.
      The elements of the Enum type are initialized to constant values within the Enum statement. For example:

Public Enum ProcScope
      ScopePrivate = 1
      ScopePublic = 2
      ScopeFriend = 3
      ScopeDefault = 4
End Enum

Public Enum AccessSpecifications
      maxSectionHeight = 31680
      maxFormWidth = 31680
      maxReportWidth = 31680
      RecordSelectorWidth = 300
End Enum


      Similarly, as enums are constant values, these do not need to be adapted for 64-bit Access
      For more details, see the Microsoft Help article: Enum statements



3.   Variable Definitions

      Some examples:

Dim bt As BalloonTooltip
Dim hRgn As Long0
Dim intPerPixelX As Integer
Dim intPerPixelY As Integer


      For long datatype variables, if these correspond to pointers/handles, these need to be modified for use with 64-bit using conditional compilation where appropriate.
      For example, here are two functions used to convert measurements of screen objects between twips & pixels:

Public Function converttoPixelX(ByVal TwipsX As Long) As Long
      'twips to pixels (1440 twips = 1 inch)
     lngDC = GetDC(HWND_DESKTOP)
     intPerPixelX = 1440 / GetDeviceCaps(lngDC, LOGPIXELSX)
     ReleaseDC HWND_DESKTOP, lngDC
     converttoPixelX = TwipsX / intPerPixelX
End Function

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

Public Function converttoTwipsY(ByVal PixelY As Long) As Long
      'pixels to twips
     lngDC = GetDC(HWND_DESKTOP)
     intPerPixelY = 1440 / GetDeviceCaps(lngDC, LOGPIXELSY)
     ReleaseDC HWND_DESKTOP, lngDC
      converttoTwipsY = intPerPixelY * PixelY
End Function


      These two functions involve the use of:
      a)   THREE constants: HWND_DESKTOP, LOGPIXELSX, LOGPIXELSY (see above)

      b)   THREE APIs: GetDC, ReleaseDC & GetDeviceCaps
            Conditional compilation is required if some users are still running A2007 or earlier

#If VBA7 Then       ' A2010 or later (32-bit or 64-bit)
     Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
     Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDC As LongPtr) As Long
     Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDC As LongPtr, ByVal nIndex As Long) As Long
#Else       ' A2007 or earlier (32-bit or 64-bit)
     Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
     Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) As Long
     Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDC As LongPtr, ByVal nIndex As Long) As Long
#End If


            NOTE:
            Alternatively, you can use #If Win 64 ...#Else ...#End If . See the previous article for the differences in functionality.

      c)   TWO integer variables : intPerPixelX, intPerPixelY - no conversion needed

      d)   ONE pointer variable : lngDC with a datatype depending on the bitness, so again conditional compilation is required as described above:

#If VBA7 Then
      Dim lngDC As LongPtr
#Else
     Dim lngDC As Long
#End If




4.   Type Statements

      These are used at module level to define a user-defined data type containing one or more elements.
      For more details, see the Microsoft Help article: Type statement

      Here are two simple examples of type statements which define variables as long datatype for use in the position and size of screen objects:

Private Type RECT
     Left As Long
      Top As Long
      Right As Long
      Bottom As Long
End Type

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

Public Type SIZE
      Width As Long
      Height As Long
End Type


      No conversion is needed for either of the above type statements in 64-bit.
      However, where a type statement includes a long datatype pointer, conversion to LongPtr is needed as for APIs and 'standalone' variable definitions

      For example, consider the 32-bit version of this type statement used with balloon tooltips (system tray alerts)

Private Type NOTIFYICONDATA
      cbSize As Long
      hwnd As Long
      UID As Long
      uFlags As Long
      uCallbackMessage As Long
      hicon As Long
      szTip As String * 128
      dwState As Long
      dwStateMask As Long
      szInfo As String * 256
      uTimeoutAndVersion As Long
      szInfoTitle As String * 64
      dwInfoFlags As Long
      guidItem As GUID
End Type


This contains TWO pointers (hwnd & hIcon) which need to be redefined as LongPtr for use in 64-bit:

Private Type NOTIFYICONDATA
      cbSize As Long
      hwnd As LongPtr
      UID As Long
      uFlags As Long
      uCallbackMessage As Long
      hicon As LongPtr
      szTip As String * 128
      dwState As Long
      dwStateMask As Long
      szInfo As String * 256
      uTimeoutAndVersion As Long
      szInfoTitle As String * 64
      dwInfoFlags As Long
      guidItem As GUID
End Type


      Using conditional compilation this could be written as:

#If VBA7 Then
      Private Type NOTIFYICONDATA
      cbSize As Long
      hwnd As LongPtr
      UID As Long
      uFlags As Long
      uCallbackMessage As Long
      hicon As LongPtr
      szTip As String * 128
      dwState As Long
      dwStateMask As Long
      szInfo As String * 256
      uTimeoutAndVersion As Long
      szInfoTitle As String * 64
      dwInfoFlags As Long
      guidItem As GUID
      End Type
#Else
      Private Type NOTIFYICONDATA
      cbSize As Long
      hwnd As Long
      UID As Long
      uFlags As Long
      uCallbackMessage As Long
      hicon As Long
      szTip As String * 128
      dwState As Long
      dwStateMask As Long
      szInfo As String * 256
      uTimeoutAndVersion As Long
      szInfoTitle As String * 64
      dwInfoFlags As Long
      guidItem As GUID
      End Type
#End If


     Alternatively, you can remove duplicate code lines by using:

Private Type NOTIFYICONDATA
      cbSize As Long
      #If VBA7 Then
            hwnd As LongPtr
      #Else
            hwnd As Long
      #End If
      UID As Long
      uFlags As Long
      uCallbackMessage As Long
      #If VBA7 Then
            hicon As LongPtr
      #Else
            hicon As Long
      #End If
      szTip As String * 128
      dwState As Long
      dwStateMask As Long
      szInfo As String * 256
      uTimeoutAndVersion As Long
      szInfoTitle As String * 64
      dwInfoFlags As Long
      guidItem As GUID
End Type


      This has fewer code lines but may be slightly harder for developers to understand the code.

      Here is another more complex example used with a Color Chooser dialog:

Private Type CHOOSECOLOR
     lStructSize As Long
     hwndOwner As Long
     hInstance As Long
     rgbResult As Long
     lpCustColors As Long
     flags As Long
     lCustData As Long
     lpfnHook As Long
     lpTemplateName As String
End Type


      This contains FIVE pointers: hwndOwner, hInstance, lpCustColors, lCustData and lpfnHook, all of which need to be redefined as LongPtr for use in 64-bit:

Private Type CHOOSECOLOR
     lStructSize As Long
     hwndOwner As LongPtr
     hInstance As LongPtr
     rgbResult As Long
     lpCustColors As LongPtr
     flags As Long
     lCustData As LongPtr
     lpfnHook As LongPtr
     lpTemplateName As String
End Type


     Using conditional compilation this could be written as:

#If VBA7 Then
      Private Type CHOOSECOLOR
           lStructSize As Long
           hwndOwner As LongPtr
           hInstance As LongPtr
           rgbResult As Long
           lpCustColors As LongPtr
           flags As Long
           lCustData As LongPtr
           lpfnHook As LongPtr
           lpTemplateName As String
      End Type
#Else
      Private Type CHOOSECOLOR
           lStructSize As Long
           hwndOwner As Long
           hInstance As Long
           rgbResult As Long
           lpCustColors As Long
           flags As Long
           lCustData As Long
           lpfnHook As Long
           lpTemplateName As String
      End Type
#End If


     Again this will work, but has several repeated lines of code.

     Or, you can remove duplicate code lines by using:

Private Type CHOOSECOLOR
     lStructSize As Long
      #If VBA7 Then
           hwndOwner As LongPtr
           hInstance As LongPtr
           lpCustColors As LongPtr
           lCustData As LongPtr
           lpfnHook As LongPtr
      #Else
           hwndOwner As Long
           hInstance As Long
           lpCustColors As Long
           lCustData As Long
           lpfnHook As Long
      #End If
     rgbResult As Long
     flags As Long
     lpTemplateName As String
End Type


      Again this has fewer code lines but it may be significantly harder for developers to understand the code.

      It will also be more complex to separate out the required code if conditional compilation is no longer required at a later date

      It is up to individual developers to decide which is the most appropriate solution in each case



5.   Conversion Utilities

      Once again, if you have a lot of applications to convert and/or a lot of APIs & Type statements, you may find one or both of the following utilities useful

a)   Windows API Viewer for Excel
      Despite its name, the information provided is equally applicable to all VBA enabled Office applications.
      This is a free, standalone utility created by former Excel MVP, Dennis M. Wallentin back in 2016.
      It handles API declarations, type statements and constants

      NOTE: Choose the correct version to match your Windows (not Office) bitness

      Click to download:

      a)   64-bit:       Windows API Viewer x64       EXE file (zipped) - approx 28 MB

      b)   32-bit:       Windows API Viewer x86       EXE file (zipped) - approx 28 MB

b)   Access 32 to 64 Conversion
      This is an ongoing project currently being developed by Peter Cole and available from Access32to64
      It includes a free API scanner and Viewer available for download from the above site.
      If you have a large number of procedures / applications to update, an Access 32 to 64 Updater application is also available from the same site.

      NOTE: The Updater is a commercial application. For more details including prices, send an email to: support@thememydatabase.co.uk



6.   Feedback

      Please use the contact form below to let me know whether you found this article interesting/useful or if you have any questions/comments.

      Please also consider making a donation towards the costs of maintaining this website. Thank you



Colin Riddington           Mendip Data Systems                 Last Updated 7 Dec 2023



Return to Access Articles Page Page 3 of 5 1 2 3 4 5 Return To Top