Codejock Forums Homepage
Forum Home Forum Home > Codejock Products > Visual C++ MFC > Docking Pane
  New Posts New Posts RSS Feed - Cannot drag panels to other monitor with other DPI
  FAQ FAQ  Forum Search   Events   Register Register  Login Login

Cannot drag panels to other monitor with other DPI

 Post Reply Post Reply
Author
Message
andredevries View Drop Down
Newbie
Newbie


Joined: 22 June 2018
Location: Netherlands
Status: Offline
Points: 5
Post Options Post Options   Thanks (0) Thanks(0)   Quote andredevries Quote  Post ReplyReply Direct Link To This Post Topic: Cannot drag panels to other monitor with other DPI
    Posted: 22 June 2018 at 8:55am
Multiple 4K screens, some with 100% scaling, others with scaling other than 100. Can't move any of the windows across to the other screens if the scaling is different. They get stuck; they jump to a different location on the screen it comes from. See this short video showing the issue:
https://www.youtube.com/watch?v=IFiAtYSNl30

This happens when the "main" monitor is to the right of the "second" monitor, so the second monitor will have negative horizontal co-ordinates. Now, if the two monitors have different DPI scale settings then none of our "Floating Tool Panel" windows, that are based on a CodeJock control for dockable floating panels, can be dragged into the left panel (i.e the second monitor with negative co-ordinates).

Note: When you drag the floating panel towards the left monitor, Windows will send a notification to it when more than 50% of the panel is in the left monitor (WM_DPICHANGED). The notification is to tell the panel that it is now dragged into a monitor that has a different DPI Scale. It seems that the CodeJock Docking panel should respond to this notification in some way and it seems it is not doing that, or incorrectly?

I reproduced the issue using Codejock MFC 18.3.0.
I hope this problem can be solved or someone can tell me how to fix it myself. Thanks.

Back to Top
olebed View Drop Down
Admin Group
Admin Group
Avatar

Joined: 01 July 2014
Location: Ukraine
Status: Offline
Points: 841
Post Options Post Options   Thanks (0) Thanks(0)   Quote olebed Quote  Post ReplyReply Direct Link To This Post Posted: 22 June 2018 at 11:50am
Hello,

I think this problem related to new macros XTP_POINT_FROM_LPARAM
It constructs wrong CPoint if .x or .y from lparam are negative.
I have investigated that negative points are only in method CXTPCommandBarsFrameHook::OnHookMessage()

So as workaround you can delete this macros from CXTPCommandBarsFrameHook::OnHookMessage 
because CPoint has own constructor with lparam as parameter CPoint(LPARAM dwPoint) throw();

CPoint point = XTP_POINT_FROM_LPARAM(lParam);
>
CPoint point(lParam);

Regards,
Oleksandr Lebed  
Back to Top
olebed View Drop Down
Admin Group
Admin Group
Avatar

Joined: 01 July 2014
Location: Ukraine
Status: Offline
Points: 841
Post Options Post Options   Thanks (0) Thanks(0)   Quote olebed Quote  Post ReplyReply Direct Link To This Post Posted: 22 June 2018 at 12:11pm
However if you say that bug with DockingPane control,  than I can say that bug the same as with XTP_POINT_FROM_LPARAM - signed/unsigned casting.
Back to Top
Sven View Drop Down
Senior Member
Senior Member


Joined: 21 August 2003
Location: Germany
Status: Offline
Points: 125
Post Options Post Options   Thanks (0) Thanks(0)   Quote Sven Quote  Post ReplyReply Direct Link To This Post Posted: 23 June 2018 at 2:18am
I have changed XTP_POINT_FROM_LPARAM to

#define XTP_POINT_FROM_LPARAM(lParam) CPoint(static_cast<short>(LOWORD(lParam)), static_cast<short>(HIWORD(lParam)))

The original non-typecast macro is also the reason, that buttons in themed frames (minimize, maximize, restore) can't be clicked if the main window is on the left monitor with negative coordinates.
Back to Top
olebed View Drop Down
Admin Group
Admin Group
Avatar

Joined: 01 July 2014
Location: Ukraine
Status: Offline
Points: 841
Post Options Post Options   Thanks (0) Thanks(0)   Quote olebed Quote  Post ReplyReply Direct Link To This Post Posted: 23 June 2018 at 4:41am
Sven, yes hit test for frame buttons doesn't work due to signed-unsigned cast. But CPoint class has own constructor with initialization with LParam.
Back to Top
andredevries View Drop Down
Newbie
Newbie


Joined: 22 June 2018
Location: Netherlands
Status: Offline
Points: 5
Post Options Post Options   Thanks (0) Thanks(0)   Quote andredevries Quote  Post ReplyReply Direct Link To This Post Posted: 25 June 2018 at 4:47am
Thanks for your responses.
However, I still have difficulty to come to a solution. It sounds plausible that it may be a signed/unsigned casting issue, and it might be a conversion issue between LPARAM and Point. But when I search in the sources on XTP_POINT_FROM_LPARAM, I find nothing. Where is that macro defined? I could not find anything similar that may be a problem. Any more ideas?

Back to Top
olebed View Drop Down
Admin Group
Admin Group
Avatar

Joined: 01 July 2014
Location: Ukraine
Status: Offline
Points: 841
Post Options Post Options   Thanks (0) Thanks(0)   Quote olebed Quote  Post ReplyReply Direct Link To This Post Posted: 25 June 2018 at 5:37am
XTP_POINT_FROM_LPARAM introduced in v18.4.

Unfortunately I can't reproduce your problem. Can you provide sample ?
I have monitors configuration of work station as you described except 4k (only fullHD).
Back to Top
andredevries View Drop Down
Newbie
Newbie


Joined: 22 June 2018
Location: Netherlands
Status: Offline
Points: 5
Post Options Post Options   Thanks (0) Thanks(0)   Quote andredevries Quote  Post ReplyReply Direct Link To This Post Posted: 25 June 2018 at 8:17am
Aha, I am using v18.3. I just tested the DockingPane samples, they work fine. Seems like I am doing something wrong here.
Unfortunately it is not so easy to isolate sources to provide an example (and I am not that familiar with it).
Could you tell me what gets triggered when moving a docking pane to a screen with other DPI?
Back to Top
olebed View Drop Down
Admin Group
Admin Group
Avatar

Joined: 01 July 2014
Location: Ukraine
Status: Offline
Points: 841
Post Options Post Options   Thanks (0) Thanks(0)   Quote olebed Quote  Post ReplyReply Direct Link To This Post Posted: 25 June 2018 at 9:03am
see method  CXTPDockingPaneMiniWnd::UpdatePosition()

also for drawing used 
ToolkitPro1840UD.dll!CXTPDockingPaneOffice2013Theme::DrawFloatingFrame(CDC * pDC, CXTPDockingPaneMiniWnd * pPane, CRect rc) Line 298 C++
ToolkitPro1840UD.dll!CXTPDockingPaneMiniWnd::OnNcPaint() Line 699 C++
Back to Top
andredevries View Drop Down
Newbie
Newbie


Joined: 22 June 2018
Location: Netherlands
Status: Offline
Points: 5
Post Options Post Options   Thanks (0) Thanks(0)   Quote andredevries Quote  Post ReplyReply Direct Link To This Post Posted: 25 June 2018 at 10:58am
Thanks, but does not help so far. Debugger does not stop at any of those methods.
Will have to search further myself I guess. Thanks anyway.
Back to Top
Cedric_ar View Drop Down
Groupie
Groupie


Joined: 04 September 2012
Status: Offline
Points: 19
Post Options Post Options   Thanks (0) Thanks(0)   Quote Cedric_ar Quote  Post ReplyReply Direct Link To This Post Posted: 31 October 2018 at 1:23pm
hi,

I have the same issue. it's realy hard to switch pane to a different monitor with a different DPI. I have a monitor in 125% and another in 100%. 

I try to remove XTPWM_DOCKINGPANE_NOTIFY to test if the problem is on my side, but i have the same issue. the mainframe inherited from 

class CMainFrame:public CXTPMDIFrameWnd, CXTPCommandBarsFrameHook

i initialize the dockingpane manager like this

kPaneManager = new CXTPDockingPaneManager();
kPaneManager->InstallDockingPanes( AfxGetApp()->m_pMainWnd );
kPaneManager->SetTheme( /*xtpPaneThemeVisualStudio2005Beta1*/xtpPaneThemeVisualStudio2015 );
kPaneManager->SetAlphaDockingContext(TRUE);
kPaneManager->SetShowDockingContextStickers(/*TRUE*/(XTPDockingContextStickerStyle)xtpPaneStickerStyleVisualStudio2015Dark);

i'm on 18.5.0.
Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 693
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 23 July 2019 at 4:33pm
olebed,

is this the issue I mentioned here:

http://forum.codejock.com/forum_posts.asp?TID=23877&title=docking-pane-drag-is-wrong-with-this-setup

I have the same problem. Here is my setup. I have 3 monitors. A 2k one on the left. My middle monitor is my main monitor, a 4k monitor scaled 200%. My third monitor is a 2k monitor to the right of my main monitor.

I can drag a pane from the main monitor to the left one. But when I cross the boundary, the pane "separates" from the cursor. The closer to the top of the monitor I am, the closer the blue window being dragged is to the cursor. Move down and it separates at a 2X rate.

Now move towards the right monitor. When it reaches the halfway point, it quits moving. That's because CJ thinks the cursor is off the desktop.

The virtual size of the monitor does not match the physical size on the two 2k monitors. GetDeviceCaps and GetMonitorInfoEx shows the difference and also clues on in on how to offset and scale the window rect calculations.
Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 693
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 15 April 2020 at 12:13pm
So, what is the fix here? Even with 19.0 I still have the problem. We really could use a fix.
Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 693
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 29 July 2020 at 9:32am
andredevries and oled,

I can guess why one might not be able to duplicate the issue. If an application is built with per monitor aware DPI settings (usually set in the manifest), the issue will not appear regardless of the monitor setup, including 4k > 100%).

If built with system aware DPI setting, the issue easily shows up. I have not tried "none" for the DPI setting in the VS Manifest setting. I'm not where my 4k monitor is or I would try setting the settings on a sample.

For our app, I have removed the DPI setting via manifest and instead set it programmatically after reading a registry setting I use to determine which of the DPI settings I want to try.

I would not be surprised if the OS version also has an effect. My 4k setup has a box with OS Version 1803. I know Microsoft has made some changes in 1903 and put out a hot fix for that OS and supposedly has rolled the change into the latest updates. That fix had to do with resizing a window where the dynamic rectangle could fail to show up on the correct monitor and could fail to show up anywhere on the desktop when not using per monitor aware.
Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 693
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 29 July 2020 at 9:55am
Don't know if this helps but MFC has an issue drawing a frame rect around a toolbar depending on the monitors involved and I obtained the following code that showed one way to fix it. But, we don't build MFC and we found setting per monitor aware allows an MFC app with a toolbar to work just fine. In any case, here is some code that simulates a resizing rectangle that worked on my desktop with 3 monitors including the 4k set to 200%. The magic is in VirtualToPhysical. I'd upload the project but don't see an easy way to do so. It is a single source file though.

// DrawToScreenSample.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#include <windowsx.h>
#include "DrawToScreenSample.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

const WCHAR dummyMoveWindowClass[] = L"DummyMoveWindow";
using SetThreadDpiAwarenessContextFunc = DPI_AWARENESS_CONTEXT (WINAPI*)(_In_ DPI_AWARENESS_CONTEXT dpiContext);
SetThreadDpiAwarenessContextFunc g_setThreadDpiAwarenessContext;

HWND g_windowToTrack;
bool m_movingWindow;
RECT g_lastRect;
POINT g_moveStartPoint;
POINT g_moveEndPoint;
bool g_moveWindow;
HWND g_dummyWindowToMove;

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
ATOM                RegisterDummyMoveWindowClass(HINSTANCE hInstance);

BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawToScreen(HWND selectedWindow);
RECT VirtualToPhysical(const RECT &virtualRect);

INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_DRAWTOSCREENSAMPLE, szWindowClass, MAX_LOADSTRING);

    if (!MyRegisterClass(hInstance))
    {
        return FALSE;
    }

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HMODULE user32Dll = GetModuleHandle(L"User32.dll");
    if (!user32Dll)
    {
        return FALSE;
    }

    g_setThreadDpiAwarenessContext = reinterpret_cast<SetThreadDpiAwarenessContextFunc>(GetProcAddress(user32Dll, "SetThreadDpiAwarenessContext"));
   
    if (!g_setThreadDpiAwarenessContext && GetLastError() != ERROR_PROC_NOT_FOUND)
    {
        return FALSE;
    }

    if (g_setThreadDpiAwarenessContext && !RegisterDummyMoveWindowClass(hInstance))
    {
        return FALSE;
    }

    //g_setThreadDpiAwarenessContext = nullptr;
   
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DRAWTOSCREENSAMPLE));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return static_cast<int>(msg.wParam);
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DRAWTOSCREENSAMPLE));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_DRAWTOSCREENSAMPLE);
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

ATOM RegisterDummyMoveWindowClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex = {};
    wcex.hInstance = hInstance;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.lpfnWndProc = [](
        _In_ HWND hWnd,
        _In_ UINT message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam) ->LRESULT
    {
        switch (message)
        {
        case WM_DPICHANGED:
            {
                RECT* const prcNewWindow = reinterpret_cast<RECT*>(lParam);
                SetWindowPos(hWnd,
                    nullptr,
                    prcNewWindow->left,
                    prcNewWindow->top,
                    prcNewWindow->right - prcNewWindow->left,
                    prcNewWindow->bottom - prcNewWindow->top,
                    SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
                break;
            }
        }

        return DefWindowProc(hWnd, message, wParam, lParam);
    };

    wcex.lpszClassName = dummyMoveWindowClass;
    wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance; // Store instance handle in our global variable

    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN:
        SetCapture(hWnd);
        return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_MOUSEMOVE:
        {
            DPI_AWARENESS_CONTEXT oldAwareness = nullptr;
            if (g_setThreadDpiAwarenessContext)
            {
                oldAwareness = g_setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
            }

            if (GetCapture() == hWnd)
            {
                DWORD postion = GetMessagePos();
                POINT pt;
                pt.x = GET_X_LPARAM(postion);
                pt.y = GET_Y_LPARAM(postion);

                if (!m_movingWindow)
                {
                    HWND window = WindowFromPoint(pt);
                    HWND topLevelWindow = GetAncestor(window, GA_ROOT);
                    if ((g_windowToTrack || topLevelWindow) && (g_windowToTrack != topLevelWindow))
                    {
                        DrawToScreen(topLevelWindow);
                        g_windowToTrack = topLevelWindow;
                    }

                    // if the user wants to move the top-level window
                    if (topLevelWindow && (wParam & MK_CONTROL))
                    {
                        m_movingWindow = true;
                        g_moveStartPoint = pt;
                        g_moveWindow = false;

                        if (g_setThreadDpiAwarenessContext)
                        {
                            RECT physicalRect;
                            if (GetWindowRect(g_windowToTrack, &physicalRect))
                            {
                                g_dummyWindowToMove = CreateWindow(dummyMoveWindowClass, nullptr, WS_POPUP/* | WS_VISIBLE*/, physicalRect.left, physicalRect.top, physicalRect.right - physicalRect.left, physicalRect.bottom - physicalRect.top, nullptr, nullptr, hInst, nullptr);
                            }
                        }
                    }
                }
                else
                {
                    if (!(wParam & MK_CONTROL))
                    {
                        ReleaseCapture();
                    }
                    else
                    {
                        DrawToScreen(nullptr);
                    }
                }
            }

            if (g_setThreadDpiAwarenessContext)
            {
                g_setThreadDpiAwarenessContext(oldAwareness);
            }
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_LBUTTONUP:
        {
            if (m_movingWindow)
            {
                if (wParam & MK_CONTROL)
                {
                    DPI_AWARENESS_CONTEXT oldAwareness = nullptr;
                    if (g_setThreadDpiAwarenessContext)
                    {
                        oldAwareness = g_setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
                    }

                    DrawToScreen(nullptr);

                    if (g_setThreadDpiAwarenessContext)
                    {
                        g_setThreadDpiAwarenessContext(oldAwareness);
                    }

                    DWORD postion = GetMessagePos();
                    g_moveEndPoint.x = GET_X_LPARAM(postion);
                    g_moveEndPoint.y = GET_Y_LPARAM(postion);
                    g_moveWindow = true;
                }
            }
            ReleaseCapture();
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_CAPTURECHANGED:
        if (m_movingWindow)
        {
            m_movingWindow = false;
            DrawToScreen(nullptr);

            if (g_moveWindow)
            {
                RECT virtualRect;

                if (g_dummyWindowToMove)
                {
                    if (GetWindowRect(g_dummyWindowToMove, &virtualRect))
                    {
                        SetWindowPos(g_windowToTrack, nullptr, virtualRect.left, virtualRect.top, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSIZE);
                    }
                }
                else
                {
                    if (GetWindowRect(g_windowToTrack, &virtualRect))
                    {
                        OffsetRect(&virtualRect, (g_moveEndPoint.x - g_moveStartPoint.x), (g_moveEndPoint.y - g_moveStartPoint.y));
                        SetWindowPos(g_windowToTrack, nullptr, virtualRect.left, virtualRect.top, 0, 0, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE);
                    }
                }
            }

            if (g_dummyWindowToMove)
            {
                DestroyWindow(g_dummyWindowToMove);
                g_dummyWindowToMove = nullptr;
            }

            g_windowToTrack = nullptr;
        }
        else if (g_windowToTrack)
        {
            DrawToScreen(nullptr);
            g_windowToTrack = nullptr;
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

void DrawToScreen(HWND selectedWindow)
{
    HDC dc = GetDC(nullptr);
    if (dc)
    {
        if (SetROP2(dc, R2_XORPEN))
        {
            WORD grayPattern[8];
            for (int i = 0; i < 8; i++)
            {
                grayPattern = WORD(0x5555 << (i & 1));
            }

            HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern);
            if (grayBitmap)
            {
                LOGBRUSH logBrush = {};
                logBrush.lbStyle = BS_PATTERN;
                logBrush.lbHatch = reinterpret_cast<LONG_PTR>(grayBitmap);
                HPEN pen = ExtCreatePen(PS_GEOMETRIC, 0, &logBrush, 0, nullptr);
                if (pen)
                {
                    HGDIOBJ oldPen = SelectObject(dc, pen);
                    if (oldPen)
                    {
                        HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
                        if (oldBrush)
                        {
                            if (g_windowToTrack)
                            {
                                Rectangle(dc, g_lastRect.left, g_lastRect.top, g_lastRect.right, g_lastRect.bottom);
                            }

                            RECT calculatedPhysicalRect = {};

                            if (m_movingWindow)
                            {
                                DWORD postion = GetMessagePos();
                                POINT pt;
                                pt.x = GET_X_LPARAM(postion);
                                pt.y = GET_Y_LPARAM(postion);

                                RECT virtualRect;
                                if (GetWindowRect(g_windowToTrack, &virtualRect))
                                {
                                    OffsetRect(&virtualRect, (pt.x - g_moveStartPoint.x), (pt.y - g_moveStartPoint.y));
                                    if (g_dummyWindowToMove)
                                    {
                                        if (SetWindowPos(g_dummyWindowToMove, nullptr, virtualRect.left, virtualRect.top, virtualRect.right - virtualRect.left, virtualRect.bottom - virtualRect.top,
                                            SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE))
                                        {
                                            if (!GetWindowRect(g_dummyWindowToMove, &calculatedPhysicalRect))
                                            {
                                                SetRectEmpty(&calculatedPhysicalRect);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        calculatedPhysicalRect = VirtualToPhysical(virtualRect);
                                    }
                                }
                            }
                            else if (selectedWindow)
                            {
                                if (g_setThreadDpiAwarenessContext)
                                {
                                    if (!GetWindowRect(selectedWindow, &calculatedPhysicalRect))
                                    {
                                        SetRectEmpty(&calculatedPhysicalRect);
                                    }
                                }
                                else
                                {
                                    RECT virtualRect;
                                    if (GetWindowRect(selectedWindow, &virtualRect))
                                    {
                                        calculatedPhysicalRect = VirtualToPhysical(virtualRect);
                                    }
                                }
                            }

                            if (!IsRectEmpty(&calculatedPhysicalRect))
                            {
                                if (Rectangle(dc, calculatedPhysicalRect.left, calculatedPhysicalRect.top, calculatedPhysicalRect.right, calculatedPhysicalRect.bottom))
                                {
                                    g_lastRect = calculatedPhysicalRect;
                                }
                            }

                            SelectObject(dc, oldBrush);
                        }
                        SelectObject(dc, oldPen);
                    }
                    DeleteObject(pen);
                }
                DeleteObject(grayBitmap);
            }
        }
        ReleaseDC(nullptr, dc);
    }
}

RECT VirtualToPhysical(const RECT &virtualRect)
{
    RECT calculatedPhysicalRect = {};

    POINT centerPoint;
    centerPoint.x = virtualRect.left + (virtualRect.right  - virtualRect.left) / 2;
    centerPoint.y = virtualRect.top  + (virtualRect.bottom - virtualRect.top)  / 2;
    HMONITOR monitor = MonitorFromPoint(centerPoint, MONITOR_DEFAULTTONEAREST);
    if (monitor)
    {
        MONITORINFOEX monitorInfo = {};
        monitorInfo.cbSize = sizeof(MONITORINFOEX);
        if (GetMonitorInfo(monitor, &monitorInfo))
        {
            HDC monitorDC = CreateDC(nullptr, monitorInfo.szDevice, nullptr, nullptr);
            if (monitorDC)
            {
                int screenWidth = GetDeviceCaps(monitorDC, DESKTOPHORZRES);
                int virtualizedScreenWidth = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;

                calculatedPhysicalRect.left   = (virtualRect.left   - monitorInfo.rcMonitor.left) * screenWidth / virtualizedScreenWidth + monitorInfo.rcMonitor.left;
                calculatedPhysicalRect.top    = (virtualRect.top    - monitorInfo.rcMonitor.top)  * screenWidth / virtualizedScreenWidth + monitorInfo.rcMonitor.top;
                calculatedPhysicalRect.right  = (virtualRect.right  - monitorInfo.rcMonitor.left) * screenWidth / virtualizedScreenWidth + monitorInfo.rcMonitor.left;
                calculatedPhysicalRect.bottom = (virtualRect.bottom - monitorInfo.rcMonitor.top)  * screenWidth / virtualizedScreenWidth + monitorInfo.rcMonitor.top;

                DeleteDC(monitorDC);
            }
        }
    }

    return calculatedPhysicalRect;
}

//void DrawMoving()
//{
//    HDC dc = GetDC(nullptr);
//
//    SetROP2(dc, R2_XORPEN);
//
//    WORD grayPattern[8];
//    for (int i = 0; i < 8; i++)
//    {
//        grayPattern = (WORD)(0x5555 << (i & 1));
//    }
//
//    HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern);
//
//    LOGBRUSH logBrush = {};
//    logBrush.lbStyle = BS_PATTERN;
//    logBrush.lbHatch = (LONG_PTR)grayBitmap;
//    HPEN pen = ExtCreatePen(PS_GEOMETRIC, 0, &logBrush, 0, nullptr);
//
//    SelectObject(dc, pen);
//    SelectObject(dc, GetStockObject(NULL_BRUSH));
//
//    if (g_windowToTrack)
//    {
//        Rectangle(dc, g_lastRect.left, g_lastRect.top, g_lastRect.right, g_lastRect.bottom);
//    }
//   
//    if (m_movingWindow) //
//    {
//        DWORD postion = GetMessagePos(); //
//        POINT pt; //
//        pt.x = GET_X_LPARAM(postion); //
//        pt.y = GET_Y_LPARAM(postion); //
//
//        RECT virtualRect;
//        GetWindowRect(g_windowToTrack, &virtualRect);
//        OffsetRect(&virtualRect, (pt.x - g_moveStartPoint.x), (pt.y - g_moveStartPoint.y)); //
//
//        RECT calculatedPhysicalRect = {};
//
//        if (g_dummyWindowToMove) //
//        {
//            SetWindowPos(g_dummyWindowToMove, nullptr, virtualRect.left, virtualRect.top, 0, 0, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE); //
//
//            DPI_AWARENESS_CONTEXT oldAwareness = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
//            GetWindowRect(g_dummyWindowToMove, &calculatedPhysicalRect); //
//            SetThreadDpiAwarenessContext(oldAwareness);
//        }
//        else
//        {
//            POINT centerPoint;
//            centerPoint.x = virtualRect.left + (virtualRect.right - virtualRect.left) / 2;
//            centerPoint.y = virtualRect.top + (virtualRect.bottom - virtualRect.top) / 2;
//            HMONITOR monitor = MonitorFromPoint(centerPoint, MONITOR_DEFAULTTONEAREST);
//            MONITORINFOEX monitorInfo = {};
//            monitorInfo.cbSize = sizeof(MONITORINFOEX);
//            GetMonitorInfo(monitor, &monitorInfo);
//
//            HDC monitorDC = CreateDC(nullptr, monitorInfo.szDevice, nullptr, nullptr);
//            int screenWidth = GetDeviceCaps(monitorDC, DESKTOPHORZRES);
//            int virtualizedScreenWidth = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
//           
//            calculatedPhysicalRect.left = ((virtualRect.left - monitorInfo.rcMonitor.left) * screenWidth / virtualizedScreenWidth) + monitorInfo.rcMonitor.left;
//            calculatedPhysicalRect.top = ((virtualRect.top - monitorInfo.rcMonitor.top) * screenWidth / virtualizedScreenWidth) + monitorInfo.rcMonitor.top;
//            calculatedPhysicalRect.right = ((virtualRect.right - monitorInfo.rcMonitor.left) * screenWidth / virtualizedScreenWidth) + monitorInfo.rcMonitor.left;
//            calculatedPhysicalRect.bottom = ((virtualRect.bottom - monitorInfo.rcMonitor.top) * screenWidth / virtualizedScreenWidth) + monitorInfo.rcMonitor.top;
//        }
//
//        Rectangle(dc, calculatedPhysicalRect.left, calculatedPhysicalRect.top, calculatedPhysicalRect.right, calculatedPhysicalRect.bottom);
//       
//        g_lastRect = calculatedPhysicalRect;
//    }
//
//    DeleteObject(pen);
//    DeleteObject(grayBitmap);
//
//    ReleaseDC(nullptr, dc);
//}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

Back to Top
 Post Reply Post Reply
  Share Topic   

Forum Jump Forum Permissions View Drop Down



This page was generated in 0.141 seconds.