XBalloonMsg - a non-MFC balloon-shaped message box






4.99/5 (66 votes)
XBalloonMsg displays a message box using balloon-style tooltips. Message and title strings may be embedded or stored in string resource.
Introduction
I was inspired to create XBalloonMsg when I saw great article by Paul Roberts, CBalloonMsg. I like balloon messages because visually they seem to be more lightweight and less obtrusive than standard message box:
Standard![]() |
XBalloonMsg![]() |
This is ideal way to draw user's attention to a control or area of the screen. I decided to learn more about balloon tooltips which are used to show balloon messages, and find out how to integrate them in my projects.
XBalloonMsg Features and Behaviors
Here are features I wanted in XBalloonMsg:![]() |
The balloon message box should display until some user action occurs - clicking mouse, pressing key (including Esc key), changing focus to another window, etc. - or until a specified time interval has passed. |
![]() |
In addition to closing balloon message box after user action
mentioned above, there should be close button (![]() |
![]() |
You should be able to specify title and message strings either embedded or as resource IDs. |
![]() |
It should be possible to display very long message strings - longer than the
standard 80-character strings you are limited to with
LPSTR_TEXTCALLBACK tooltips.
|
![]() |
MFC should not be used, to allow for use in any C++ project. |
![]() |
The balloon message box should work properly on Vista. |
![]() |
In case balloon tips are disabled in registry, regular (rectangular) tooltip should be displayed. |
The programmatic interface to XBalloonMsg is very simple: just two functions, one of which you only need if you want to dismiss message balloon for some particular reason:
Function | Description |
---|---|
void Show() | Show balloon message |
void Destroy() | Remove balloon message from screen |
Show() Function
Here are details forShow()
function:
Show
The Show function creates, displays, and operates a balloon message box. The message box contains an application-defined message and title, a close button, and an optional icon. void Show(
LPCTSTR lpszTitle,
);
LPCTSTR lpszMsg, HWND hCtrl, HWND hParent, HINSTANCE hInstance, UINT nIcon = TTI_INFO, BOOL bUseBalloonTips = TRUE, UINT nTimeOutSeconds = 0, LPRECT pRect = NULL Parameters lpszTitle
[in] Pointer to a null-terminated string that contains the balloon message
title. If this parameter is NULL, no title and no icon will be displayed.
The special symbol LPCTSTR_DEFAULT_TITLE may be used; it will cause the
executable module name to be displayed.
lpszMsg
[in] Pointer to a null-terminated string that contains the balloon message
to be displayed. Must not be null. Text callbacks
( LPSTR_TEXTCALLBACK ) are not used, so the text string can be as
long as you want, up to the size of the internal text buffer
m_szMsg .
hCtrl
[in] Handle to the control that the message is being displayed for.
Must not be null.
hParent
[in] Handle to the parent window of the control. Must not be null.
hInstance
[in] Handle to the instance of the module that contains the
string resource. May be null if string resource is not used.
nIcon
[in] Specifies the icon to associate with the balloon message.
This can be one of the following values:
bUseBalloonTips
This parameter may also be the handle of an icon obtained from LoadIcon or LoadImage functions. If not present, this parameter defaults to TTI_INFO.
[in] Specifies whether balloon tips are to be used to display the message.
If this parameter is TRUE, balloon tips will be used unless disabled
in the registry. If this parameter is FALSE, regular tooltips will be used,
regardless of value of registry key.
If not present, this parameter defaults to TRUE.
nTimeOutSeconds
[in] Specifies the number of seconds before the
balloon message is automatically closed. If
this parameter is zero, the balloon message
will not be automatically closed. If not
present, this parameter defaults to zero.
pRect
[in] Pointer to a RECT struct that contains position where balloon message
is to be displayed. May be null if default position should be used.
If not present, this parameter defaults to null.
bSubclassParent
[in] Specifies whether parent is to be subclassed. Not subclassing
parent will cause a slight loss in functionality - clicking on another
app will not dismiss the balloon message.
If not present, this parameter defaults to TRUE.
NOTE: Using XBalloonMsgDll.dll with VB.net apps requires that this parameter be FALSE. |
Implementation Notes
I started by trying to get balloon message to display:m_hWndBalloon = ::CreateWindowEx(0, TOOLTIPS_CLASS, 0, WS_POPUP | WS_VISIBLE | TTS_ALWAYSTIP | TTS_NOPREFIX | TTS_BALLOON | TTS_CLOSE | TTS_NOFADE | TTS_NOANIMATE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, 0, 0, 0);This worked, except that close button (

Now that I have balloon message displayed,
how to get rid of it? Clicking close button of course works,
but what if user clicks on another window? I have taken care of
this in other projects by using TTF_SUBCLASS
flag.
This time, TTF_SUBCLASS
has no effect.
After trying several things to get this to work,
I give up and decide to subclass the parent window myself,
looking for specific messages that would indicate that user
is doing something, and so message balloon should be dismissed.
After implementing this,
I verify that this approach works by clicking on dialog caption,
clicking on another control, clicking on dialog background, and
clicking on another window.
All of these actions now dismiss the message balloon.
However, things are still not working quite right. Some keys (arrow keys, function keys) are just ignored. What's worse, the Esc key causes the balloon tip to disappear, but also closes the dialog! The solution to these problems was to install a keyboard hook using the SetWindowsHookEx() function. This allowed me to catch the keystrokes that a user would expect to dismiss the balloon tip.
XBalloonMsgDLL |
![]() |
XBalloonMsgShow()
, which takes same parameters
as CXBalloonMsg::Show()
(see above).
The download includes Visual Basic projects for both VS6 and VS2005,
that show how to use DLL with VB:
XBalloonMsgShow()
's
nIcon parameter:
Value | SDK Symbol | Meaning |
---|---|---|
0 | TTI_NONE | Use no icon |
1 | TTI_INFO |
Use the information icon ![]() |
2 | TTI_WARNING |
Use the warning icon ![]() |
3 | TTI_ERROR |
Use the error icon ![]() |
10 | — |
Use the XP help icon ![]() |
11 | — |
Use the Vista help icon ![]() |
12 | — |
Use the question icon ![]() |
Depending on whether your application is running on XP or Vista, you can select the appropriate help icon. Here is code from C++ demo app that checks for Vista:
BOOL IsVista() { BOOL rc = FALSE; OSVERSIONINFO osvi = { 0 }; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osvi)) { if ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osvi.dwMajorVersion >= 6)) { rc = TRUE; } } return rc; }
This is how DLL's XBalloonMsgShow()
function is called
from VB6 (please see Form1.frm for complete code to VB app):
Private Sub ShowMessage(nIcon As Long)
Dim ptCursor As POINTAPI
Dim hWndOver As Long
Dim l As Long
Call GetCursorPos(ptCursor) ' Get cursor position
hWndOver = WindowFromPoint(ptCursor.X, ptCursor.Y) ' Get window cursor is over
l = XBalloonMsgShow("My Title", "This is My Message", _
hWndOver, GetParent(hWndOver), 0, nIcon, 1, 0, 0, 1)
End Sub
For VB2005, the last parameter (bSubclassParent) must be
FALSE
:
Private Sub ShowMessage(nIcon As Integer)
Dim ptCursor As POINTAPI
Dim hWndOver As Integer
Dim l As Integer
Call GetCursorPos(ptCursor) ' Get cursor position
hWndOver = WindowFromPoint(ptCursor.X, ptCursor.Y) ' Get window cursor is over
l = XBalloonMsgShow("My Title", "This is My Message", _
hWndOver, GetParent(hWndOver), 0, nIcon, 1, 0, 0, 0)
End Sub
C++ Demo App
Here is what demo app looks like:
If you do not want to use balloon messages (or cannot because registry setting disables them), regular tooltip will be displayed:
LPSTR_TEXTCALLBACK
) are not used:
‘What's This’ Help
In the above screenshot, notice


![]() |
![]() |
![]() |
On Vista you will see similar message balloon:
The tooltip control has built-in support for info, warning, and error icons,
but none for help icon (
![]()
The help.ico files contain multiple formats - from 16x16x16 to 48x48x32.
To reduce the size, I edited them (using excellent
ArtIcons Pro
icon editor)
to remove everything but the 32bpp formats. To ensure that correct
size (16x16) was loaded, I used |
This technique allows you to have What's This help for any control without having to create a help file. Here is code that displays What's This help balloon:
//============================================================================= BOOL CXBalloonMsgTestDlg::OnHelpInfo(HELPINFO* pHelpInfo) //============================================================================= { CString s = _T(""); // the string resource id is the same as control id if (s.LoadString(pHelpInfo->iCtrlId)) { CXBalloonMsg::Show(_T("What's This? Help"), s, ::GetDlgItem(m_hWnd, pHelpInfo->iCtrlId), m_hWnd, AfxGetInstanceHandle(), (UINT)m_hHelp); } else if (pHelpInfo->iCtrlId != -1) // ignore clicking on dialog box { s.Format(_T("There is no help for control #%d.\r\n") _T("Please click on another control."), pHelpInfo->iCtrlId); CXBalloonMsg::Show(_T("Help Unavailable"), s, ::GetDlgItem(m_hWnd, pHelpInfo->iCtrlId), m_hWnd, AfxGetInstanceHandle(), TTI_INFO); } return TRUE; }
One final note about What's This help: it is customary to use Shift+F1 to invoke What's This help. However, in MFC by default the F1 key (unshifted) will activate What's This help. The following code will restore the Windows standard behaviors for F1 and Shift+F1.
//============================================================================= BOOL CXBalloonMsgTestDlg::PreTranslateMessage(MSG* pMsg) //============================================================================= { BOOL rc = TRUE; // Trap the famous undocumented F1 key message. Windows normally // responds to this message by sending the WM_HELP message (referred // to as WM_HELPINFO in MFC), which we use to enter What's This // (Shift+F1) help mode. This override makes unshifted F1 call // the normal Help function, and makes shifted F1 invoke the // What's This help. if (pMsg->message == 0x004D) { if (GetKeyState(VK_SHIFT) & 0x8000) SendMessage(WM_SYSCOMMAND, SC_CONTEXTHELP); else OnHelp(); } else { rc = CDialog::PreTranslateMessage(pMsg); } return rc; } //============================================================================= void CXBalloonMsgTestDlg::OnHelp() //============================================================================= { // Here you can implement full-blown F1 help }
If you want to add What's This help to a dialog, you must also select the
extended style Context help in dialog properties. One gotcha: you
can't have a minimize or maximize box at the same time, or the
What's This button won't be displayed.
|
Balloon Tip Registry Key
On most systems, balloon tips are enabled by default. However, there is registry key that may be set that will disable balloon tips from displaying. If balloon tips are disabled, this has unfortunate effect of preventing any tooltip created withTTS_BALLOON
style from displaying - it does not
automatically fall back to displaying a regular tooltip.
To handle this situation, XBalloonMsg checks
HKEY_CURRENT_USER
registry key
Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\EnableBalloonTipsand if it is set to 0,
TTS_BALLOON
style
will not be used. This allows regular tooltips to be displayed:
How to use
Step 1 - Add Files
To integrateCXBalloonMsg
into your app,
you first need to add following files to your project:
- XBalloonMsg.h
- XBalloonMsg.cpp
The .cpp file should be set to Not using precompiled header in Visual Studio. Otherwise, you will get error
fatal error C1010: unexpected end of file while looking for precompiled header directive
XBalloonMsg.h should be included in whatever module you intend to use
XBalloonMsg in. Also, if you want to implement What's This
help, you should add one or both of the help icon files included with the demo.
Step 2 - Call CXBalloonMsg::Show()
TheCXBalloonMsg::Show()
function
displays message balloon, and may be called using
embedded strings like this:
CXBalloonMsg::Show(_T("Edit1 Info "), _T("This is an info string for Edit1."), m_ctrlEdit1.m_hWnd, m_hWnd, AfxGetInstanceHandle(), TTI_INFO);or using string resource IDs like this:
CXBalloonMsg::Show(MAKEINTRESOURCE(IDS_EDIT2_INFO_TITLE), MAKEINTRESOURCE(IDS_EDIT2_INFO_MSG), m_ctrlEdit2.m_hWnd, m_hWnd, AfxGetInstanceHandle(), TTI_INFO);Internally there is just one function used for both calls. The
function determines whether
the calling parameter is resource id or string,
by inspection of high-order word of pointer:
// is the message a string or a resource id?
if (HIWORD(lpszMsg) == 0)
{
// id
UINT nID = LOWORD((UINT)(UINT_PTR)lpszMsg);
if (!::LoadString(hInstance, nID, m_szMsg, sizeof(m_szMsg)/sizeof(TCHAR)-2))
{
XBALLOONMSGTRACE(_T("ERROR - failed to load message string %d\n"), nID);
_ASSERTE(FALSE);
}
}
else
{
// string
_tcsncpy(m_szMsg, lpszMsg, sizeof(m_szMsg)/sizeof(TCHAR)-2);
}
Revision History
Version 1.3 - 2008 July 11
- Added parameter to control parent subclassing
- Added separate VB and DLL projects for VS6 and VS2005
- Added example of timed XBalloonMsg
Version 1.2 - 2008 July 2
-
Added help (question mark) icons to DLL and expanded VB demo
Version 1.1 - 2008 July 1
- Added DLL project and VB demo program
Version 1.0 - 2008 June 23
- Initial public release
Usage
This software is released into the public domain. You are free to use it
in any way you like, except that you may not sell this source code. If you
modify it or extend it, please to consider posting new code here for everyone
to share. This software is provided "as is" with no expressed or implied
warranty. I accept no liability for any damage or loss of business that
this software may cause.