I have an application which has several windows and I want that some of them (which I will call CMyLockedFrameWndEx
, because they derive from CFrameWndEx
) stay placed where they were after changing system display area.
The Parent of all windows of my application is NULL.
I've managed to already catch the WM_DISPLAYCHANGE
message when I drag the position of the 2nd monitor relatively to the first; and I also had come to catch the WM_DEVICECHANGE
when I connect or disconnect the 2nd monitor's HDMI cable. I've intercepted them both at CMyLockedFrameWndEx::WindowProc
.
The automatic window repositioning occurs after that. I noticed that bacause I've put breakpoints on CMyLockedFrameWndEx::OnWindowPosChanging
and CMyLockedFrameWndEx::OnWindowPosChanged
and they stop after the events I catched on WindowProc
. This workflow seems to be unrelated to the catching of events I described as my WindowProc
method is:
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);
}
and when passing in OnWindowPosChanging
or OnWindowPosChanged
, the flow doesn't come from the specific cases of WindowProc
handled by me. And that is a problem.
I tried to follow the call stack to see what window sent the WM_WINDOWPOSCHANGING
or the WM_WINDOWPOSCHANGED
message, but I didn't succeed. I have even tried to use Spy++64 to detect who was the the sender of the message, but I didn't succeed. The whole idea of seeing who was the sender was: if it is associated to a system's display change is to detect it beforehand and impeach the auto repositioning to even happen.
As i didn't succeed yet, what can I do to make the window immune to a system's display change?
Thanks.
The unhappy news are I can not do this on a preventive way, because the system moves the windows to the primary screen even after sending any useful messages.
The good news are I can react to the move by adding a
ON_WM_WINDOWPOSCHANGED()
line on the class's message map and supply it with its respective handler function:
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;
}
}
}´
Note, that it helps me that I was persisting the position where the window was in the m_Top
and m_Left
variables.