MonitorFromPoint works in x86 - Sometimes in x64


I am writing some declares for working with multiple monitors and am running into an issue when retrieving the handle of a monitor based on a global mouse position. If the mouse is in another screen then it will display the monitor handle (hdlMonitor) where the mouse is located. The program works great in x86. When running in Xojo 2017 r2.1, the monitor handle only appears when the mouse y-value is seperated by values of 32.

Example: The windows handle will appear in x64 mode with the following y-mouse values:
0, 1, 2,
32, 33, 34,
64, 65, 66,
96, 97, 98,
multiples of 32 — etc…

If the y-mouse value is between 3-31, or 35-63, etc, then the handle is not shown. It works perfectly in x86 though.

Here is the code which is in the Timer1 Action event (needed for global mouse values):

[code]Sub Action() Handles Action
//Create a MyPoint variable from the POINTAPI Structure
Dim MyPoint as POINTAPI
//Get the current global mouse position
MyPoint.X = System.MouseX
MyPoint.Y = System.MouseY

//Show the position in the TextArea1 Control
TextArea1.Text = "Global Mouse Coordinates: X: " + MyPoint.X.ToText + ", Y: " + System.MouseY.Totext + EndOfLine


//Return the handle to the monitor nearest the current cursor position
Dim hdlMonitor as Integer = MonitorFromPoint(MyPoint, MONITOR_DEFAULTTONEAREST)
TextArea1.Text = TextArea1.Text + "Monitor Handle: " + hdlMonitor.ToText + EndOfLine
End Sub

Here is an example project download link:

There is likely something simple that I am missing, and the code is quite simple… Any helpful thoughts on what it could be?


Edit: changed y-mouse value from 35-64 to 35-63.

You do realize you can determine the screen without declares ?

Each screen has a rect that is its logical position

And since its a rect you can easily test if a point is in the rect

No, I didn’t realize this. I looked through the screen object at Xojo Screen, and also found Screen Count. I couldn’t seem to find the correct google search. Could I ask for a link to this helpful information?

There is so much that the Xojo language can do, its just a matter of trying to find out where :slight_smile:

It does? I see discrete coordinate parameters, but a RECT structure would be nice

Top, Left, Width and Height

[quote=351497:@Greg O’Lone]

Top, Left, Width and Height[/quote]

but that is NOT a RECT Structure, which is what I thought Norman was inferring existed.

My bad.
Windows have bounds which is a rect
Screens only have top left width height
But its a one liner to turn that into a rect and use the rect

dim r as REalbasic.Rect = new REALBasic.Rect ( screen(x).left, screen(x).top, screen(x).width, screen(x).height )

Here is a working version:

From the testing I have performed, its something related to the way the POINTAPI structure is handled in 64bit as compared with 32bit even though the data types do not change size (they are fixed at Int32).

I’ve had to use a MamoryBlock to get around this problem and it seems to be working ok. I’m not great with memoryblocks yet so pulling out a UInt64Value might cause an issue (I dont know if it does anything with the data when its extracted), I’m not sure, please advise if you are reading this and have the time/inclination.

I have tested the struct in other languages and it doesnt change size when switching between 64/32 bit so its definitely specified correctly.

If someone can shed some more light on the structure issue, I would appreciate it.

Might this be a bug?

Thanks for looking into this Julian.

I created a feedback report last night: <> and my temporary workaround looks like it is not working on all computers in x64 mode.

I’ll be back on my development computer tonight and will test the code using a memoryblock, as it is 9:25 am here.

Hi Julian,

You are on the right track. After spending some time with this, it looks like the Structure is converting the data from a little endian to big endian. The reason why a memory block works is because the data remains in the same endianess. Below is a demonstration program - press OK to get the data.

A decimal value of 287 is 0000 011F in Int32 Big Endian (X)
A decimal value of 228 is 0000 00E4 in Int32 Big Endian (Y)

Windows is a Little Endian System, and putting the values 287, 228 as an Integer should store the Int32 data as 1F01 0000 E400 0000. To make sure the data is in little endian format, the memoryblock is assigned LittleEndian to be true, and the UInt64 value (as you suggested) is 0000 E400 0000 011F which is big endian.

Data in the memory block was then converted to Big Endian (LittleEndian=False), and the value 287, 228 was actually 1F01 0000 E400 0000 which is incorrectly little endian. The Big Endian value should be 0000 011F 0000 00E4.

I think I got this right, and I need a beer after all of the byte swapping :slight_smile:

Interesting Eugene, I’ll keep an eye on the feedback ticket.

After (over) thinking about this issue last night, solution shows that the Monitorfrompoints method works correctly in x64 and x86 versions with a memoryblock and not a structure.

I may need to create a new case to show that the underlying reason is a structure bug, and not a declare issue.

Have you tried adding the StructureAlignment attribute with a value of 0? This causes the compiler to lay out the structure “naturally”, according to the platform’s rules.

Hi Joe,

Thanks for the suggestion. I tried your suggestion with the StructureAlignment setting of zero, along with other alignment settings, and even tried LittleEndian as true, and nothing seems to work on x64 and it seems to work well on x86 in Windows.

Do you happen to have any other suggestions with Little Endianness for a structure?

Thanks :slight_smile:

I just came across this old thread, and the solution seems to be to force the data into a Uint64 first:

#if Target32Bit
  Declare Function MonitorFromPoint Lib "User32" (pt As Point, dwFlags As UInt32) As Integer
  monitorID = MonitorFromPoint(cursorPos, 2)
#elseif Target64Bit
  Declare Function MonitorFromPoint Lib "User32" (pt64 As Uint64, dwFlags As UInt32) As Integer
    dim tmp as uint64 = Bitwise.ShiftLeft(cursorPos.x,32) or cursorPos.Y // create a temporary Uint64 to pass by value
  monitorID = MonitorFromPoint(tmp, 2)

I think the suggestions that this is a compiler bug are likely true - when a small Structure is passed ByVal, it’s not getting on the stack (or into a register) correclty under the 64 bit compiler or linker. I’m still seeing this in 2019R1.1, for what it’s worth.

there is a bug report about passing structures byval
I submitted this <> since the other is private so no one can see it OR sign on to it :frowning:

this had to do with calling another xojo method with a byval structure so I’m not sure if that affects this case or not

Its been an issue for over two years now <> which is why I still don’t recommend anyone use 64bit in windows. It broke in the transition from 2017r3 to 2018r1 and hasn’t been fixed since which is really concerning.

[quote=492429:@Norman Palardy]there is a bug report about passing structures byval
I submitted this <> since the other is private so no one can see it OR sign on to it :frowning:

this had to do with calling another xojo method with a byval structure so I’m not sure if that affects this case or not[/quote]

<> is the private ticket, I’ve asked for the ticket to be made public as the person I helped has has a two month lead on the knowledge in the ticket. However the byref issue doesn’t fix this problem so its probably loosely related and is a stack/register issue as Michael mentions as I’ve not spent (wasted?) the time looking.

To overcome problems with Declares, we did ourselves a few newer Declare classes via MBS Xojo Plugins:

Maybe we can help you with some declares?