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.
UINT AfxMessageBox(HWND hWnd, UINT nIDText, UINT nType, UINT nIDHelp = 0)
{
CString s;
s.LoadString(nIDText);
return AfxMessageBox(hWnd, s, nType, nIDHelp);
}
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;
mbp.lpszCaption = AfxGetAppName();
if (nIDHelp != 0)
{
mbp.dwStyle = nType | MB_HELP;
}
else
{
mbp.dwStyle = nType;
}
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.