When i receive a WM_MOUSEMOVE message in WndProc the lParam contains the cursor coordinates. I translate this parameter into a Point
structure:
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
My problem is that when the x-coordinate of the cursor becomes negative the LOWORD function fails with an overflow exception. According to MSDN you should use the GET_X_LPARAM and GET_Y_LPARAM macros not the HI/LO WORD macros. But no such functions are available in vb.net.
So what to do?
Overflow checking really gets in the way here. The best way to tackle this problem is by declaring a union. A union is a structure that has overlapping values. Which elegantly allows you to overlay an IntPtr on top of structure members that have type Short. The conversion is extremely fast and cannot throw an overflow exception.
Add a new Module to your project, name it NativeMethods and make it look like this:
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
I threw in a conversion operator for Point since that's the one you really want. Some test code that exercises this:
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
It now becomes a very simple one-liner in, say, an override of a form's WndProc() method:
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