锁定窗口位置显示更改

时间:2016-03-03 18:48:35

标签: mfc position window screen display

我有一个应用程序,它有几个窗口,我希望它们中的一些(我将称之为CMyLockedFrameWndEx,因为它们来自CFrameWndEx)保持在更改系统显示区域后的位置。 我的应用程序的所有窗口的父级都是NULL。

当我将第二台显示器的位置相对于第一台显示器拖动时,我已设法抓住WM_DISPLAYCHANGE消息;当我连接或断开第二台显示器的HDMI线缆时,我也赶来WM_DEVICECHANGE。我已经CMyLockedFrameWndEx::WindowProc拦截了他们。

之后会发生自动窗口重新定位。我注意到,因为我在CMyLockedFrameWndEx::OnWindowPosChangingCMyLockedFrameWndEx::OnWindowPosChanged上设置了断点而且我们在WindowProc上捕获的事件后停止了。这个工作流程似乎与我所描述的事件的捕获无关,因为我的WindowProc方法是:

LRESULT CMyLockedFrameWndEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_DISPLAYCHANGE)
    {
        TRACE(_T("DISPLAY CHANGE"));
        return 0L;
    }

    if (message == WM_SYSCOMMAND)
    {
        TRACE(_T("SYSCOMMAND"));

        if (wParam == SC_MOVE)
        {
            return 0L;
        }
    }

    if (message == WM_WININICHANGE)
    {
        TRACE(_T("WININICHANGE"));

        if (wParam == SPI_SETWORKAREA)
        {
            return 0L;
        }
    }



    return __super::WindowProc( message, wParam, lParam);
}

当传入OnWindowPosChangingOnWindowPosChanged时,流程并非来自我处理的WindowProc的特定情况。这是一个问题。

我尝试按照调用堆栈查看发送WM_WINDOWPOSCHANGINGWM_WINDOWPOSCHANGED消息的窗口,但我没有成功。我甚至试图使用Spy ++ 64来检测谁是消息的发送者,但我没有成功。看到谁是发件人的整个想法是:如果它与系统的关联显示更改是事先检测它并弹劾自动重新定位甚至发生。

由于我还没有成功,我该怎样做才能让窗户免受系统显示的影响?

感谢。

2 个答案:

答案 0 :(得分:1)

好消息是:显然,您可以控制自己窗口的位置。

坏消息 - Windows将首先将您的窗口移至新位置,然后向您发送WM_DISPLAYCHANGEWM_SETTINGCHANGE,如图所示在这个Spy ++的日志中:

S WM_WINDOWPOSCHANGING lpwp:003CF9AC
S WM_GETMINMAXINFO lpmmi:003CF624
R WM_GETMINMAXINFO lpmmi:003CF624
R WM_WINDOWPOSCHANGING
S WM_WINDOWPOSCHANGED lpwp:003CF9AC
S WM_MOVE xPos:278 yPos:450
R WM_MOVE
R WM_WINDOWPOSCHANGED
S WM_SETTINGCHANGE wFlag:SPI_ICONVERTICALSPACING pszMetrics:0026E018
R WM_SETTINGCHANGE
S WM_DISPLAYCHANGE cBitsPerPixel:32 cxScreen:2560 cyScreen:1440
R WM_DISPLAYCHANGE
S WM_SETTINGCHANGE wFlag:SPI_SETWORKAREA pszMetrics:0026E018
R WM_SETTINGCHANGE

所以 - 你必须自己测试位置改变到另一个屏幕。就像在这个简化的例子中一样,2560是我的屏幕宽度:

case WM_WINDOWPOSCHANGING:
{
    WINDOWPOS* pWP = (WINDOWPOS*)lParam;
    if ((pWP->flags & SWP_NOMOVE) == 0) // it's a move
    {
        if (pWP->x < 2560)
            pWP->flags |= SWP_NOMOVE;
    }
    return 0;
}

答案 1 :(得分:0)

不幸的消息是我无法以预防方式执行此操作,因为即使在发送任何有用的消息后系统也会将窗口移动到主屏幕。

好消息是我可以通过添加

来对此举做出反应

ON_WM_WINDOWPOSCHANGED()

在类的消息映射上行,并为其提供相应的处理函数:

CMyLockedFrameWndEx::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
    __super::OnWindowPosChanged(lpwndpos);

    CFrameWndEx* pFrame=(CFrameWndEx*)::AfxGetMainWnd();
    VALIDATE_FPTR(pFrame);

    CMyDoc* pDoc=(CMyDoc*)pFrame->GetActiveDocument();
    VALIDATE_FPTR(pDoc);

    POSITION p= pDoc->GetFirstViewPosition();

    while(p)
    {
        CMyLockedView* pLockedView= dynamic_cast<CLockedView*>(pDoc->GetNextView(p));
        if(!pLockedView)
            continue;

        if(pLockedView->GetParentFrame() == this)
        {
            this->SetWindowPos(NULL, m_Top, m_Left, 0, 0, SWP_NOSIZE);

            break;
        }
    }
}´

请注意,我在m_Topm_Left变量中保持窗口的位置对我有帮助。