Using PtrSafe and LongPtr for Windows API declarations.

Declaring Windows API functions in Excel VBA allows you to access low-level operating system features, such as registry keys, hardware timers, and user-interface manipulation. In modern 64-bit versions of Office, Windows API declarations require two critical keywords: PtrSafe and LongPtr.

How Do PtrSafe and LongPtr Work in VBA Windows API Declarations?

PtrSafe informs the VBA compiler that an API declaration is compatible with 64-bit Office. LongPtr is a variable type that scales automatically: it occupies 8 bytes on 64-bit Office to store memory pointers and window handles safely, and 4 bytes on 32-bit Office. Values that represent pure numbers or flags must remain standard 32-bit Long variables.

Quick Syntax Reference

Here is a side-by-side pattern for declaring a Windows API function (in this case, SendMessage):

#If VBA7 Then
    ' Compatible with Office 2010+ (Scales automatically in 32-bit and 64-bit)
    Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" ( _
        ByVal hWnd As LongPtr, _
        ByVal wMsg As Long, _
        ByVal wParam As LongPtr, _
        ByVal lParam As LongPtr) As LongPtr
#Else
    ' Legacy 32-bit Office fallback (Office 2007 and earlier)
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
        ByVal hWnd As Long, _
        ByVal wMsg As Long, _
        ByVal wParam As Long, _
        ByVal lParam As Long) As Long
#End If

Detailed Mechanics of PtrSafe and LongPtr

The Purpose of PtrSafe

PtrSafe is a compiler assertion keyword. In 64-bit Office, omitting PtrSafe causes an immediate compilation failure: 32-bit vs. 64-bit: Fixing “The code in this project must be updated for use on 64-bit systems.”.

Adding PtrSafe tells the compiler: “I have verified the data types of the pointers and handles in this declaration.”

How LongPtr Solves the Pointer Width Problem

Before Office 2010, memory addresses and Windows handles were stored in standard 4-byte Long variables. When 64-bit Office was released, memory addresses expanded to 8 bytes.

Microsoft introduced LongPtr as an alias data type:

  • In 32-bit Office, LongPtr resolves internally to a standard 4-byte Long.
  • In 64-bit Office, LongPtr resolves internally to an 8-byte LongLong.

Because LongPtr adapts based on the host environment, you can write a single declaration that runs in both 32-bit and 64-bit versions of modern Office without manual modifications.


Identifying Which Variables Need LongPtr

A frequent cause of hard Excel crashes after a 64-bit migration is converting the wrong data types.

What to Change to LongPtr:

  • Handles: Any variable prefixed with h (such as hWnd, hdc, hProcess, hIcon, hKey).
  • Pointers: Any parameter expecting a memory address or structure pointer (such as lpString, lpBuffer, lpOverlapped).
  • Pointer-sized integers: Windows messaging parameters that pass addresses, such as wParam and lParam.
  • Return Values: Any function that returns a pointer or handle (such as FindWindow, GetWindowLongPtr, GetDC).

What Must Remain Long:

  • Counts and Durations: Timeouts, millisecond intervals (dwMilliseconds), loop counters.
  • Flags and Enumerations: Bitmask flags (dwFlags, uType).
  • Dimensions and Coordinates: Screen positions (x, y, cx, cy, nWidth, nHeight).
  • Return Codes: Success/failure booleans or error codes returning a 32-bit integer (BOOL, HRESULT).

Common API Upgrade Examples

Example 1: GetTickCount vs. GetTickCount64

GetTickCount returns milliseconds elapsed as a 32-bit integer. It does not use pointers:

' Correct: No parameters are pointers, so only PtrSafe is added
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long

Example 2: Window Positioning with SetWindowPos

Notice how the handle is updated to LongPtr, while the coordinate and flag parameters remain standard Long:

Private Declare PtrSafe Function SetWindowPos Lib "user32" ( _
    ByVal hWnd As LongPtr, _
    ByVal hWndInsertAfter As LongPtr, _
    ByVal X As Long, _
    ByVal Y As Long, _
    ByVal cx As Long, _
    ByVal cy As Long, _
    ByVal uFlags As Long) As Long

Example 3: User-Defined Types (UDTs) with Pointers

If an API function accepts a custom Type struct, update the pointer fields inside the struct definition as well:

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private Type MSG
    hWnd As LongPtr      ' Updated: Window handle
    Message As Long     ' Unchanged: Message ID
    wParam As LongPtr   ' Updated: Can hold a pointer
    lParam As LongPtr   ' Updated: Can hold a pointer
    Time As Long        ' Unchanged: Timestamp
    pt As POINTAPI      ' Unchanged: Coordinates
End Type

Troubleshooting Crashes After Conversion

If updating your API calls results in sudden Excel crashes or silent failures:

  1. Verify ByVal vs. ByRef: Windows APIs generally expect parameters passed ByVal unless explicitly documented to take a pointer to a pointer. Omitting ByVal defaults to ByRef in VBA, passing an address instead of the value and crashing Excel.
  2. Handle Special Functions (GetWindowLongPtr): On 64-bit Windows, GetWindowLong is redirected to GetWindowLongPtr. Calling the legacy name in 64-bit Office can corrupt the stack: #If VBA7 Then Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" ( _ ByVal hWnd As LongPtr, _ ByVal nIndex As Long) As LongPtr #Else Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" ( _ ByVal hWnd As Long, _ ByVal nIndex As Long) As Long #End If
  3. Audit Data Conversions: Ensure you are not forcing incompatible string or numeric data types into pointers. To troubleshoot type conflicts, see Runtime Error 13: Type Mismatch (Trying to perform math on a string variable)..
  4. Clean Error Trapping: Wrap test executions with explicit error monitoring rather than suppressing failures with On Error Resume Next. Review Using On Error Resume Next vs. On Error GoTo 0 (The right way)..
  5. System Compatibility Framework: If you are managing wide enterprise deployments with mixed versions, refer to the VBA Environment & System Guide: Fixing Security, Version, and Compatibility Errors.