Home Search Contact us About us
Title Catching and Preventing the Close event.
Summary An article about how to catch and or prevent an operator from closing a dialog, SDI or MDI application.
Contributor John McTainsh
Published 5-Mar-2001
Last updated 5-Mar-2001
Page rating   78% for 14 votes Useless Brilliant

Introduction

It is often the case that you do not want the user to be able to close the application by accident. To prevent this you could disable the [X] close button, or ask the user if they are "sure" they want to do this. This article covers ideas on how the prevent accidental closing..

Keeping a MDI child window open

Although, not the most common practice, it is often necessary to prevent the user from closing and MDI child window. To do this simply remove the window type menu to option to close and the System menu close option. Note when the system menu option is removed the [X] close button is disabled.

Start by handling the system menu close event and disabling the button.

In ChildFrm.cpp add ON_WM_SYSCOMMAND to the message map and implement OnSysCommand. Also disable the button ans seperator in the OnCreate which can be added by using wizard to handle WM_CREATE.

BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
    //{{AFX_MSG_MAP(CChildFrame)
    .....
    .....
    ON_WM_CREATE()
    //}}AFX_MSG_MAP
    ON_WM_SYSCOMMAND()  
END_MESSAGE_MAP()

...
...

// ***************************************************************************
//DESCRIPTION:
//      Disable the Close button and menu item (Only for the children)
//PARAMS:
//      see help
//RETURN:
//      see help
//CREATED:
//      3-3-2001, 8:49:14 PM by john@mctainsh.com
// ***************************************************************************
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
    CMenu *pSysMenu = GetSystemMenu(FALSE);
    ASSERT(pSysMenu != NULL); 
    VERIFY( pSysMenu->DeleteMenu( SC_CLOSE, MF_BYCOMMAND ) );   
    VERIFY( pSysMenu->RemoveMenu( 5, MF_BYPOSITION ) );     
    return 0;
}
void CChildFrame::OnSysCommand(UINT nID, LPARAM lParam)
{
    if(nID == SC_CLOSE)
        return;
    CMDIChildWnd::OnSysCommand(nID, lParam);
} 

In ChildFrm.h add.

    ...
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 
    //}}AFX_MSG
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    DECLARE_MESSAGE_MAP()

Finally delete the File->Close menu item from the type menu resource.

Preventing the closing of a MDI or SDI application.

Here we will try an alternative method to remove the [X] close app button from the main frame. This is done by modifying the way the frame is created. This sample allows the user to close the app by using File->Exit but not with {ALT+F4} or the [X] close button. As a free bonus code is also shown to set the original position and size of the window and whether it can be minimised or maximised.

//////////////////////////////////////////////////////////////////////////////
//Setup the pre display view of the main frame
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
    //      | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
    if(CMDIFrameWnd::PreCreateWindow(cs))
    {
        //cs.style &= ~WS_MINIMIZEBOX;              //This hides the Minimise box
        //cs.style &= ~WS_MAXIMIZEBOX;              //This hides the Maximise box
        //cs.style &= ~WS_SYSMENU;                  //This option hides the nice icon
        cs.lpszClass = AfxRegisterWndClass( CS_NOCLOSE
            , AfxGetApp()->LoadStandardCursor( IDC_ARROW )
            //,( COLOR_APPWORKSPACE + 1) 
            , CreateSolidBrush( RGB(0,0,0))
            , AfxGetApp()->LoadIcon( IDR_MAINFRAME ) );
        cs.x = 0;
        cs.y = 0;
        cs.cx = 640;
        cs.cy = 480;
        return TRUE;
    }
    return FALSE;
}

Finally a dialog.

A simple dialog app when first created will close when the user presses {Enter}, OK, {Esc}, Cancel, {ALT+F4} or the [X] close button. To overcome this we will handle each of these events starting with {Enter}.

  • Use the wizard to add a handler for the OK button. OnOK() this will prevent {Enter} closing the dialog if CDialog::OnOK() is deleted from the wizard generated code.
  • Use the wizard  to add a handler for the Cancel button. OnCancel() and delete CDialog::OnCancel() from the wizard generated code.  This will prevent {Esc}, Cancel, {ALT+F4} or the [X] close button closing the dialog.
  • You should now either grey out the [X] close button or add a seperate handler for it. Grey it out by adding this line to the end of InitDialog().
    VERIFY( pSysMenu->DeleteMenu( SC_CLOSE, MF_BYCOMMAND ) );
  • To only handle the [X] button press, simply add a handler to OnSysCommand and catch if( nID == SC_CLOSE ).

In closing...(ha)

In most cases these methods can be mixed and matched. Try each one to see which works best for you. Remember, changing the default windows behaviour often upsets people so only do it for good reason.

Comments Date
Home Search Contact us About us