Adding a ToolTip to a Nonbutton Control

If your toolbar contains a nonbutton control, you have to do a bit more work to support ToolTips. In my sample, I created a combo box and then parented it to the toolbar. To add a ToolTip to this control, the application must send the TTM_ADDTOOL message to the ToolTip control (or use the MFC AddTool member function). It also needs to trap the WM_MOUSEMOVE, WM_LBUTTONDOWN, and WM_LBUTTONUP messages in the window procedure for the combo box and pass these on to the ToolTip control so that it will know to pop up the ToolTip for the combo box. The following C code demonstrates these steps:

// This code is in the main window procedure after the
combo box
// has been created.
// Set the window procedure for the combo box.
lpfnDefCombo = (WNDPROC) GetWindowLong (hWndCombo, GWL_WNDPROC);
SetWindowLong (hWndCombo, GWL_WNDPROC, (LONG)ComboWndProc);

// Get the handle to the ToolTip window.
hWndTT = (HWND) SendMessage (hWndToolbar, TB_GETTOOLTIPS, 0, 0);

if (hWndTT)
{
// Fill out the TOOLINFO structure.
lpToolInfo.cbSize = sizeof (lpToolInfo);
// The uID is the handle of the tool (the combo box).
lpToolInfo.uFlags = TTF_IDISHWND | TTF_CENTERTIP;
// The string ID in the resource
lpToolInfo.lpszText = (LPSTR)IDM_COMBO;
// The window that gets the ToolTip messages
lpToolInfo.hwnd = hWnd;
// The tool
lpToolInfo.uId = (UINT)hWndCombo;
// The instance that owns the string resource
lpToolInfo.hinst = hInst;

// Set up the ToolTip for the combo box.
SendMessage (hWndTT, TTM_ADDTOOL, 0,
(LPARAM)(LPTOOLINFO)&lpToolInfo);
}
§

// This function relays the mouse messages from the combo box
// to get the ToolTip to work.
LRESULT CALLBACK ComboWndProc (HWND hWnd, UINT uMessage, WPARAM wParam,
LPARAM lParam)
{
switch (uMessage)
{
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
{
MSG msg;
HWND hWndTT;
msg.lParam = lParam;
msg.wParam = wParam;
msg.message = uMessage;
msg.hwnd = hWnd;
hWndTT = (HWND) SendMessage (hWndToolbar, TB_GETTOOLTIPS, 0, 0);
SendMessage (hWndTT, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg);
break;
}
}
return CallWindowProc (lpfnDefCombo, hWnd, uMessage, wParam, lParam);
}

The corresponding MFC procedure is similar. One change I made was to create a class for my combo-box control derived from CComboBox and use ClassWizard to create a message map to WindowProc. Within this function, I did the same type of processing—except that it was less tedious to fill out the message structure. Instead, I was able to call CWnd::GetCurrentMessage.