65.9K
CodeProject is changing. Read more.
Home

Add a Help Button to a MessageBox

May 24, 2000

viewsIcon

98062

How to add a help button to a MessageBox and associate it with a context-sensitive help ID

Sample Image - mbhelp.gif

Introduction

If you look up the AfxMessageBox function in the MFC documentation, you see that it has the following declarations:


int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );

int AFXAPI AfxMessageBox( UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT) -1 );

You will note that there is a help context ID number passed to the function. The problem is that there is no way to display a help button on the dialog, so the user has no idea that help on the message is available. They can only press F1 to get the help, which is not intuitive, even for advanced users.

The only way to get a Help button on a message box is with a call to ::MessageBoxIndirect. However this requires you to fill out a structure every time you want to use a message box (some UI designers would have no problem with this because it would prevent programmers from putting so many message boxes in their applications, and use of message boxes is considered bad UI design by many). You must also provide a callback function to process the help button command.

An Improved AfxMessageBox Function

I created a new version of AfxMessageBox, which makes a call to ::MessageBoxIndirect. If the help context number is non-zero, a help button is added to the message box. If the help context number is 0, no help button is added.

Note that the first parameter is a handle to the parent window. This allows the compiler to distinguish my AfxMessageBox function from the standard MFC AfxMessageBox function. I have also found that there are times when you explicitly want to provide a handle of the parent window to the message box (such as when invoking from a modeless dialog box). Of course, you can always pass NULL for the handle.

My version of AfxMessageBox also uses the application title as a caption, just like the MFC AfxMessageBox (you have to specify a caption in your call to ::MessageBox in the Windows API). However, you could easily change the function to provide a different caption.


// this version accepts a resource string identifier
UINT AfxMessageBox(HWND hWnd, UINT nIDText, UINT nType, UINT nIDHelp = 0)
{
	CString s;
	s.LoadString(nIDText);
	return AfxMessageBox(hWnd, s, nType, nIDHelp);
}

// this version accepts a text string
UINT AfxMessageBox(HWND hWnd, LPCTSTR szText, UINT nType, UINT nIDHelp = 0)
{
	MSGBOXPARAMS mbp;

	memset(&mbp, 0, sizeof mbp);

	mbp.cbSize = sizeof MSGBOXPARAMS; 
	mbp.hwndOwner = hWnd; 
	mbp.hInstance = AfxGetInstanceHandle(); 
	mbp.lpszText = szText; 

	// if you wanted to specify a different caption, here is where you do it
	mbp.lpszCaption = AfxGetAppName(); 

	// if Help ID is not 0, then add a help button
	if (nIDHelp != 0)
	{
		mbp.dwStyle = nType | MB_HELP; 
	}
	else
	{
		mbp.dwStyle = nType; 
	}

	//  mbp.lpszIcon = ; // note, you could provide your own custom ICON here!

	mbp.dwContextHelpId = nIDHelp; 
	mbp.lpfnMsgBoxCallback = &MsgBoxCallback; 
	mbp.dwLanguageId = 0x0409;
	
	return ::MessageBoxIndirect(&mbp); 
}

The Callback Function -- How to Invoke Help

When the user clicks the Help button, a callback function is invoked, receiving information about the help context number. We must provide the callback function. In the callback function, we simply call CWinApp::WinHelp specifying the correct help context ID.


VOID CALLBACK MsgBoxCallback(LPHELPINFO lpHelpInfo)
{
	AfxGetApp()->WinHelp(lpHelpInfo->dwContextId);
} 


Specifying the Help File

The help file that is invoked for this implementation of AfxMessageBox is specified by the m_pszHelpFilePath member of your CWinApp-derived application class. This member is given a value by default, but it is always best to explicitly specify the location of your help file in your applications OnInitInstance member function. Even this isn't simple because m_pszHelpFilePath is just a pointer. You must explicitly provide the buffer space for the string (refer to MFC documentation of CWinApp::m_pszHelpFilePath for an example of how to do this).

As a final note, adding the Help button to your message boxes is the easy part. The challenge is creating help topics for each message, and implementing the correct context numbers for each message box. Hopefully, the increased user satisfaction, and decreased technical support requirements will make it worth the effort.