Compile Error using 64-bit system

net

Registered User.
Local time
Yesterday, 20:37
Joined
Mar 12, 2006
Messages
50
Hello Code Experts:

I inherited a recipe database from my aunt. The database was created by her husband who is no longer with us. RIP uncle.

I loaded the Microsoft Access database on my laptop but when I go into view a recipe I receive the following error message.

Error Code Form:

Compile Error:
The code in this project must be updated for use on 64-bit systems. Please review and update Declare statements and then mark them with the PtrSafe attribute.

Can someone help update the code from a 32-bit to a 64-bit so that I can use the database on my laptop please. Your time is appreciated. :)

I have the following system:

Windows: Windows 7
System Type: 64-bit Operating System
Intel(R) Core(TM) i5-4300M CPU @ 2.6GHz

The following is the VB code where it errors:

<Begin Code>

Option Compare Database

Option Explicit

Private Declare Function GetClassNameA Lib "user32" ( _
ByVal hwnd As Long, _
ByVal lpClassName As String, _
ByVal nMaxCount As Long) _
As Long
Private Declare Function GetWindow Lib "user32" ( _
ByVal hwnd As Long, _
ByVal wCmd As Long) _
As Long
Private Declare Function ShowWindowAsync Lib "user32" ( _
ByVal hwnd As Long, _
ByVal nCmdShow As Long) _
As Boolean

Private Const GW_HWNDNEXT = 2
Private Const GW_CHILD = 5

Private Const SW_HIDE = 0
Private Const SW_SHOW = 5

<End Code>
 
Hi

The changes required for 64-bit Access are:
- add PtrSafe after Declare
- change Long to LongPtr

However if you just do that, it won't be possible to run it in 32-bit Access
So you do conditional compiling as follows to allow it to run in either 'bitness'

Code:
Option Compare Database
Option Explicit

#If Win64 Then '64-bit Access
        Private Declare PtrSafe Function GetClassNameA Lib "user32" ( _
           ByVal hwnd As LongPtr, _
           ByVal lpClassName As String, _
           ByVal nMaxCount As LongPtr) _
           As LongPtr
       Private Declare PtrSafe Function GetWindow Lib "user32" ( _
          ByVal hwnd As LongPtr, _
          ByVal wCmd As LongPtr) _
          As LongPtr
       Private Declare PtrSafe Function ShowWindowAsync Lib "user32" ( _
          ByVal hwnd As LongPtr, _
          ByVal nCmdShow As LongPtr) _
          As Boolean
#Else '32-bit Access
       Private Declare Function GetClassNameA Lib "user32" ( _
          ByVal hwnd As Long, _
          ByVal lpClassName As String, _
          ByVal nMaxCount As Long) _
          As Long
       Private Declare Function GetWindow Lib "user32" ( _
          ByVal hwnd As Long, _
          ByVal wCmd As Long) _
          As Long
       Private Declare Function ShowWindowAsync Lib "user32" ( _
          ByVal hwnd As Long, _
          ByVal nCmdShow As Long) _
          As Boolean
#End If

Private Const GW_HWNDNEXT = 2
Private Const GW_CHILD = 5

Private Const SW_HIDE = 0
Private Const SW_SHOW = 5

NOTE:
1. Using 64-bit, the 32-bit section after #Else will appear in RED
This isn't an error!

2. You will need to do the same process for any other API declarations in other modules
 
The changes required for 64-bit Access are:
- add PtrSafe after Declare
- change Long to LongPtr
You should not change all Long variables to LongPtr. Only those that actually are pointers!
About half of the Long variables in the sample at hand are not.
 
You should not change all Long variables to LongPtr. Only those that actually are pointers!
About half of the Long variables in the sample at hand are not.

I agree with the above statement in principle.
However, I've been doing #If Win64 ...#Else ...#End If for several years and never had any problems in doing a 'blanket' conversion.

It would perhaps have helped the OP more if you had listed your version...

This link may be useful - its for Excel but also applies to Access http://www.cpearson.com/excel/Bitness.aspx
 
Last edited:
Thank you Ridders, I updated the old code with yours and that worked, but now I am getting a "Type Mismatch" on GetWindow.

I apolozie, but I am not code savy so I cannot make out most of the issues. :-(

<Being Code>
Public Sub ShowDbWindow(ByVal bCmdShow As Boolean)

Dim hWndApp As Long

hWndApp = GetWindow(Application.hWndAccessApp, GW_CHILD)
Do Until hWndApp = 0
If GetClassName(hWndApp) = "MDIClient" Then
Exit Do
End If
hWndApp = GetWindow(hWndApp, GW_HWNDNEXT)
Loop

If hWndApp > 0 Then
hWndApp = GetWindow(hWndApp, GW_CHILD)
Do Until hWndApp = 0
If GetClassName(hWndApp) = "ODb" Then
Exit Do
End If
hWndApp = GetWindow(hWndApp, GW_HWNDNEXT)
Loop
End If

If hWndApp > 0 Then
ShowWindowAsync hWndApp, IIf(bCmdShow, SW_SHOW, SW_HIDE)
End If

End Sub
<End Code>
 
Please use code tags (# button on toolbar) when posting code as its easier to read ... like this:

Code:
Public Sub ShowDbWindow(ByVal bCmdShow As Boolean)

Dim hWndApp As Long

hWndApp = GetWindow(Application.hWndAccessApp, GW_CHILD)
Do Until hWndApp = 0
If GetClassName(hWndApp) = "MDIClient" Then
Exit Do
End If
hWndApp = GetWindow(hWndApp, GW_HWNDNEXT)
Loop

If hWndApp > 0 Then
hWndApp = GetWindow(hWndApp, GW_CHILD)
Do Until hWndApp = 0
If GetClassName(hWndApp) = "ODb" Then
Exit Do
End If
hWndApp = GetWindow(hWndApp, GW_HWNDNEXT)
Loop
End If

If hWndApp > 0 Then
ShowWindowAsync hWndApp, IIf(bCmdShow, SW_SHOW, SW_HIDE)
End If

End Sub

However, I can't see why that's not working for you - perhaps someone else can ...
Which line does it error at? And what is the error?

It seems likely to me that you are going to have further errors after this.
Have you checked if any other modules have declarations?

If necessary, hold the SHIFT key down whilst you open the db.
That will allow you to bypass any startup conditions so you can examine all the code
 
I did not know there were code tags. I will use them going forward. Thanks for the info.

The Error message is

Compile Error:
Type Mismatch

It errors out on the this line and highlights the word "GetWindow"

hWndApp = GetWindow(Application.hWndAccessApp, GW_CHILD)
 
Sorry but I can't help just by reading that section of code

The GetWindow API you provided is very widely used & I have several examples of it in my databases.
However I don't have the function ShowDbWindow - you could try googling it in case your late uncle downloaded it.

I assume its to control whether the database window is visible or hidden.

If so, I have alternative code you could try in this post:
https://www.access-programmers.co.uk/forums/showpost.php?p=1539350&postcount=3
...AND the good news is I have already converted that for 64-bit!

The relevant code is in modDatabaseWindow and uses the same ShowWindow API.

You'll also see other modules with 32-bit to 64-bit conversions.

BTW - 64-bit Access has NO benefits over 32-bit Access and as you are already discovering, can cause lots of issues.
If you have the opportunity to swop to 32-bit Office, I would do so.

NOTE: You can't have both on the same computer
 
I really appreciate the first update you provided. I will take a look at your suggestions. Thank you so much for spending the time helping with my issue.
 
Merely changing the API declaration to x64 is not enough. When there is compiler error fo back and see the correct Api declaration.

On this case pay attention to hWndApp, this should be LongPtr Since this is a window handle.

Public Sub ShowDbWindow(ByVal bCmdShow As Boolean)
#if win64 then
Dim hWndApp As LongPtr
#else
Dum hWndApp As Long
#End If

hWndApp = GetWindow(Application.hWndAccessApp, GW_CHILD)
Do Until hWndApp = 0
If GetClassName(hWndApp) = "MDIClient" Then
Exit Do
End If
hWndApp = GetWindow(hWndApp, GW_HWNDNEXT)
Loop

If hWndApp > 0 Then
hWndApp = GetWindow(hWndApp, GW_CHILD)
Do Until hWndApp = 0
If GetClassName(hWndApp) = "ODb" Then
Exit Do
End If
hWndApp = GetWindow(hWndApp, GW_HWNDNEXT)
Loop
End If

If hWndApp > 0 Then
ShowWindowAsync hWndApp, IIf(bCmdShow, SW_SHOW, SW_HIDE)
End If

End Sub
 
I agree with the above statement in principle.
However, I've been doing #If Win64 ...#Else ...#End If for several years and never had any problems in doing a 'blanket' conversion.
My knowledge of C and the x64 calling conventions is insufficient to point out any function declarations where this will fail for sure. However, if you 'blanket converted' any custom type and pass that type to an API function, the call will instantly and always fail

It would perhaps have helped the OP more if you had listed your version...
Agreed.
To contribute some more helpful insights on this topic, I wrote down my thoughts on this in a slightly longer text on Windows API declarations in VBA for 64-bit.
I'm not sure if this will actually help the OP, but it might contain a useful idea or two for VBA developers with a bit more experience.
 
My knowledge of C and the x64 calling conventions is insufficient to point out any function declarations where this will fail for sure. However, if you 'blanket converted' any custom type and pass that type to an API function, the call will instantly and always fail

I was deliberately simplifying there.
However, I have successfully deployed several databases for both 32-bit & 64-bit Access for the past 7 years.
These are used by several hundred end users in several different locations.

I always include code to create a popup message for 64-bit Access users informing them that issues MAY occur and asking for feedback if so.

There has in all that time been only one occasion where my conversion didn't work first time in 64-bit Access.
I did have to modify API declaration code in a ribbon creation module code supplied by Gunter Avenius.
The 'solution' was a bit messy but it worked (attached if you are interested - but not the complete module with declarations))
However I've added improving it to my list of jobs for this month

To contribute some more helpful insights on this topic, I wrote down my thoughts on this in a slightly longer text on Windows API declarations in VBA for 64-bit.
I'm not sure if this will actually help the OP, but it might contain a useful idea or two for VBA developers with a bit more experience.

Ouch...that feels like a dig at me...

I've quickly read your article and think it's a useful contribution to explaining this area. In fact it might be a good candidate as a 'sticky' post in e.g. modules & VBA

Two things:
1. I think it would be helpful to developers if you provided additional detail on identifying which arguments are pointers e.g. hwnd and those that aren't

2. A very common method of conditional compiling is to use 3 sections
Code:
If VBA7 Then

#ElseIf Win64 Then

#Else

#End If

I notice you didn't cover that approach.
Your views on that method?
 

Attachments

Last edited:
the first part (#if VBE7) is only a check if your VBE is new (A2010 onward) and nothing more. A2K7 (and older version) doesnt have keywords like PtrSae, LongPtr and LongLong.
for this to work it, you should have another test to see if you are using Office x64 or x86:

#If vbe7 Then
#If Win64 Then
'declare with PtrSafe (MUST use LongPtr, LongLong, etc.)
#Else
'declare with PtrSafe (no need to use LongPtr, LongLong, etc.)
#End If
#Else
'declare as normal (no need PtrSafe, LongPtr, LongLong, etc.)
#End If
 
I was deliberately simplifying there.
However, I have successfully deployed several databases for both 32-bit & 64-bit Access for the past 7 years.
I actually tried to find an API call where the incorrect use of LongPtr right in the function declaration would actually and reproducibly cause a problem. - I wasn't able to do find any. So, with most declaration it seems not make much of a difference.

Still, I would advise to rather use the correct declaration according to the original spec of the function than an alternative one that happens to be working also.

Ouch...that feels like a dig at me...
Sorry, that was not my intention at all!

I've quickly read your article and think it's a useful contribution to explaining this area. In fact it might be a good candidate as a 'sticky' post in e.g. modules & VBA
Thank you! :-)

1. I think it would be helpful to developers if you provided additional detail on identifying which arguments are pointers e.g. hwnd and those that aren't
Agreed, that would be an useful addition. I'll try to add some more information on that when I find the time to do so.

2. A very common method of conditional compiling is to use 3 sections
Code:
If VBA7 Then

#ElseIf Win64 Then

#Else

#End If
I notice you didn't cover that approach.
Your views on that method?
Well, one of my points is that you only very, very rarely need to do this. Usually the distinction between #VBA7 and earlier is enough.

However, there are cases where you would want, but not necessarily need, to do this. My Example of GetTickCount vs. GetTickCount64 is such a case. I deliberately reduced the code to the #VBA7=True case there. Otherwise this would become messy.

Nevertheless, that left-out, messy part could become a good example to show how the differences in the 32/64-bit declarations can fall-out far beyond the immediate API declaration. Your example of the picture handling in the ribbon code (thank you for that) also shows the spread of duplicate, conditionally compiled, code throughout several procedures.

My advice on this would be, avoid it whenever possible. In my sample scenario the use of GetTickCount64 is obviously optional. So, if I would need to support pre-VBA7 environments with this, I would not use the specific 64-bit-function at all to avoid that messiness.
 
the first part (#if VBE7) is only a check if your VBE is new (A2010 onward) and nothing more.
Correct, but usually that is all you need to check!

I would like to revise your explanation code a bit:
Code:
#If VBA7 Then
  #If Win64 Then
    ' MUST use PtrSafe and LongPtr, CAN use LongLong if required (it almost never is!)
  #Else
    ' SHOULD use PtrSafe and LongPtr, CANNOT use LongLong
  #End If
#Else
  ' CANNOT use PtrSafe, LongPtr, and LongLong
#End If
In almost all situations you can combine both VBA7 branches of that code into one and get much cleaner and simpler code as a reward.
 
I actually tried to find an API call where the incorrect use of LongPtr right in the function declaration would actually and reproducibly cause a problem. - I wasn't able to do find any. So, with most declaration it seems not make much of a difference.

Still, I would advise to rather use the correct declaration according to the original spec of the function than an alternative one that happens to be working also.

Well I'm relieved that you haven't yet found an example of this failing specifically where LongPtr was used incorrectly.

I'm sure that an example does exist but it does reinforce my view that posting a warning like this for 64-bit users may cover almost all situations

attachment.php


Nevertheless, that left-out, messy part could become a good example to show how the differences in the 32/64-bit declarations can fall-out far beyond the immediate API declaration. Your example of the picture handling in the ribbon code (thank you for that) also shows the spread of duplicate, conditionally compiled, code throughout several procedures.

My advice on this would be, avoid it whenever possible. In my sample scenario the use of GetTickCount64 is obviously optional. So, if I would need to support pre-VBA7 environments with this, I would not use the specific 64-bit-function at all to avoid that messiness.

Yes I agree completely.
I do use GetTickCount in some of my code but have never reached a limit so not needed to consider the 64-bit version.

The example I gave came from IDBE Ribbon Creator by Gunter Avenius which is available here: http://www.ribboncreator2016.de/en/?Download

Previously this was 32-bit only which I adapted for dual bitness.

However, when I went to check the address just now I found he had recently released a 64-bit Access 2016 version.

I'm going to look at it later & see how he has dealt with the code section.
 

Attachments

  • Capture.PNG
    Capture.PNG
    18.8 KB · Views: 885

Users who are viewing this thread

Back
Top Bottom