Различие в вызовах функций 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
|