В системном программировании под Windows часто используется приём, который позволяет хранить в одной переменной сразу два значения. Это позволяет, к примеру, при посылке сообщения окну с помощью функций SendMessage или PostMessage, передать сразу четыре параметра, в то время, как зти функции поддерживают передачу только двух параметров. Реализуется это путём записи в 32-битовую переменную (длинное целое) двух 16-битовых значений (короткое целое, не превышающее 0хffff).
В языке программирования С для создания такого числа применяется макрос MAKELONG:
#define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))
а для извлечения значений из старших и младших 16-ти разрядов, соответственно, HIWORD и LOWORD:
#define HIWORD(l) ((WORD) (((DWORD) (l) >> 16) & 0xFFFF))
#define LOWORD(l) ((WORD) (l))
Как известно, Visual Basic 6 не поддерживает операции битового сдвига (>>). В литературе предлагается немало способов обойти это ограничение. Все они ненадёжны, очень часто дают ошибки переполнения, или работают некорректно.
Наиболее надёжным и безотказным выходом из положения является использование API-функции CopyMemory, производящей прямое копирование одного участка оперативной памяти компьютера в другой. Для тех, кто знаком с языком программирования C++, добавим, что это обёртка над C-runtime функцией memcpy. В неё передаётся три параметра: адрес назначения, адрес источника, и количество байт, которое нужно скопировать. На VB6 эта функция объявляется так:
Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (ByVal Destination As Long, _
ByVal Source As Long, ByVal Length As Long)
Для получения адреса переменных используется недокументированная VB-функция VarPtr:
Function VarPtr(Ptr As Any) As Long
Переведём макросы на язык VB 6:
Public Function MAKELONG( _
ByVal wLow As Integer, _
ByVal wHigh As Integer) As Long
Dim retVal As Long, b(3) As Byte
CopyMemory ByVal VarPtr(b(0)), ByVal VarPtr(wLow), 2
CopyMemory ByVal VarPtr(b(2)), ByVal VarPtr(wHigh), 2
CopyMemory ByVal VarPtr(retVal), ByVal VarPtr(b(0)), 4
MAKELONG = retVal
End Function
Public Function HIWORD(ByVal dwValue As Long) As Integer
Dim retVal As Integer, b(3) As Byte
CopyMemory ByVal VarPtr(b(0)), ByVal VarPtr(dwValue), 4
CopyMemory ByVal VarPtr(retVal), ByVal VarPtr(b(2)), 2
HIWORD = retVal
End Function
Public Function LOWORD(ByVal dwValue As Long) As Integer
Dim retVal As Integer, b(3) As Byte
CopyMemory ByVal VarPtr(b(0)), ByVal VarPtr(dwValue), 4
CopyMemory ByVal VarPtr(retVal), ByVal VarPtr(b(0)), 2
LOWORD = retVal
End Function
Автор - Цзяофань
|