How does GET_X_LPARAM() differ from GetCursorPos() when DPI scaling is done?

1.1k views Asked by At

I have an application that creates a windows tray icon. When the user right clicks on it, a context menu is displayed. The application works fine until DPI scaling is done from control panel. For eg. when DPI scaling is set to 150% (Scaling value when I logged in), the context menu will be shown correctly, but when I change DPI scaling to 125% (without logging out and logging back again - after logging out and logging in again they agree), the context menu gets displaced, and is shown at a position far away from the tray icon. This does not happen if I use GetCursorPos() instead of GET_X_LPARAM(wParam), and GET_Y_LPARAM(wParam) to get mouse coordinate.

MSDN documentation on NOTIFYICONDATA (https://msdn.microsoft.com/en-us/library/windows/desktop/bb773352(v=vs.85).aspx) data structure says that GET_X_LPARAM(wParam), and GET_Y_PARAM(wParam), inside the callback function which handles uCallbackMessage should give X, and Y coordinates of the right-mouse-button click event (which is used to invoke tray icon's context menu). This does not happen when DPI is changed in the manner written above. GetCursorPos() however continues to give correct value.

I feel that they should always report the same value.

EDIT 1 - Assume that after a right click, the mouse hasn't moved, in which case both should give the same coordinates.

EDIT 2 - Repro (Information regarding reproducing the bug)

Have a look at the following open source project, Picotorrent. In NotifyIconController.cpp::NotifyIconController::Execute() , I added the following lines of code to print the values returned by GET_X_LPARAM(), and GetCursorPos() (highlighted code in the image).

    TCHAR debug_string[50];
    _stprintf_s(debug_string,sizeof(debug_string), _T("\n\n[wParam      :(x,y)=(%d,%d)]\n"), GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam));
    OutputDebugString(debug_string);

    POINT pt;
    GetCursorPos(&pt);
    _stprintf_s(debug_string,sizeof(debug_string),_T("[GetCursorPos:(x,y)=(%d,%d)]\n"), pt.x, pt.y);
    OutputDebugString(debug_string);

code added to check values returned by GET_X_LPARAM() and GetCursorPos()

The program, Picotorrent when run, creates a tray icon. When user right clicks on the tray icon, a context menu is shown on the location of mouse pointer at the time of click. As of now, to display the context menu the X,Y coordinates of the click are being obtained using GET_X_LPARAM(wParam), and GET_Y_LPARAM(wParam).

See the following screenshots showing the position of context menu with respect to the tray icon at different DPI scaling values.

The following image shows the position of the context menu when the DPI scaling is 150%. This was the DPI scaling value when I logged in to the system.

context menu at 150% DPI scaling

The following image shows the position of the context menu when DPI scaling is changed to 125%. Notice that windows is telling me to log out, and log back in. But since our task here is to study why GET_X_LPARAM(), and GetCursorPos() aren't showing same value (whether right or wrong, doesn't matter). Also, notice that the context menu is no longer displayed near the tray icon. Remember that here I am using GET_X_LPARAM(wParam), and GET_Y_LPARAM(wParam) to get X, and Y coordinates for displaying the menu, and not GetCursorPos().

context menu at 125% DPI scaling

Now, let us see the output in the debugger's output window.

[wParam      :(x,y)=(1539,1045)]
[GetCursorPos:(x,y)=(1539,1045)]


[wParam      :(x,y)=(1606,1054)]
[GetCursorPos:(x,y)=(1927,1265)]

Also, see the following screenshot.

GET_X_LPARAM(), and GetCursorPos() return different values when DPI scaling is changed

From the output we can clearly see that initially GET_X_LPARAM(), and GetCursorPos() agree on the values of coordinates, but when scaling value is changed, they do not.

0

There are 0 answers