Page 1 Page 2 Page 3 Page 5



First Published 10 Dec 2023                                               Difficulty level :   Moderate

The previous two articles in this series focused on when and how to use conditional compilation correctly with API declarations and type statements.

This is the fourth and final article on 32- bit to 64-bit conversion.
Here the focus is on managing possible issues you may face with procedures when converting your 32-bit Access applications to run in 64-bit Access.

In many cases, your procedures will continue to run without any changes provided you have followed the steps outlined in the previous three articles.
However there are two types of situation that you will need to address



1.   Procedure Level Variables

In the previous article, I discussed variables defined at the module level. In the case of long datatype variables, if these correspond to pointers/handles, these need to be modified for use with 64-bit using conditional compilation where appropriate.

The same point applies where such variables are defined at the procedure level. For example, consider this procedure which was written for 32-bit Access:

Public Function TwipsPerPixel(strDirection As String) As Long

'Purpose : Get monitor's twips per pixel

      Dim lngDC As Long       'Handle to device context
      Dim lngPixelsPerInch As Long
      Const nTwipsPerInch = 1440

      lngDC = GetDC(0)

      If strDirection = "X" Then       'Horizontal
            lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSX)
      Else       'Vertical
            lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSY)
      End If

      lngDC = ReleaseDC(0, lngDC)
      TwipsPerPixel = nTwipsPerInch / lngPixelsPerInch

End Function



In this case, the only line that needs converting for 64-bit is that shown in BOLD type above. As lngDC is a handle it must be defined as LongPtr

Public Function TwipsPerPixel(strDirection As String) As Long

'Purpose : Get monitor's twips per pixel
'modified to work in 64-bit Access (also works in 32-bit Access 2010 or later)

      Dim lngDC As LongPtr       'Handle to device context
      Dim lngPixelsPerInch As Long
      Const nTwipsPerInch = 1440

      lngDC = GetDC(0)

      If strDirection = "X" Then       'Horizontal
            lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSX)
      Else       'Vertical
            lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSY)
      End If

      lngDC = ReleaseDC(0, lngDC)
      TwipsPerPixel = nTwipsPerInch / lngPixelsPerInch

End Function



If all your users are running VBA7 i.e. Access 2010 or later (32-bit or 64-bit), no other change is required.
However if your user base still includes some users running A2007 or earlier, conditional compilation is needed at the procedure level
There are two ways you can do this:

a)   on the individual variable(s)

Public Function TwipsPerPixel(strDirection As String) As Long

      'first section of code here . . .

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

      'rest of code here . . .

End Function


b)   over the entire procedure

#If VBA7 Then

      Public Function TwipsPerPixel(strDirection As String) As Long

           'first section of code here . . .
            Dim lngDC As LongPtr
           'rest of code here . . .

      End Function

#Else

      Public Function TwipsPerPixel(strDirection As String) As Long

            'first section of code here . . .
            Dim lngDC As Long
            'rest of code here . . .

      End Function

#End If


The main advantage of the first approach is that it avoids duplication of many lines of code.
However, disentangling the code may be more difficult when you longer need to worry about users on A2007 or earlier.

The second approach results in longer code with duplication of many code lines.
However, editing the code may be easier when you longer need to deal with older versions of Access.



2.   Arguments in Procedure Headers

Similar issues apply if you have handles/pointers used as arguments in procedure headers.

For example, this procedure was written for working with system tray alerts (balloon tooltips) in 32-bit Access.
In this case, there is both a procedure argument (Version) and a procedure level variable (lpBuffer) that need converting from Long to LongPtr.

Private Function IsShellVersion(ByVal Version As Long) As Boolean

      Dim lpBuffer As Long
      Dim nBufferSize As Long
      Dim nUnused As Long
      Dim nVerMajor As Integer
      Dim bBuffer() As Byte
      Const sDLLFile As String = "shell32.dll"

      nBufferSize = GetFileVersionInfoSize(sDLLFile, nUnused)
      If nBufferSize > 0 Then
            ReDim bBuffer(nBufferSize - 1) As Byte
            Call GetFileVersionInfo(sDLLFile, 0&, nBufferSize, bBuffer(0))
            If VerQueryValue(bBuffer(0), "\", lpBuffer, nUnused) = 1 Then
                  CopyMemory nVerMajor, ByVal lpBuffer + 10, 2
                  IsShellVersion = nVerMajor >= Version
            End If
      End If

End Function


After conversion to be 64-bit compatible, this becomes:

Private Function IsShellVersion(ByVal Version As LongPtr) As Boolean

      Dim lpBuffer As LongPtr
      Dim nBufferSize As Long
      Dim nUnused As Long
      Dim nVerMajor As Integer
      Dim bBuffer() As Byte
      Const sDLLFile As String = "shell32.dll"

      nBufferSize = GetFileVersionInfoSize(sDLLFile, nUnused)
      If nBufferSize > 0 Then
            ReDim bBuffer(nBufferSize - 1) As Byte
            Call GetFileVersionInfo(sDLLFile, 0&, nBufferSize, bBuffer(0))
            If VerQueryValue(bBuffer(0), "\", lpBuffer, nUnused) = 1 Then
                  CopyMemory nVerMajor, ByVal lpBuffer + 10, 2
                  IsShellVersion = nVerMajor >= Version
            End If
      End If

End Function


As before, when conditional compilation is required, this can be handled in one of two ways

a)   Modify just the code lines required

#If VBA7 Then

      Private Function IsShellVersion(ByVal Version As LongPtr) As Boolean

            Dim lpBuffer As LongPtr
#Else

      Private Function IsShellVersion(ByVal Version As Long) As Boolean

            Dim lpBuffer As Long

#End If

'rest of procedure code here

End Function


b)   repeat the entire procedure

#If VBA7 Then

      Private Function IsShellVersion(ByVal Version As LongPtr) As Boolean

            Dim lpBuffer As LongPtr
            'rest of procedure code here

      End Function

#Else

      Private Function IsShellVersion(ByVal Version As Long) As Boolean

            Dim lpBuffer As Long
            'rest of procedure code here

      End Function

#End If



Each approach has the same advantages and disadvantages as before. To a large extent, personal preference applies here.

Here is another example of a procedure modified using the first approach.
It is taken from code used to create a transparent background to a form as part of my Attention Seeking example app.

#If VBA7 Then
      Public Function TransparentFormWithVisibleControl(f As Access.Form, Optional Color As Variant = vbCyan) As LongPtr
      Dim lhnd As LongPtr
#Else
      Public Function TransparentFormWithVisibleControl(f As Access.Form, Optional Color As Variant = vbCyan) As Long
      Dim lhnd As Long
#End If

            lhnd = SetWindowLong(f.hWnd, GWL_EXSTYLE, GetWindowLong(f.hWnd, GWL_EXSTYLE) Or WS_EX_LAYERED)
            SetLayeredWindowAttributes f.hWnd, Color, 0&, LWA_COLORKEY
            TransparentFormWithVisibleControl = lhnd

      End Function




Conclusions

I hope this series of articles has provided sufficient information for you to tackle even the most complex conversion project.

Even so, I recommend you make use of the various documentation and utilities available to assist with the conversion process
See the Information & Guidance section in the first article in this series.

As you have seen, using conditional compilation makes the code significantly more complex.

Remember that you do NOT need to use conditional compilation if all your users are running Access 2010 or later.

This should now be the standard situation as Microsoft no longer supports any versions of Office / Access earlier than 2016.

Finally, please use the Contact form below to let me know if there are any errors or omissions in these articles.



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 10 Dec 2023



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