Environment: VC6, WIN9x, NT4
Programming a modeless wizard has been a problem that I’ve been trying to
solve for some time now. Since I’ve seen that many others have had difficulty with
this as well, I finally decided to dive into the code and figure out how to do this
once and for all. As it turned out, I was surprised to
see how simple it is to make a Wizard modeless.
To use this trick in your code, simply follow these steps:
- Insert all the code you would need in your project to create
a CPropertySheet Wizard. Don’t forget to call the SetWizardMode()
member function. - Override the DoModal() member function. You can use the ClassWizard to do so.
- Copy the function body from CPropertySheet::DoModal() member function into
your overridden member function. You will also need to include the
‘afxpriv.h’ and ‘afximpl.h’ header files in your source. - Eliminate a few lines in the code you have copied
into your overridden function. Just below, is the code you should have
inside your function. The lines you should eliminate are marked as comments
and are shown in bold face. - Consider overriding ContinueModal() as well. Take a look at the
example I prepared. The overridden version of this function makes the wizard
go away when its parent is closed. If you do not override this member
function you will get an ASSERT error when the wizard’s parent window
closes before it does.
NOTE: I haven’t tested this new wizard behavior much, so if you come
up with enhancements please let me know!
Implementation
#include “afxpriv.h”
#include “..\src\afximpl.h”
int CMyPropertySheet::DoModal()
{
ASSERT_VALID(this);
ASSERT(m_hWnd == NULL);
// register common controls
VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
AfxDeferRegisterClass(AFX_WNDCOMMCTLSNEW_REG);
// finish building PROPSHEETHEADER structure
BuildPropPageArray();
/*
// allow OLE servers to disable themselves
CWinApp* pApp = AfxGetApp();
if (pApp != NULL)
pApp->EnableModeless(FALSE);
*/
// find parent HWND
HWND hWndTop;
HWND hWndParent = CWnd::GetSafeOwner_(m_pParentWnd->GetSafeHwnd(), &hWndTop);
AFX_OLDPROPSHEETHEADER* psh = GetPropSheetHeader();
psh->hwndParent = hWndParent;
/* BOOL bEnableParent = FALSE;
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
{
::EnableWindow(hWndParent, FALSE);
bEnableParent = TRUE;
}
*/
HWND hWndCapture = ::GetCapture();
if (hWndCapture != NULL)
::SendMessage(hWndCapture, WM_CANCELMODE, 0, 0);
// setup for modal loop and creation
m_nModalResult = 0;
m_nFlags |= WF_CONTINUEMODAL;
// hook for creation of window
AfxHookWindowCreate(this);
psh->dwFlags |= PSH_MODELESS;
m_nFlags |= WF_CONTINUEMODAL;
HWND hWnd = (HWND)::PropertySheet((PROPSHEETHEADER*)psh);
#ifdef _DEBUG
DWORD dwError = ::GetLastError();
#endif
psh->dwFlags &= ~PSH_MODELESS;
AfxUnhookWindowCreate();
// handle error
if (hWnd == NULL || hWnd == (HWND)-1)
{
TRACE1(“PropertySheet() failed: GetLastError returned %d\n”, dwError);
m_nFlags &= ~WF_CONTINUEMODAL;
}
int nResult = m_nModalResult;
if (ContinueModal())
{
// enter modal loop
DWORD dwFlags = MLF_SHOWONIDLE;
if (GetStyle() & DS_NOIDLEMSG)
dwFlags |= MLF_NOIDLEMSG;
nResult = RunModalLoop(dwFlags);
}
// hide the window before enabling parent window, etc.
if (m_hWnd != NULL)
{
SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
}
/* if (bEnableParent)
::EnableWindow(hWndParent, TRUE);
*/ if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
::SetActiveWindow(hWndParent);
// cleanup
DestroyWindow();
/*
// allow OLE servers to enable themselves
if (pApp != NULL)
pApp->EnableModeless(TRUE);
if (hWndTop != NULL)
::EnableWindow(hWndTop, TRUE);
*/
return nResult;
}