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

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

  • As mobile devices have pushed their way into the enterprise, they have brought cloud apps along with them. This app explosion means account passwords are multiplying, which exposes corporate data and leads to help desk calls from frustrated users. This paper will discover how IT can improve user productivity, gain visibility and control over SaaS and mobile apps, and stop password sprawl. Download this white paper to learn: How you can leverage your existing AD to manage app access. Key capabilities to …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds