Search code examples
c#winapiintptr

Win api in C#. Get Hi and low word from IntPtr


I am trying to process a WM_MOUSEMOVE message in C#.

What is the proper way to get an X and Y coordinate from lParam which is a type of IntPtr?


Solution

  • Try:
    (note that this was the initial version, read below for the final version)

    IntPtr xy = value;
    int x = unchecked((short)xy);
    int y = unchecked((short)((uint)xy >> 16));
    

    The unchecked normally isn't necessary (because the "default" c# projects are unchecked)

    Consider that these are the definitions of the used macros:

    #define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
    #define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
    
    #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
    #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
    

    Where WORD == ushort, DWORD == uint. I'm cutting some ushort->short conversions.

    Addendum:

    one and half year later, and having experienced the "vagaries" of 64 bits .NET, I concur with Celess (but note that 99% of the Windows messages are still 32 bits for reasons of compatibility, so I don't think the problem isn't really big now. It's more for the future and because if you want to do something, you should do it correctly.)

    The only thing I would make different is this:

    IntPtr xy = value;
    int x = unchecked((short)(long)xy);
    int y = unchecked((short)((long)xy >> 16));
    

    instead of doing the check "is the IntPtr 4 or 8 bytes long", I take the worst case (8 bytes long) and cast xy to a long. With a little luck the double cast (to long and then to short/to uint) will be optimized by the compiler (in the end, the explicit conversion to int of IntPtr is a red herring... If you use it you are putting yourself at risk in the future. You should always use the long conversion and then use it directly/re-cast it to what you need, showing to the future programmers that you knew what you were doing.

    A test example: http://ideone.com/a4oGW2 (sadly only 32 bits, but if you have a 64 bits machine you can test the same code)