Home arrow C++ arrow Page 2 - Modifying the System Menu in C++ with MFC
C++

Modifying the System Menu in C++ with MFC


Did you know that you can modify the Windows system menu from C++ using MFC? In this article Ben shows you exactly how to do it.

Author Info:
By: Ben Watson
Rating: 4 stars4 stars4 stars4 stars4 stars / 23
January 01, 2003
TABLE OF CONTENTS:
  1. · Modifying the System Menu in C++ with MFC
  2. · Modifying the System Menu in C with MFC
  3. · Conclusion

print this article
SEARCH DEVARTICLES

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.
blog comments powered by Disqus
C++ ARTICLES

- Intel Threading Building Blocks
- Threading Building Blocks with C++
- Video Memory Programming in Text Mode
- More Tricks to Gain Speed in Programming Con...
- Easy and Efficient Programming for Contests
- Preparing For Programming Contests
- Programming Contests: Why Bother?
- Polymorphism in C++
- Overview of Virtual Functions
- Inheritance in C++
- Extending the Basic Streams in C++
- Using Stringstreams in C++
- Custom Stream Manipulation in C++
- General Stream Manipulation in C++
- Serialize Your Class into Streams in C++

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials