C++
  Home arrow C++ arrow Page 2 - Modifying the System Menu in C++ with MFC
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Sun Developer Network 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
C++

Modifying the System Menu in C++ with MFC
By: Ben Watson
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 14
    2003-01-01

    Table of Contents:
  • Modifying the System Menu in C++ with MFC
  • Modifying the System Menu in C with MFC
  • Conclusion

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    Modifying the System Menu in C++ with MFC - Modifying the System Menu in C with MFC


    (Page 2 of 3 )

    Adding Commands
    Firstly, we need to define a unique variable to represent each menu item. This can be done in the resource.h file or in any standard header file. If the commands already exist as part of another standard or context menu, then this step can be skipped because the definitions already exist.

    However, it's important to note that even if we use the pre-existing definitions, the message handlers for the commands on the regular menu will NOT be automatically called. System commands are routed differently. So, in the end, it doesn't matter if we use the existing definition or create our own.

    For our example, we'll define:

    #define IDM_ABOUT 16
    #define IDM_EXIT 17


    The IDM just means that this variable is a menu-item ID. We add these commands in our window's initializing function (OnInitDialog(), OnCreate()). My example is in a dialog class, so this is what the function looks like:

    BOOL CBabelOnDlg::OnInitDialog()
    {
    CDialog::OnInitDialog();

    // Add "About..." and "Exit" menu items to system menu.

    // Command IDs must be in system range
    // the ANDing is because of a bug in Windows 95

    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    ASSERT((IDM_EXIT & 0xFFF0) == IDM_EXIT);
    ASSERT(IDM_EXIT < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
    pSysMenu->AppendMenu(MF_STRING,IDM_EXIT,"E&xit Program");
    pSysMenu->AppendMenu(MF_SEPARATOR);
    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, "A&bout BabelOn");
    }
    .
    .
    .other initialization


    The first thing that you should notice is a couple of ASSERT statements for each command. The first one deals with a bug present in Windows 95 and the second ensures the custom command is below the range used by pre-defined system commands.

    Here's an exert from the MFC documentation:

    "All predefined Control-menu items have ID numbers greater than 0xF000. If an application adds items to the Control menu, it should use ID numbers less than F000."

    Next, we get a pointer to the system menu with the GetSystemMenu function. We call it with an argument of FALSE to get the pointer. If we call it with TRUE, then it will reset the menu to its default state.

    If the pointer is valid, we call some commands to add to the bottom of the menu, passing the IDs and the string we want to show up when the menu is viewed.

    Simple, isn't it?

    Processing Custom Commands
    In order to have those commands do anything, we can't rely on the normal message-handling mechanism -- even if we have handlers for the same items in other menus. We have to handle the WM_SYSCOMMAND message in our dialog/window class:

    void CBabelOnDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    //trap our own system menu messages
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
    CAboutDlg dlgAbout;
    dlgAbout.DoModal();
    } else if ((nID & 0xFFF0)==SC_CLOSE){
    OnClose();
    } else if ((nID & 0xFFF0)==IDM_EXIT) {
    ::PostQuitMessage(0);
    }

    else {

    CDialog::OnSysCommand(nID, lParam);
    }
    }


    This is the height of simplicity herself. We compare the code that was passed in with the system to our commands, again ANDing them to account for the Windows 95 bug. Then we can call whatever code we want to handle it.

    If we selected Exit, then we post a message to quit the application.

    Take a look at the second test: SC_CLOSE is a predefined menu constant. It's one normally handled by Windows, but we can still add custom processing to it if we want. In this application I didn't want it to exit, but to merely hide the application (with an icon in the system tray). Because of this, I just call a handler that I wrote to do exactly that. If the ID doesn't equal anything that we want to custom-process, then we just pass it on up the hierarchy for default processing.

    The IDs for the most common system commands are:

    SC_CLOSE Close the CWnd object.
    SC_MAXIMIZE (or SC_ZOOM) Maximize the CWnd object.
    SC_MINIMIZE (or SC_ICON) Minimize the CWnd object.
    SC_MOVE Move the CWnd object.
    SC_RESTORE Restore window to normal position and size.
    SC_SIZE Size the CWnd object.

    There are others system commands used in special situations that you can learn about in the documentation for WM_SYSCOMMAND.

    Modifying Existing Commands
    We just saw that it's possible to change the default handling of built-in system commands, but it's also possible to modify existing menu items by changing their text, or to entirely remove them.

    To modify the text of a command, use the ModifyMenu() function on pSysMenu in the above example. For example, to change "Close" to "Hide", I could do this:

    pSysMenu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND,IDM_HIDE, "&Hide");

    The MF_BYCOMMAND argument tells the function to interpret SC_CLOSE as a command ID. IDM_HIDE is a new command ID. The last option is the text we want to show on the menu item.

    Alternatively, we can call ModifyMenu() on the menu item:

    pSysMenu->ModifyMenu(0,MF_BYPOSITION,IDM_HIDE,"&Hide");

    This changes the first menu item to Hide.

    Removing Commands
    Don't want a close command at all on the window? I'm not sure if this is a good idea or not, but you can do it. Here's how:

    pSysMenu->RemoveMenu(SC_CLOSE,MF_BYCOMMMAND);
    pSysMenu->RemoveMenu(0,MF_BYPOSITION);


    The first line of code removes the command associated with SC_CLOSE, while the second removes the first item on the menu.

    More C++ Articles
    More By Ben Watson


     

    C++ ARTICLES

    - Paths and Files
    - Directories in C++
    - Focusing on C++ Files
    - Const Correctness in C++
    - Manipulating Streams and Files with C++
    - Streams and Files
    - Multiplying Large Numbers with Karatsuba`s A...
    - Large Numbers
    - Dijkstra`s Shunting Algorithm with STL and C...
    - Brief Introduction to the STL Containers
    - The Standard Template Library
    - Templates in C++
    - C++ Programmer Alerts
    - C++ Programming Tips
    - First Steps in (C) Programming, conclusion






    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 3 hosted by Hostway
    Stay green...Green IT