Programming a Modeless Property Sheet

Modeless Wizard

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;
}

Downloads

Download sample source - 43 KB


Comments

  • Modeless Property Sheet

    Posted by Rita1981 on 05/18/2006 05:49pm

    The code above seems really complicated and I could not get it to compile. Does anyone know an easy way to create a modeless property sheet? My goal is just to have a simple Modeless property sheet that has NO Ok, Apply , Cancel and help buttons. I managed to get rid of the buttons on a Modal Property sheet but the empty space still appears underneath the tabs. Please help. Thanks,

    Reply
  • Modeless Property Sheet

    Posted by Rita1981 on 05/18/2006 05:36pm

    The code above seems really complicated and I could not get it to compile. Does anyone know an easy way to create a modeless property sheet? My goal is just to have a simple Modeless property sheet that has NO Ok, Apply , Cancel and help buttons. I managed to get rid of the buttons on a Modal Property sheet but the empty space still appears underneath the tabs. Please help. Thanks,

    Reply
  • How can i position the modeless porpertysheet dlg

    Posted by Legacy on 10/16/2003 12:00am

    Originally posted by: fting

    CConcreteLxlPropertySheet m_ConcreteLxlPropertySheet(""); CConcreteLxlPage1 page1; CConcreteLxlPage2 page2; m_ConcreteLxlPropertySheet.AddPage(&page1); m_ConcreteLxlPropertySheet.AddPage(&page2); m_ConcreteLxlPropertySheet.DoModal(); m_ConcreteLxlPropertySheet.MoveWindow(myRect.left+myRect.Width()/9,myRect.top+32,500,400,true);

    However, it seems that this doesn't work ,besides, when i close the propertysheet dlg, I am warned-"debug assertion failed".
    I don't know how to deal with it.
    Could someone give me some help??
    Thank you very much!!!!!

    Reply
  • Create Modeless PropertySheet : In MS knowledge Base

    Posted by Legacy on 04/07/2003 12:00am

    Originally posted by: duckbill

    You can find an article which is explaining the method in Microsoft Knowledge Base.
    Go to http://msdn.microsoft.com/, and
    search with keyword Q146916 in Knowledge Base Category.

    Good luck.

    Reply
  • Closing of modeless Dialog Box

    Posted by Legacy on 08/03/2000 12:00am

    Originally posted by: Hariprasad Rao

    How do I destroy the modeless dialog box? Whether DestroyWindow() can be used here?
    
    

    Thaning you

    H.V. Rao

    Reply
  • How can i close modeless propertysheet?

    Posted by Legacy on 05/06/2000 12:00am

    Originally posted by: Seorak, Lee

    Please help me. I can't close this dialog.

    I used to Create Function

    Reply
  • ASSERT failure!!!!!!!!!!!!!!!!in RunModal(), please help

    Posted by Legacy on 03/15/2000 12:00am

    Originally posted by: bhaskar


    Assert failure in CWnd::DestroyWindow
    #ifdef _DEBUG
    ASSERT(m_hWnd == hWndOrig);
    which is in
    CWnd::FilterToolTipMessage()

    pToolTip->DestroyWindow();
    delete pToolTip;
    which is in

    void PASCAL CWnd::_FilterToolTipMessage(MSG* pMsg, CWnd* pWnd)
    {
    pWnd->FilterToolTipMessage(pMsg);
    }

    which is in

    BOOL CWnd::PreTranslateMessage(MSG* pMsg)
    {
    // handle tooltip messages (some messages cancel, some may cause it to popup)
    AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
    if (pModuleState->m_pfnFilterToolTipMessage != NULL)
    (*pModuleState->m_pfnFilterToolTipMessage)(pMsg, this);

    // no default processing
    return FALSE;
    }

    etc..

    Can you spot the mistake???

    Bhaskar

    Reply
  • 2 modeless PropertySheet : don't close the first!!!

    Posted by Legacy on 01/19/2000 12:00am

    Originally posted by: deshays

    2 modeless PropertySheet : don't close the first!!!
    Where's the problem?

    Reply
  • Unhandled exception for Modeless Property Sheet (not Wizard)

    Posted by Legacy on 10/13/1999 12:00am

    Originally posted by: Edmond Chui

    By using the same trick as in the example, I turned a modal property sheet to modeless. Everything worked fine until I tried to kill the parent window before killing the property sheet. I got an Unhanled exception error (Access Violation) when the if(!ContinueModal()) line is called inside RunModalLoop(), which in turn is called by DoModeless(). Any suggestion on what's wrong?

    Also, how to bring the modeless property sheet behind the parent when it yields the input focus?

    Thanks,
    Edmond

    Reply
  • Where is the focus on a modeless property sheet after clicking on the HELP button on the sheet

    Posted by Legacy on 08/03/1999 12:00am

    Originally posted by: Terry Chan

    I try to make the HELP button and the F1 on my modeless property sheet work, but they have been acting so weird . For instance, if F1 is clicked, then F1 is not active, but if I lick the cursor somewhere in side the page, F1 works. It seems to me that after HeLP button is released, the focus on this sheet is gone, Please give me some idea how to solve this problem

    Thanks
    Terry

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • This paper introduces IBM Java on the IBM PowerLinux 7R2 server and describes IBM's implementation of the Java platform, which includes IBM's Java Virtual Machine and development toolkit.

  • A modern mobile IT strategy is no longer an option, it is an absolute business necessity. Today's most productive employees are not tied to a desk, an office, or a location. They are mobile. And your company's IT strategy has to be ready to support them with easy, reliable, 24/7 access to the business information they need, from anywhere in the world, across a broad range of communication devices. Here's how some of the nation's most progressive corporations are meeting the many needs of their mobile workers …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds