Introduction
This article describes how to modify a modal dialog's styles and position at run-time so it can work both as a child of a CPropertySheet
as well as a pop-up window on its own.
Background
When a CPropertyPage
is added to a CPropertySheet
, it has to be a child of that property sheet. Also, the property page has to be disabled and not visible initially. What if the same property page has to be run independent of the property sheet, as a modal dialog? In that case, the styles have to be changed at run-time. When do we change the styles? It turns out that doing so in OnInitDialog()
is too late. Besides, the repositioning of the popup dialog requires some specific options which may not be apparent from the MSDN documentation. This article shows how to do both.
Using the code
The DialogStyleModificationExample
project is a very simple dialog based MFC app with two buttons. The "Open Dialog With Default Styles" button adds the property page CPropertyPageFirst
, without changing its style or position, to a CPropertySheet
and opens the property sheet.
The "Open Dialog With Modified Styles" sets the modify flag for the property page and starts it up as a modal dialog on its own. We override PreSubclassWindow
to change the property page's styles.
void CPropertyPageFirst::PreSubclassWindow()
{
if (m_bModifyDlgStylesAndPos == true)
{
if(m_hWnd != NULL)
{
LONG lStyle = GetWindowLong(m_hWnd, GWL_STYLE);
lStyle &= ~WS_CHILD;
lStyle &= ~WS_DISABLED;
lStyle |= WS_POPUP;
lStyle |= WS_VISIBLE;
lStyle |= WS_SYSMENU;
SetWindowLong(m_hWnd, GWL_STYLE, lStyle);
}
}
CPropertyPage::PreSubclassWindow();
}
We set the dialog's position by overriding OnInitDialog()
.
BOOL CPropertyPageFirst::OnInitDialog()
{
CPropertyPage::OnInitDialog();
if((m_bModifyDlgStylesAndPos == true) && m_hWnd)
{
SetWindowText("Modified Property Page");
CRect rectFrame, rectDlg;
CWnd* pMainWnd = AfxGetMainWnd();
if(pMainWnd != NULL)
{
pMainWnd->GetClientRect(rectFrame);
pMainWnd->ClientToScreen(rectFrame);
GetWindowRect(rectDlg);
int nXPos = rectFrame.left + (rectFrame.Width() / 2)
- (rectDlg.Width() / 2);
int nYPos = rectFrame.top + (rectFrame.Height() / 2)
- (rectDlg.Height() / 2);
::SetWindowPos(m_hWnd, HWND_TOP, nXPos, nYPos,
rectDlg.Width(), rectDlg.Height(), SWP_NOCOPYBITS);
}
}
}
Points of Interest
The main task here was to use the same property page in two different environments:
- As a child of a
CPropertySheet
.
- As an independent pop-up dialog.
It was apparent that I would have to modify the dialog's style in case #2. I tried doing this in OnInitDialog()
with ModifyStyle(...)
but that did not work as it is too late to change a child window to a pop-up in OnInitDialog()
.
I considered PreCreateWindow(...)
thinking I could change the CREATESTRUCT
in this function to change both the styles and position in one go. But it turns out that PreCreateWindow(...)
doesn't get called at all for modal dialogs.
I could try instantiating the dialog as modeless but there were two problems with this approach:
- The
PreCreateWindow(...)
still didn't get called.
- Memory management problems occurred as one instance of the dialog was modal and the other was modeless.
I could get around a) above by calling CreateEx(...)
as doing so would call PreCreateWindow(...)
but at this point we would be creating the styles for the dialog from scratch instead of modifying them which is not what we intended. So the solution was to modify the styles in PreSubclassWindow()
. Now you may be tempted to re-position the dialog here as well but no matter how you try it, the dialog does not move from the left corner of the screen. Additionally, the dialog is drawn with some areas as transparent. So you have to re-position it in OnInitDialog()
.
There is one more catch though: when using ::SetWindowPos(...)
, you have to specify SWP_NOCOPYBITS
as the window sizing and positioning flag, otherwise all valid contents of the client area of the previous window position are copied into the client area after the window is sized or repositioned, resulting in a strange looking dialog with some unexpected graphics.
That's it! Please go ahead and experiment, suggest other ways to accomplish the same. Enjoy!