Compile Error For 64 Bit
Compile Error For 64 Bit
Compile Error For 64 Bit
On This Page
SYMPTOMS
Consider the following scenario:
You write a Microsoft Visual Basic for Applications (VBA) macro code that uses
Declare statements.
Your VBA macro code uses compilation constants. For example, your macro code
uses one the following compilation constants:
o #If VBA7
o #If Win64
You use an #Else block in a conditional block. In the #Else block, you use syntax
for a Declare statement designed to run in Microsoft Visual Basic for Applications
6.0.
You edit the code in a 64-bit version of a Microsoft Office 2010 program.
You try to change the Declare statement in the #Else block.
In this scenario, you receive the following error message:
Microsoft Visual Basic for Applications
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.
Note This issue only occurs when you edit the VBA macro. This issue does not occur
when you run the macro.
RESOLUTION
To resolve this issue, ignore the "Compile error" and run the VBA code in the 64-bit
version of the Office 2010 program.
Back to the top | Give Feedback
MORE INFORMATION
Steps to reproduce the problem
Microsoft provides programming examples for illustration only, without warranty either
expressed or implied, including, but not limited to, the implied warranties of
merchantability and/or fitness for a particular purpose. This article assumes that you are
familiar with the programming language being demonstrated and the tools used to create
and debug procedures. Microsoft support professionals can help explain the functionality
of a particular procedure, but they will not modify these examples to provide added
functionality or construct procedures to meet your specific needs.
If you have limited programming experience, you may want to contact a Microsoft
Certified Partner or Microsoft Advisory Services. For more information, visit these
Microsoft Web sites:
Microsoft Certified Partners - https://partner.microsoft.com/global/30000104
Microsoft Advisory Services - http://support.microsoft.com/gp/advisoryservice
For more information about the support options that are available and about how to
contact Microsoft, visit the following Microsoft Web site:
http://support.microsoft.com/default.aspx?scid=fh;EN-US;CNTACTMS
1. Start the 64-bit version of Microsoft Excel 2010 that is running on a Windows 64bit operating system.
Note By default, a new workbook is opened.
2.
3. Press ALT+F11 to start the Visual Basic for Applications 7.0 IDE window.
4. On the Insert menu, click Module.
5. In the code window that appears, copy and paste the following code:
6. #If VBA7 Then
7.
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As
LongPtr)
8. #Else
9.
Private Declare Sub Sleep Lib "kernel32" (ByVal ms as Long)
10. #End If
11. In each Declare statement, manually change the name of any parameter that is
I've already encountered this problem on people using my in-house tools on new 64 bit machines wi
all I had to do was change lines of code like this:
To This:
23 down
vote
accepted You will, of course want to make sure that the library you're using is available on both machines, bu
problem.
Note that in the old VB6, PtrSafe isn't even a valid command, so it'll appear in red as though you ha
ever give an error because the compiler will skip the first part of the if block.
Applications using the above code compile and run perfectly on Office 2003, 2007, and 2010 32 and
I've already encountered this problem on people using my in-house tools on new 64 bit
machines with Office 2010.
all I had to do was change lines of code like this:
Private Declare Function ShellExecute Lib "shell32.dll" Alias
"ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As
String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal
nShowCmd As Long) As Long
To This:
#If VBA7 Then
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll"
Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile
As String, ByVal lpParameters As String, ByVal lpDirectory As String,
ByVal nShowCmd As Long) As Long
#Else
Private Declare Function ShellExecute Lib "shell32.dll" Alias
"ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile
As String, ByVal lpParameters As String, ByVal lpDirectory As String,
ByVal nShowCmd As Long) As Long
#End If
You will, of course want to make sure that the library you're using is available on both
machines, but so far nothing I've used has been a problem.
Note that in the old VB6, PtrSafe isn't even a valid command, so it'll appear in red as
though you have a compile error, but it won't actually ever give an error because the
compiler will skip the first part of the if block.
Applications using the above code compile and run perfectly on Office 2003, 2007, and
2010 32 and 64 bit.
Why is this? Were we not told that VBA7 is 100% compatible with VBA6? The issue isnt with
VBA. The reason your macros are failing is because they are not set up to reference 64 bit DLL
files, or the DLL files you are trying to reference are not 64 bit compatible. This includes ActiveX
controls, which have the extension .ocx but are actually still DLLs underneath. So if you are using
any of the Microsoft Common Controls in your user form (e.g., slider, calendar, web browser) then
you are using ActiveX controls that will fail in VBA7.
First Im going to give you the quick-and-dirty steps on how to (hopefully) fix your dilemma. Later,
if youre so inclined, you can keep reading and learn the technical why behind the dilemma.
Unfortunately, Microsoft has decided not to update the underlying DLLs to support 64 bit, so you
will definitely need a workaround. If you cant find an alternative DLL and dont mind writing your
own, keep in mind that since these controls are really just wrappers for underlying Win32 API
calls, it is certainly possible to write a DLL that accesses those Win32 API calls directly.
64 bit
Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" Alias
"SHGetPathFromIDListA" (ByVal pidl As LongPtr, ByVal pszPath As String) As
LongPtr
2. The inclusion of the PtrSafe keyword simply means you think the DLL is safe for 64 bit use.
This doesnt mean it actually is safe! If you arent certain if a DLL is 64 bit, you can determine this
using tools like Process Explorer or Dependency Walker.
3. Even if your DLL is compiled for 64 bit and you are using PtrSafe and LongPtr properly, your
macro will still fail if your DLL has any dependent DLLs that are not compiled for 64 bit.
Not too bad, is it? Note that you can use conditional compilation constants anywhere in your
code, including LongPtr declarations within other functions and sub-procedures.
Technical Background
I hope by this point you know what you need to do to correct any 64 bit compatibility issues youre
having with your macros. For some of you, however, this isnt enough. You want to know the
why behind all of this. This next section should answer of that for you.
To answer the why question, we need to begin by understanding why 64 bit computers exist in
the first place. As anyone whos taken a basic course in digital logic knows, the smallest unit of
information in a computer is a bit, which represents a 1 or a 0. The smallest amount of
information that your computer can write to and read from, however, is not a bit but a byte, which
is composed of 8 bits. Next, what you need to understand is that when data is stored in RAM
(memory), each byte has an address. Just like a postal address, your computer needs to know
where data is being stored in memory in order to read it or write to it. On a 32 bit system, these
addresses are composed of 4 bytes. Since each byte is composed of 8 bits, that means we have
32 bits total to work with. In binary, that means our total number of possible bytes we can address
with a 32 bit memory address is 2^32, or 4,294,967,296. As you know, thats equal to 4 GiB.
Now, as we all know, 4GB just isnt good enough! We want more memory lots more! But with
only 32 bits, we cant address all of that memory. The solution? Start making addresses that are
64 bits in length. This will allow for a whopping 16 Exabytes of possible memory. (Note: No doubt
it will only be a couple of decades before I look back and laugh at myself for finding 16 Exabytes
so astounding!)
Continuing on, we need to know that addresses are also called pointers. Since these pointers
are composed 4 bytes, we need store them in a data type of this size. If you open up the
Microsoft VBA Help in the VB Editor and locate the Data Type Summary article, youll see that
Long and Object data types listed as containing 4 bytes. Not surprisingly, these are the data types
used for pointers. In the case of the SolidWorks API, the Object data type is used to store the
pointer for our SolidWorks object interfaces like ISldWorks, IModelDoc2, etc. In the case of DLL
functions, the pointers are often times declared as Long.
VBA6 is the version of VBA used in the late 90s and the following decade. It can only handle 32
bit addresses. Now that computers are using 64 bit addresses, a new version of VBA was needed
to handle addresses of this length. Thus VBA7 was created. Since VBA7 uses 64 bit memory
addresses, any DLLs that it references must be 64 bit compatible. This is where the problem
comes in for so many users: the DLLs referenced in their macros are still compiled for 32 bit
computers. For many DLLs, this issue is solved by recompiling the DLL for 64 bit.
When you call a function from a DLL in a VBA macro, you need to use the Declare statement. For
example, lets say you have a DLL called diskspace.dll that resides in C:\somepath\. Here is
how you would declare it in your module:
Declare Function getdiskinfo Lib "c:\somepath\diskinfo.dll"
(ByVal mydrive As String, ByVal myvolume As String, free As Long) As Long
On 64 bit computers, however, this will not work because our Long variables, which are being
used as pointers, cannot handle 64 bit addresses. Basically, we need a new version of Long that
can hold a 64 bit memory type. In VBA7, Microsoft created this new variable for us. It is called
LongLong, and it only works in 64 bit applications. Converting our Long variables to LongLong
isnt the only modification we have to make, however. In order to indicate that the DLL is safe for
64 bit use, we also need to insert the PtrSafe keyword after the Declare keyword. So all together
we have this:
Declare PtrSafe Function getdiskinfo Lib "c:\somepath\diskinfo.dll"
(ByVal mydrive As String, ByVal myvolume As String, free As LongLong) As
LongLong
Keep in mind that this will ONLY work on 64 bit versions of our application. For applications like
Microsoft Office, however, you can actually have a 32 bit version of Office running on a 64 bit
computer. In this case, LongLong wouldnt work, so Microsoft created a data type that transforms
into Long or LongLong depending on the application. This data type is called LongPtr.
SolidWorks x86 (32 bit) cannot be installed on a 64 bit computer, but you might as well use
LongPtr anyway:
Declare PtrSafe Function getdiskinfo Lib "c:\somepath\diskinfo.dll"
(ByVal mydrive As String, ByVal myvolume As String, free As LongPtr) As LongPtr
To summarize: once your DLL is compiled for 64 bit, all you need to do is change the pointers to
LongPtr and insert the PtrSafe keyword after the Declare keyword. Moreover, you can use what
are called Conditional Compilation Constants to allow for backward compatibility of your code,
which was demonstrated in any earlier section of the post.
Before I finish up, I want to share something interesting regarding the SolidWorks API and 64 bit.
Even though 64 bit computers have been supported by SolidWorks since SolidWorks 2006,
SolidWorks 2013 is the first version to contain VBA7 (since Microsoft did not make VBA7
available to third-party vendors until recently). That means that for SolidWorks 2006-2012 64 bit,
VBA6 was still being used. How did that work? It worked because SolidWorks Corporation
created an out-of-process COM server called swVBAserver.exe to handle the interaction between
64 bit SolidWorks and 32 bit VBA. (You may have noticed swVBAserver.exe in your Task
Manager.) Normally, if VBA and SolidWorks were both 32 bit or 64 bit, VBA can run inside the
SLDWORKS.EXE process. When this isnt the case, however, VBA must run out of process,
which also causes the API to run slightly slower. The out of process scenario is also what caused
the infamous issue of user forms appearing behind the SolidWorks application: it is the
swVBAserver.exe that owned the form, not SLDWORKS.EXE. In SolidWorks 2013, VBA does run
inside the SLDWORKS.EXE process, so the correct owner is identified and no additional code is
necessary. (Note: swVBAserver.exe is still used in SolidWorks 2013 and later, which is why you
will see it in the Task Manager, but not as a proxy server for 32 bit VBA. It is also used to drive
equation updates using IEquationMgr.)
If you want more resources on the technical aspects of the move to 64 bit, Id encourage you to
check out the following: