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
|
|