Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

MDI child frame without a close button

Posted on 1998-05-26
12
1,085 Views
Last Modified: 2013-11-20
I'm new to MFC and Windows programming, making the leap from DOS (a dark screen with a C:\>, remember?)

Can I create an MDI child frame that does not have a close button. I do not want the user to be able to close the first child window opened when the program starts. I've played around with the ::LoadFrame(), ::Create(), and ::PreCreateWindow() member functions of the CChildFrame class to no avail. I've tried various combinations of the WS_XXXX bits in the frame styles, but haven't hit the correct one. Is this possible in MFC?

Note that I also have to get rid of the Close option from the Windows system menu.

Thanks,
Nelson Chenkin
0
Comment
Question by:nchenkin
12 Comments
 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1315335
No, it is possible. But you can do the next best thing by trapping WM_SYSCOMMAND in the child frame and if the number of child windows is 1 (meaning it is the first), then ignore the command if the wparam has SC_CLOSE in it:

  void MyWnd::OnSysCommand(wp, lp)
  {
    BOOL ignore = FALSE;
    if (count == 1)
      if ((wp & SC_CLOSE) == SC_CLOSE)
        ignore = TRUE;
    if (!ignore)
      CChildFrame::OnSysCommand(wp, lp);
  }


   
0
 

Expert Comment

by:t004024
ID: 1315336
GetSystemMenu, gives a handle to the system menu. Maybe U can get this and manipulate the menu using the CMenu class functions. U need to call the GetSystemMenu for the MainFrame window. SO Maybe U could do something like
CMenu *tMenu = AfxGetMainWnd()->GetSystemMenu() and then call
tMenu->RemoveMenu(SC_CLOSE, MF_BYCOMMAND); and then call maybe
CMDIChildWnd *ptWnd = GetParent() // This is only if U are in the View class otherwise, call MDIGetActive of the CMDIFrameWnd and call the SetSystemMenu and RemoveMenu for this.
0
 

Expert Comment

by:footloose
ID: 1315337
***** The standard code generated by MFC for CChildFrame contains this override:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
     // TODO: Modify the Window class or styles here by modifying
     //  the CREATESTRUCT cs

     return CMDIChildWnd::PreCreateWindow(cs);
}

***** Change it as below:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
     cs.style &= ~WS_SYSMENU;
     cs.style |= WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
     return CMDIChildWnd::PreCreateWindow(cs);
}

***** This gets rid of the system menu but retains the minimize/maximize buttons.
***** As THUI suggested, you need to override WM_SYSCOMMAND handler as below.
***** WM_SYSCOMMAND may not appear on the standard message list, so you will
***** have to go to the CLASSINFO tab of class wizard (for CChildFrame), change
***** MESSAGE FILTER option to WINDOW, and then go back to MESSAGE MAPS tab
***** and override WM_SYSCOMMAND handler as below:

void CChildFrame::OnSysCommand(UINT nID, LPARAM lParam)
{
     if ( nID == SC_CLOSE )
     {
          //do some checking, as THUI suggested and/or call the default
     }
     CMDIChildWnd::OnSysCommand(nID, lParam);
}

***** Also remember to go to IDR_appTYPE menu on the resource editor and get rid of
***** FILE/CLOSE menu item.
0
Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

 

Author Comment

by:nchenkin
ID: 1315338
Footloose,

I tried as you suggested in the ::PreCreateWindow() function. However this got rid of ALL three buttons: the minimize and maximize buttons were not displayed. I could still maximize the child by double clicking on the title bar, and then use Window/Cascade to restore it, but the buttons weren't there. This was one of the things I stumbled on in my attempts.

By the way, to ensure nothing else had changed I did this in newly generated App Wizard code.

Thanks,
nchenkin
0
 

Author Comment

by:nchenkin
ID: 1315339
Adjusted points to 100
0
 

Expert Comment

by:Beatachon
ID: 1315340
Does the window still have the normal looking title bar? Make sure you have your operators right. I.E: cs.style |= and NOT cs.style =.....
0
 

Author Comment

by:nchenkin
ID: 1315341
The title bar looks normal execpt the system menu icon on the left is gone and there are no buttons at all on the right.

Here's the code lifted from the file. Again, this is the only change to a new App Wizard app using all defaults.

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
   // TODO: Modify the Window class or styles here by modifying
   //  the CREATESTRUCT cs

   cs.style &= ~WS_SYSMENU;
   cs.style |= (WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
   return CMDIChildWnd::PreCreateWindow(cs);
}


0
 

Expert Comment

by:footloose
ID: 1315342
duh! how come I missed the missing minimize/maximize boxes!! Sorry! Will keep trying.
0
 

Accepted Solution

by:
footloose earned 100 total points
ID: 1315343
OK, let's try again: t004024's earlier suggestion on using GetSysMenu works. I tried this out, and the close button is disabled. Thui's earlier suggestion to trap WM_SYSCOMMAND still has to be carried out if you want to prevent Ctrl-F4 from closing the child window.

Override CChildFrame::Create as below:

BOOL CChildFrame::Create(  LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                                                     DWORD dwStyle, const RECT& rect,
                                                     CMDIFrameWnd* pParentWnd, CCreateContext* pContext )
{
   if ( CMDIChildWnd::Create( lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd,
                                                    pContext ) )
   {
      CMenu *p = GetSystemMenu( FALSE );
      p->RemoveMenu( 5, MF_BYPOSITION );
      p->RemoveMenu( 5, MF_BYPOSITION );

      return TRUE;
   }

   return FALSE;
}

0
 

Author Comment

by:nchenkin
ID: 1315344
Footloose, Thanks it worked!

But I wound up combining your suggesstion with t004024's comment. The final code is:

BOOL CChildFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                         DWORD dwStyle, const RECT& rect,
                         CMDIFrameWnd* pParentWnd, CCreateContext* pContext)
{
   if ( CMDIChildWnd::Create( lpszClassName, lpszWindowName, dwStyle,
                              rect, pParentWnd, pContext ) )
   {
      CMenu *p = GetSystemMenu( FALSE );
      p->RemoveMenu( SC_CLOSE, MF_BYCOMMAND );
      return TRUE;
   }
   return FALSE;
}

This gets rid of having to call RemoveMenu twice as your example required (why is that?!),
and also changes the hardcoded '5' to a friendlier SC_CLOSE symbol.

I realize I also need to implement Thui's trap.
Thanks all for your help.
0
 

Expert Comment

by:footloose
ID: 1315345
Final comment: RemoveMenu is called twice because you have to remove CLOSE first and then the seperator below it. Otherwise you get two seperators one next to another.
0
 

Author Comment

by:nchenkin
ID: 1315346
Footloose, A final comment to your final comment:

Gotcha. Given that, I'll probably put the 2nd call back in to get rid of the seperator.
Thanks for the clarification.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
VB.NET how to use the Vertical ScrollBar 5 114
How to know only "File created" with EventLog 3 35
how to split multiple lines delimiter : 8 111
Problem to App source 6 73
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question