Различие в вызовах функций WinAPI в зависимости от версий Windows и Office

Поскольку в приложениях Office 2010 встроен другой VBA (VBA7), в отличие от ранних версий Excel, требуется предусмотреть в коде макросов различных варианты вызова API-функций Windows, чтобы они сохранили свою работоспособность при работе в любой версии Office.

Кроме того, в 64-битных Windows синтаксис вызова функций WinAPI тоже немного отличается от 32-битных систем.

В общем случае, код, корректно работающий в 64-битной Windows, будет выглядеть примерно так:

#If Win64 Then
    Declare Function MyMathFunc Lib "User32" (ByVal N As LongLong) As LongLong
#Else
    Declare Function MyMathFunc Lib "User32" (ByVal N As Long) As Long
#End If

А это код, который не будет выдавать ошибку при работе в Office 2010:

#If VBA7 Then
    Declare PtrSafe Sub MessageBeep Lib "User32" (ByVal N AS Long)
#Else
    Declare Sub MessageBeep Lib "User32" (ByVal N As Long)
#End If

Как же добиться работоспособности кода на любом компьютере?

А вот как: добавляйте описания функций WinAPI для всех возможных конфигураций. Например, ниже приведён универсальный код для вызова WinAPI функции URLDownloadToFile:

#If Win64 Then
    #If VBA7 Then    ' Windows x64, Office 2010
        Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                (ByVal pCaller As LongLong, ByVal szURL As String, ByVal szFileName As String, _
                 ByVal dwReserved As LongLong, ByVal lpfnCB As LongLong) As LongLong
    #Else    ' Windows x64,Office 2003-2007
        Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                                           (ByVal pCaller As LongLong, ByVal szURL As String, ByVal szFileName As String, _
                                            ByVal dwReserved As LongLong, ByVal lpfnCB As LongLong) As LongLong
    #End If
#Else
    #If VBA7 Then    ' Windows x86, Office 2010
        Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, _
                 ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
    #Else    ' Windows x86, Office 2003-2007
        Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                                           (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, _
                                            ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
    #End If
#End If

Более подробно тема описана на сайте Microsoft

Ещё один пример - универсальная декларация функции GetTickCount:

#If Win64 Then
    #If VBA7 Then    ' Windows x64, Office 2010
        Declare PtrSafe Function GetTickCount Lib "Kernel32" () As LongLong
    #Else    ' Windows x64,Office 2003-2007
        Declare Function GetTickCount Lib "Kernel32" () As LongLong
    #End If
#Else
    #If VBA7 Then    ' Windows x86, Office 2010
        Declare PtrSafe Function GetTickCount Lib "Kernel32" () As Long
    #Else    ' Windows x86, Office 2003-2007
        Declare Function GetTickCount Lib "Kernel32" () As Long
    #End If
#End If


(добавлено позже)


Вообще, код достаточно писать в 2 вариантах (ветку Win64 не обязательно прописывать)

Для функций GetKeyState и Sleep, код будет выглядеть так:
(чтобы работало во всех версиях Office и Windows)

#If VBA7 Then    '  Office 2010
    Declare PtrSafe Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
    Declare PtrSafe Sub Sleep Lib "Kernel32" (ByVal dwMilliseconds As Long)
#Else    '  Office 2003-2007
    Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
    Declare Sub Sleep Lib "Kernel32" (ByVal dwMilliseconds As Long)
#End If

----------------
(добавлено ещё позже)

Ну а ещё правильнее будет написать так:
(c использованием LongPtr для версий Office, начиная с 2010)

#If VBA7 Then    '  Office 2010-2013
    Declare PtrSafe Function Beep Lib "kernel32" (ByVal dwFreq As LongPtr, ByVal dwDuration As LongPtr) As LongPtr
#Else    '  Office 2003-2007
    Declare Function Beep Lib "kernel32" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long
#End If