WM_MOUSEMOVE LParam переполнение младшего разряда
Когда я получаю сообщение WM_MOUSEMOVE в WndProc, lParam содержит координаты курсора. Я перевожу этот параметр в Point
состав:
Friend Shared Function LParamToPoint(ByVal lParam As IntPtr) As Point
Return New Point(LOWORD(lParam.ToInt32()), HIWORD(lParam.ToInt32()))
End Function
Friend Shared Function HIWORD(ByVal value As Integer) As Short
Return CShort((value >> 16))
End Function
Friend Shared Function LOWORD(ByVal value As Integer) As Short
Return CShort((value And UShort.MaxValue))
End Function
Моя проблема в том, что, когда координата x курсора становится отрицательной, функция LOWORD завершается с ошибкой переполнения. Согласно MSDN вы должны использовать макросы GET_X_LPARAM и GET_Y_LPARAM, а не макросы HI/LO WORD. Но в vb.net таких функций нет.
Так что делать?
1 ответ
Проверка переполнения действительно мешает здесь. Лучший способ решить эту проблему - объявить профсоюз. Объединение - это структура, которая имеет перекрывающиеся значения. Что элегантно позволяет накладывать IntPtr поверх элементов структуры, имеющих тип Short. Преобразование выполняется очень быстро и не может вызвать исключение переполнения.
Добавьте новый модуль в ваш проект, назовите его NativeMethods и сделайте так:
Imports System.Runtime.InteropServices
Imports System.Drawing
Module NativeMethods
<StructLayout(LayoutKind.Explicit)> _
Public Structure LParamMap
Public Sub New(value As IntPtr)
lparam = value
End Sub
Public Shared Widening Operator CType(value As LParamMap) As Point
Return New Point(value.loword, value.hiword)
End Operator
<FieldOffset(0)> Public lparam As IntPtr
<FieldOffset(0)> Public loword As Short
<FieldOffset(2)> Public hiword As Short
End Structure
End Module
Я добавил оператор преобразования для Point, потому что это тот, который вы действительно хотите. Некоторый тестовый код, который осуществляет это:
Imports System.Drawing
Imports System.Diagnostics
Module Module1
Sub Main()
Debug.Assert(BitConverter.IsLittleEndian)
Dim test As New LParamMap(New IntPtr(-1))
Debug.Assert(test.loword = -1)
Debug.Assert(test.hiword = -1)
Dim pos As Point = test
Debug.Assert(pos = New Point(-1, -1))
End Sub
End Module
Теперь он становится очень простым однострочником, скажем, в переопределении метода WndProc() формы:
Protected Overrides Sub WndProc(ByRef m As Windows.Forms.Message)
If m.Msg = &H200 Then
Dim pos As Point = New LParamMap(m.LParam)
'' etc...
End If
MyBase.WndProc(m)
End Sub