Click here to Skip to main content
Click here to Skip to main content

Modifying the System Menu

, 26 Jan 2007
Rate this:
Please Sign up or sign in to vote.
Add menu items to, and learn how to handle the system menu

Introduction

This is another in my "techniques I really use" series of short articles that don't discuss theory or design patterns, or any of that other hoity-toity stuff. This article is about simply getting something done. So without wasting any more of your time than I already have, let's get started.

Doing the Deed

The system menu is the menu that's displayed when you right-click on the application's icon in the title bar. The act of changing the system menu is fairly simple. Just add the following code to your application's InitInstance function:

HMENU pSysMenu = ::GetSystemMenu(m_pMainWnd->GetSafeHwnd(), FALSE);
if (pSysMenu)
{
    ::InsertMenu(pSysMenu, 0, MF_BYPOSITION | MF_STRING, ID_SHOW_MESSAGE1, <BR>                 "Show Message 1");
    ::InsertMenu(pSysMenu, 1, MF_BYPOSITION | MF_STRING, ID_SHOW_MESSAGE2, <BR>                 "Show Message 2");
    ::InsertMenu(pSysMenu, 2, MF_BYPOSITION | MF_SEPARATOR, 0, "");
}

After you retrieve the menu, simply add your new menu items to it. In the code above, we added our custom menu items to the top of the menu, and separated them from the original menu items with a menu separator. Easy stuff.

Next, we need to add our menu item IDs to the resource.h file. The easiest way to do this is to simply add a new menu to the application's resources, and create the menu items in the new menu. Well, it's kind of easy. When I did this, and then tried to add handlers via the Properties view for the CMainFrame message map, the ID's showed up as 32771 and 32772 instead of the names I gave them. I had to go back and re-display the menu resource and change the ID names in order for them to show up properly in the message map. Sometimes VS2005 just pisses me off. In any case, I then went back and added the handlers in CMainFrame.

The final step is to add a handler for the Windows WM_SYSCOMMAND message. Once you've added the handler, replace the contents of the function with the following code:

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam)
{
    bool bRecognized = false;
    // We have to pass all system commands to the base handler. In <BR>    // ClinicBoard1, we needed to override to use the following switch <BR>    // condtion:
    //
    //        switch (wParam & 0xFFF0)
    //
    // Starting with VS2005, they're passing the actual message ID instead of 
    // a WPARAM, so we don't have to do that anymore. jms - 25JAN2007
    switch (nID)
    {
        case SC_CLOSE:
        case SC_HOTKEY:
        case SC_HSCROLL:
        case SC_KEYMENU:
        case SC_MAXIMIZE:
        case SC_MINIMIZE:
        case SC_MOUSEMENU:
        case SC_MOVE:
        case SC_NEXTWINDOW:
        case SC_PREVWINDOW:
        case SC_RESTORE:
        case SC_SCREENSAVE:
        case SC_SIZE:
        case SC_TASKLIST:
        case SC_VSCROLL:
        case 61587: // show the system menu
        case 61443: // allow window resizing by click/dragging the main window <BR>                    // borders
/*
        // no longer supported in VS2005/MFC8?
        case SC_ARRANGE:
    #if(WINVER >= 0x0400)
        case SC_DEFAULT:
        case SC_MONITORPOWER:
        case SC_CONTEXTHELP:
        case SC_SEPARATOR:
    #endif
*/
            CFrameWnd::OnSysCommand(nID, lParam);
            return;
    }

    switch (nID)
    {
        case ID_SHOW_MESSAGE1 :
        case ID_SHOW_MESSAGE2 :
            PostMessage(WM_COMMAND, nID, 0);
            break;
    }

}

First, we need to allow the function to process system commands. If none were processed we'll stillbe in the function (after handling a system command, the first switch statement returns to the calling function) and we can process our own commands. Since we have handlers for them in our CMainFrame class, we'll just post the message to our CMainFrame window.

Note About OnSysCommand

In VS2005 (or maybe even VS2003), the OnSysCommand() function was modified as follows:

  • In prior versions of the function, the first parameter was a WPARAM, with the lower word containing information used by Windows, and the upper word being the actual ID of the selected command, and it was up to the programmer to strip the lower word in order to determine the command being sent. In VS2005, MFC strips the lower word for you, thus leading to the next change.
  • The first parameter passed to the function was changed from a WPARAM to a UINT. This made things on our side of the function just a wee bit simpler because in the case of the function above, we no longer had to do this - switch(wParam&0xFFF0) - in order to get to the message ID.
  • The list of handled messages appears to have shrunk. As you can see in the code above, I commented out several message IDs not specifically listed in MSDN.
  • It seems that MSDN does not provide a complete list of system messages that this command can process. While testing the sample app, I discovered the following issues:

    • Left-clicking the application icon will not present the system menu to the user. Right-clicking will, and the menu items will work.

    • The user will be unable to click in the main menu of your application.

    • The user will not be able to resize the window by click/dragging the borders of the main window.

    • The buttons that minimize/maximize/close the window (on the right side of the title bar) appear to work normally.

    To fix all of these issues, you have to add the following case items to the code above:

    case 61587: // show the system menu
    case 61443: // allow window resizing by click/dragging the main window <BR>            // borders

    I did a search in the MFC/SDK source code, and these two message ID's are NOT defined anywhere. C'mon Microsoft - you're sure getting sloppy in your old age.

Disclaimers and Other Notes

As usual, I'm asking that you vote the article and not my politics. Isn't it a dirty rotten shame that I have to add this to every one of my articles? No, it's not because of my politics, but because some people here don't know when to leave their politics out of their voting considerations.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

John Simmons / outlaw programmer
Software Developer (Senior)
United States United States
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.
 
My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.

Comments and Discussions

 
QuestionOverriding Winform's System menu for a user control C# Sample Pinmemberekhanlari17-Feb-13 12:40 
GeneralMy vote of 5 PinmemberNigam Patel2-Jan-12 17:56 
GeneralLearned something new PinmvpHans Dietrich26-Jan-07 7:00 
GeneralNo, THIS is the thanks you get PinmemberWes Aday26-Jan-07 4:17 
GeneralSo This is The Thanks I Get... PinmvpJohn Simmons / outlaw programmer26-Jan-07 4:14 
GeneralRe: So This is The Thanks I Get... PinmvpRama Krishna Vavilala26-Jan-07 4:21 
GeneralRe: So This is The Thanks I Get... PinmemberThomas Stockwell26-Jan-07 4:32 
GeneralRe: So This is The Thanks I Get... PinmvpJohn Simmons / outlaw programmer26-Jan-07 4:35 
GeneralRe: So This is The Thanks I Get... PinmvpHans Dietrich26-Jan-07 7:06 
GeneralNot a proper way to handle the system messages PinmvpRama Krishna Vavilala26-Jan-07 4:13 
GeneralRe: Not a proper way to handle the system messages PinmvpJohn Simmons / outlaw programmer26-Jan-07 4:17 
GeneralRe: Not a proper way to handle the system messages PinmvpRama Krishna Vavilala26-Jan-07 4:19 
GeneralRe: Not a proper way to handle the system messages PinmvpJohn Simmons / outlaw programmer26-Jan-07 4:31 
GeneralRe: Not a proper way to handle the system messages PinmvpNishant Sivakumar26-Jan-07 4:40 
GeneralRe: Not a proper way to handle the system messages PinmvpJohn Simmons / outlaw programmer26-Jan-07 4:42 
GeneralRe: Not a proper way to handle the system messages PinmemberJason Henderson26-Jan-07 5:26 
GeneralRe: Not a proper way to handle the system messages PinmemberMember 85635788-Apr-12 21:18 
GeneralRe: Not a proper way to handle the system messages PinmemberPaul Conrad24-Oct-08 7:24 
GeneralRe: Not a proper way to handle the system messages PinmvpJohn Simmons / outlaw programmer24-Oct-08 8:48 
GeneralRe: Not a proper way to handle the system messages PinmemberPaul Conrad24-Oct-08 10:57 
GeneralRe: Not a proper way to handle the system messages PinmvpRama Krishna Vavilala26-Jan-07 4:22 
GeneralRe: Not a proper way to handle the system messages PinmemberMark Salsbery26-Jan-07 8:08 
GeneralRe: Not a proper way to handle the system messages PinmvpNishant Sivakumar26-Jan-07 4:20 
GeneralRe: Not a proper way to handle the system messages PinmvpJohn Simmons / outlaw programmer26-Jan-07 4:33 
GeneralRe: Not a proper way to handle the system messages PinmemberGil Clark26-Jan-07 7:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 26 Jan 2007
Article Copyright 2007 by John Simmons / outlaw programmer
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid