NabilS
NabilS

Reputation: 1421

How do I read the Win32 WM_MOVE lParam x,y coordinates in C#?

I am trying to read the lParam x and y coordinates from WM_MOVE win32 message and getting strange values. I need to extract them from the lParam IntPtr somehow.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms632631(v=vs.85).aspx

Thanks

Upvotes: 3

Views: 3474

Answers (3)

Jimi
Jimi

Reputation: 32278

In addition to what Simon Mourier already posted (which covers a number of standard macros), this method returns a Point() from a message.LParam.

MSDN suggests to use the GET_X_LPARAM and GET_Y_LPARAM macros (defined in WindowsX.h) to extract the coordinates, warning against the possible wrong results returned by the LOWORD and HIWORD macros (defined in WinDef.h), because those return unsigned integers.

These are the definitions of the suggested macros:

#define GET_X_LPARAM(lp)    ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp)    ((int)(short)HIWORD(lp))

What's important is that these values must be signed, since secondary monitors return negative values as coordinates.

public static Point PointFromLParam(IntPtr lParam)
{
    return new Point((int)(lParam) & 0xFFFF, ((int)(lParam) >> 16) & 0xFFFF);
}

Upvotes: 6

Simon Mourier
Simon Mourier

Reputation: 139065

.NET Reference source is a gold mine. In an internal System.Windows.Forms.NativeMethods+Util class you will find these helpers, that talk the same as WM_MOVE documentation (high-order word = HIWORD, low-order word = LOWORD, etc.)

public static int MAKELONG(int low, int high) {
    return (high << 16) | (low & 0xffff);
}

public static IntPtr MAKELPARAM(int low, int high) {
    return (IntPtr) ((high << 16) | (low & 0xffff));
}

public static int HIWORD(int n) {
    return (n >> 16) & 0xffff;
}

public static int HIWORD(IntPtr n) {
    return HIWORD( unchecked((int)(long)n) );
}

public static int LOWORD(int n) {
    return n & 0xffff;
}

public static int LOWORD(IntPtr n) {
    return LOWORD( unchecked((int)(long)n) );
}

public static int SignedHIWORD(IntPtr n) {
    return SignedHIWORD( unchecked((int)(long)n) );
}

public static int SignedLOWORD(IntPtr n) {
    return SignedLOWORD( unchecked((int)(long)n) );
}

public static int SignedHIWORD(int n) {
    int i = (int)(short)((n >> 16) & 0xffff);
    return i;
}

public static int SignedLOWORD(int n) {
    int i = (int)(short)(n & 0xFFFF);
    return i;
}

Upvotes: 2

Anders
Anders

Reputation: 101746

Coordinates in Windows messages are often two signed 16-bit numbers packed into a 32-bit number.

Ideally you should extract these as signed numbers emulating the GET_X_LPARAM/GET_Y_LPARAM macros:

IntPtr lparam = (IntPtr) 0xfffeffff; // -1 x -2 example coordinate
uint lparam32 = (uint) lparam.ToInt64(); // We want the bottom unsigned 32-bits
short x = (short) (((uint)lparam32) & 0xffff);
short y = (short) ((((uint)lparam32) >> 16) & 0xffff);  

Console.WriteLine(string.Format("coordinates: {0} x {1}", x, y));

In the case of WM_MOVE you could also extract them as unsigned numbers (ushort) since the client area will never be negative.

Upvotes: 0

Related Questions