Thursday, November 15, 2007

Deal menus dynamically!!

Many commercial applications developed for Windows allow the user to customize the menus of the application. This ability introduces some complexity when the application must update particular menu items at certain times. Here we discuss how to perform this task.

Windows sends a WM_INITMENUPOPUP message just before a pop-up menu is displayed.We can modify menus dynamically by handling WM_INITMENUPOPUP message on our own. A sample code to achieve this is shown below:

// OnInitMenuPopup() is the framework provided handling function for WM_INITMENUPOPUP

void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)

{

CFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);

if(if( m_bFirstTime )

{

if( 0 == nIndex ) // Menu index....

pPopupMenu->InsertMenu(0, // Position to insert

MF_BYPOSITION,

1000 // ID of the new menu item…This should be unique..

_T("My menu item") );

m_bFirstTime = false;

}

}

The above code will insert the specified string into the menu with index 0( Usually File menu ). In OnInitMenuPopup() function, we receive the pointer to the menu that is being expanded. So we can use this pointer to add, insert or delete items from that menu at will.

Now there is a question of how to add a command-handler for this new item. We can’t add code into the message map since the menu is added dynamically. For that we may resort to the OnCmdMsg() viirtual function provided by the framework. We have to override it in our application. This function is called by the framework, each time a user selects a menu command or the menu is being updated. So we can handle menu commands as well as enable/disable menu items using this function. The following is a glance on how to implement this function ourselves:

BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

if(1000 == nID && CN_COMMAND == nCode )

AfxMessageBox( "My menu item accessed. ");

return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

}

Size of an empty class

Most of us are aware that the size of object of an empty class is 1 byte( It is !! ). Have you ever thought why it is so? It is implemented likewise to ensure that the addresses of two different objects will be different. For the same reason, "new" for an empty class always returns pointers to distinct objects. For example :

               class Empty { };
 
               void f()
               {
                               Empty a, b;
                               if (&a == &b) cout << "Change your object concepts";
 
                               Empty* p1 = new Empty;
                               Empty* p2 = new Empty;
                               if (p1 == p2) cout << " Which new is this?? ";
               }              
 

There is another interesting rule that says that an empty base class need not be represented by a separate byte:

               struct X : Empty
              {          
                   int a;
              };
 
               void f(X* p)
               {
                               void* p1 = p;
                               void* p2 = &p->a;
                               if (p1 == p2) cout << "Well, the base class has no bytes";
               }
 

This optimization is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead. Some current compilers provide this "empty base class optimization".

Rename the Start button!

Here’s a method to rename the ‘Start’ button of Windows. I haven’t tried this myself. You may try this based on your convenience.

To rename the start button, you will need a hex editor.For example you can use UltraEdit. Then perform the following steps:

  1. Copy the \windows\explore.exe file to a new name (e.g. explorer_1.exe)
  2. With the hex editor, open that file and go to offset 412b6
  3. You will see the word start with blanks between each letter
  4. Edit it be any 5 characters or less
  5. Save the file
  6. Boot to DOS
  7. Copy the existing c:\windows\explorer.exe to explorer.org
  8. Copy explorer_1.exe to explorer.exe
  9. You will also need to replace the explorer.exe in the c:\windows\system32\dllcache file as well with the new one.

Note: If the partition is NTFS and you can't access the files from DOS:

  1. Start Regedit
  2. Go to HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Winlogon.
  3. Change the value of Shell from Explorer.exe to explorer_1.exe