-2

I have a process that sets a SetWindowsHookEx(WH_MOUSE_LL, , ,) right click hook. My process is set to DPI system aware on Window 10.0.10586 at 150% scaling on both monitors. This was set by calling SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE).

My problem scenario is e.g. Office 2007 is DPI unaware, so let's place MS Word on the right quarter of the screen. Right click just above the task bar in the bottom right and the mouse hook sends coordinates of 1279, 675 - scaled to Word. Then I right click on visual studio (DPI aware), nearly three quarters across the screen and the mouse hook sends me coordinates of e.g. 1279, 1008 from Visual Studio. So if I clicked higher up the screen I would potentially get the same 1279, 675.

My process is trying to determine which window is at the point by calling the WindowFromPoint API, but this will clearly fail in this scenario as two applications "share" the same point.

Is it possible to force the mouse hook to always send raw physical coordinates instead of those scaled to the DPI unaware application? and if so, how? Alternately, is there some other way of determining the hWnd or processID from the mouse hooks?

birdwes
  • 127
  • 10

2 Answers2

0

Microsoft fixed it in 10.0.14393.

You should have nothing in your client's network now with a lower build number unless they are on LTSB 10.0.10240.

This is the solution: DPI aware screen capture

birdwes
  • 127
  • 10
-1

Because the process is DPI aware, calling GetCursorPos() in the mouse hook callback handler always fetches raw physical coordinates instead of logical coordinates scaled to the application. Simply discard the coordinates passed to the mouse callback.

Added 30/09/2016

It's worth nothing that whilst GetMessagePos seems a likely, candidate it only returns the correct coordinates if the process is not dpi virtualised.

e.g.

VOID MessagePump()
{
    MSG     messageGet = { 0 };
    DWORD   dwPos;
    POINTS  p;

    while (GetMessage(&messageGet,NULL,0,0)) 
    {
        dwPos = GetMessagePos();
        p = MAKEPOINTS( dwPos );
        TranslateMessage( &messageGet );
        DispatchMessage( &messageGet );
    }
}

The Mouse callback handler gets called during the GetMessage() call, but this does not fetch correct physical coordinates where DPI virtualisation is active for the process. e.g. physical x = 1909, y = 1072 comes back as 1091, 612 with 175% scaling, which though arithmetically correct, is not what was required.

birdwes
  • 127
  • 10
  • Sounds like a bad idea. The cursor might be elsewhere by the time you call GetCursorPos. – David Heffernan Sep 24 '16 at 16:04
  • It's the best I can think of so far, and seems to be near instantaneous, but I'm open to any better suggestions. – birdwes Sep 24 '16 at 16:11
  • 1
    [GetMessagePos](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644938.aspx) is probably a better fit. – IInspectable Sep 24 '16 at 21:48
  • I tried GetMessagePos today and the results are useless. They do not correspond at all. – birdwes Sep 25 '16 at 11:18
  • Just a side-note, what is bizarre is that this behaviour is completely different to Windows 7, which always gives raw physical coordinates, regardless of whether the process is DPI virtualised or not. – birdwes Sep 25 '16 at 11:47
  • 1
    Seeing that [SetProcessDpiAwareness](https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122.aspx) was introduced in Windows 8.1 makes a change in behavior relative to Windows 7 the expected result. Since we cannot see your code, there's no way to know, whether you are extracting the mouse position properly. The documentation tells you how to do it. – IInspectable Sep 25 '16 at 18:09