Click here to Skip to main content
Click here to Skip to main content

Balloon Help as a non-modal replacement for MessageBox()

By , 7 Aug 2002
 
Release #3: Previous release: Ports:

Update Notes

The primary reason for this release is a bug I found with the open location feature: it would access deallocated memory! In addition, I've worked in a few other changes to make writing custom LaunchBalloon() methods easier, fixed a bug in the demo, and added two new options:

unDELAY_CLOSE works in tandem with a timeout value to delay the action caused by the other unCLOSE_* options. This allows you to keep a balloon active indefinately (until the user gets back from coffee break, etc. and has time to take a look at it). For long timeout values, I'd advise also using unSHOW_CLOSE_BUTTON so the user can still get rid of it quickly if need be.

unDISABLE_XP_SHADOW is exactly what it sounds like: if set, that cool dropshadow XP uses for tooltips and menus isn't shown. Note that the user can also disable dropshadows globally, in which case this option has no effect.

I want to add some new demos, there are more things that can be done with this than what I'm currently demonstrating, but I felt these bug fixes needed to be released, and I'm probably too lazy to get the demos done as soon as i'd like anyway. So, I'll do another update when they are finished. In the meantime, Rama Krishna either has already, or will soon be releasing his .NET Version, so there'll be plenty of Balloon Goodness around. :)

Balloons
CBalloonHelp test app, running under Windows XP.

Introduction
Using CBalloonHelp
API
   Important stuff
   SetAnchorPoint()
   SetBackgroundColor()
   SetForegroundColor()
   SetTitle()
   SetContent()
   SetTitleFont()
   SetContentFont()
   SetURL()
   SetIcon()
   LaunchBalloon()
Features
Compatibility
Internals
Updates
Related Articles
TODO
Thanks

Introduction

I hate message boxes.

Or really, I hate MessageBox()s. Something about having a form of output sooo convenient, a single function call, no need for resources to be added, for interfaces to be designed, for any planning or preparation at all – not even a window handle is needed (!) – seems almost to force programmers to use it whenever there is any doubt about what the user should know. Is there a chance a user will perform an action in error? Better get confirmation... Just pop up a MessageBox()!  I can't delete a file in the windows explorer without having to click through at least one MessageBox(). Am I sure? But, the file is executable... Am i really sure? But, it might affect registered programs... Am I really, really sure? ... If a check box was provided to let you hide the message in the future... But that would require extra effort, and there's this ready to use, almost good enough function that will suffice...

But worse yet are programs that feel the need to inform you, after performing an action that you explicitly requested, that the action has indeed been performed, using – you guessed it – MessageBox(). Nothing wrong with a little feedback, especially if the action had effects not necessarily intuitive to first-time users, but to do it in a way that requires you to stop what you're doing, (and what is sometimes worse, what the program is doing) just to acknowledge it... That is not funny.

OK...

Enough hypocritical griping however. Solutions do exist – creating message boxes with check boxes or “yes to all” / “no to all” buttons is not difficult. For the purpose of feedback, displaying a short message in a status bar will often suffice, or possibly adding a log pane. But both of these options really only work for the main window of an application, and have other drawbacks in terms of visibility and screen real-estate as well.

With Windows 2000, Microsoft began a practice of using balloons (of the comic strip dialog variety) for displaying messages from system tray icons. This seems to work quite well; when I dial into the Internet, once the connection is made, a small icon appears in the tray, along with a balloon giving details on my connection speed. A MessageBox() here would be inexcusable, but a balloon is small, unobtrusive, and does not require any action on my part. After a few seconds, it quietly fades away. Windows XP provides this feature for many more tray icons, from system updates to the activation reminder, adding another feature to them in the form of a close button that will dismiss the balloon instantly, in case I'm annoyed by it and don't want to wait for it to time out. (Windows XP also uses similar balloons in other situations, but that fits more in line with the general XP aping of MacOS...)

Note that balloons as described above are not ToolTips. ToolTips, also in use by tray icons by the way, serve well in their current form: small unobtrusive pieces of text that show up when you hover the mouse over a control, and disappear immediately upon moving the mouse away. Anyone who has used BalloonHelp on the MacOS (Ref: http://developer.apple.com/techpubs/mac/HIGuidelines/HIGuidelines-240.html) should know the advantages Microsoft's ToolTips have when used for this purpose.

With Internet Explorer 5 and later, Microsoft make the Balloon ToolTip style available for general use (via the TTS_BALLOON style). But it is not very simple to use, and of course not useable at all on systems without IE5.

So get to the point already...

The point of all this of course is that I've written an easy to use balloon control. I stress easy to use: in order to convince myself and others to go this way, I wanted it to be as easy to pop up a help balloon as popping up a MessageBox().

Using CBalloonHelp

Add BalloonHelp.cpp and BalloonHelp.h in your project.

API

The important stuff

The easiest way to create a balloon is to use the LaunchBalloon() static function:

void CBalloonHelp::LaunchBalloon(const CString& strTitle, 
                                 const CString& strContent, 
      const CPoint& ptAnchor, 
      LPCTSTR szIcon /*= IDI_EXCLAMATION*/
      unsigned int unOptions /*= unSHOW_CLOSE_BUTTON*/,
      CWnd* pParentWnd /*= NULL*/,
      const CString strURL /*= ""*/,
      unsigned int unTimeout /*= 10000*/)

This will allocate a new CBalloonHelp object, create the window, and show it. When the window closes, the CBalloonHelp object will be deleted automatically. Parameters are as follows:

strTitle    //  Title of balloon

strContent  //  Content of balloon

ptAnchor    //  point tail of balloon  will  be "anchor"ed to.
            //  This is  in client coordinates if pParentWnd is given, 
            //  otherwise it is in screen coordinates.

szIcon      //  One of:
            //    IDI_APPLICATION
            //    IDI_INFORMATION IDI_ASTERISK (same)
            //    IDI_ERROR IDI_HAND (same)
            //    IDI_EXCLAMATION IDI_WARNING (same)
            //    IDI_QUESTION
            //    IDI_WINLOGO

unOptions   /*  One or more of: 
     unCLOSE_ON_LBUTTON_DOWN |  closes window on WM_LBUTTON_DOWN
     unCLOSE_ON_MBUTTON_DOWN |  closes window on WM_MBUTTON_DOWN
     unCLOSE_ON_RBUTTON_DOWN |  closes window on WM_RBUTTON_DOWN
     unCLOSE_ON_LBUTTON_UP   |  closes window on WM_LBUTTON_UP
     unCLOSE_ON_MBUTTON_UP   |  closes window on WM_MBUTTON_UP
     unCLOSE_ON_RBUTTON_UP   |  closes window on WM_RBUTTON_UP
     unCLOSE_ON_MOUSE_MOVE   |  closes window when user moves mouse 
                             |    past threshhold
     unCLOSE_ON_KEYPRESS     |  closes window on the next keypress message 
                                 sent to this thread.
     unCLOSE_ON_ANYTHING     |  all of the above.
     unDELAY_CLOSE           |  when a user action triggers the close, 
                             |   begins timer.  closes when timer expires.
     unSHOW_CLOSE_BUTTON     |  shows close button in upper right
     unSHOW_INNER_SHADOW     |  draw inner shadow in balloon
     unSHOW_TOPMOST          |  place balloon above all other windows
     unDISABLE_XP_SHADOW     |  disable Windows XP's drop-shadow effect 
                             |   (overrides system and user settings)
     unDISABLE_FADE          |  disable the fade-in/fade-out effects 
                             |   (overrides system and user settings)
     unDISABLE_FADEIN        |  disable the fade-in effect
     unDISABLE_FADEOUT       |  disable the fade-out effect
*/

pParentWnd  //  Parent window/anchor window.  If NULL, balloon will be 
            //  anchored in screen coordinates, and owned by the 
            //  application's main window.
strURL      //  If not empty, when the balloon is clicked ShellExecute() 
            //  will be called, with strURL passed in.
unTimeout   //  If not 0, balloon will automatically close after unTimeout 
            //  milliseconds.

Use:

CBalloonHelp::LaunchBalloon("BoogaBooga", 
     "What the hell is \"Booga Booga\" supposed to mean, anyway?", 
     CPoint(0,0));

CBalloonHelp::LaunchBalloon("You are holding down the right mouse button!", 
     "Blah", Cpoint(0,0), IDI_WARNING, 
      CballoonHelp::unCLOSE_ON_RBUTTON_UP|CBalloonHelp::unSHOW_INNER_SHADOW, 
                                          this, "", 0);

The first line above will show a balloon with the title “BoogaBooga” and associated message anchored to the top left corner of the screen (point is in screen coordinates). Ideally, you'd anchor it to something more meaningful, such as the center of a control, or a status bar icon. The default options will cause this balloon to disappear after 10 seconds, and to show the standard information icon at top left, and a close button at top right.

The second line above will show a balloon, this time anchored to the top left corner of the window represented by this, this time with the standard warning icon. The CBalloonHelp::unCLOSE_ON_RBUTTON_UP option will cause it to be destroyed when the right mouse button is released – if a mouse button is being held down, then mouse input is captured, so the balloon will close whenever the right mouse button is released. If no mouse button is held down, the user will have to release the right mouse button somewhere in a window owned by the same thread in order for it to close. The CballoonHelp::unSHOW_INNER_SHADOW option will cause the balloon to be drawn with an inner hilight and shadow... Not all that interesting, but if you're not running on Windows XP, it's the only shadow you can get.

It is also possible to create a balloon using the Create function, in which case you can opt not to have the object automatically deleted when the window closes (the LaunchBalloon function always adds the option CBalloonHelp::unDELETE_THIS_ON_CLOSE to force this, but it may not be desirable if, for instance, you allocate a CBalloonHelp object from the stack). This function gives much greater potential for customization as well (see below for more info).

Complete API

<a name="API Create"></a>BOOL CBalloonHelp::Create(const CString& strTitle, 
               const CString& strContent, 
               const CPoint& ptAnchor, unsigned int unOptions,
               CWnd* pParentWnd /*=NULL*/,
               const CString strURL /*= ""*/,
               unsigned int unTimeout /*= 0*/,
               HICON hIcon /*= NULL*/);
      

This will create and display a balloon window. Title and content override any set for the object prior to this call. ptAnchor indicates anchor location in screen coordinates. unOptions should be a combination of one or more of the following:

CBalloonHelp::unCLOSE_ON_LBUTTON_DOWN //  closes window on WM_LBUTTON_DOWN
CBalloonHelp::unCLOSE_ON_MBUTTON_DOWN //  closes window on WM_MBUTTON_DOWN
CBalloonHelp::unCLOSE_ON_RBUTTON_DOWN //  closes window on WM_RBUTTON_DOWN
CBalloonHelp::unCLOSE_ON_LBUTTON_UP   //  closes window on WM_LBUTTON_UP
CBalloonHelp::unCLOSE_ON_MBUTTON_UP   //  closes window on WM_MBUTTON_UP
CBalloonHelp::unCLOSE_ON_RBUTTON_UP   //  closes window on WM_RBUTTON_UP
CBalloonHelp::unCLOSE_ON_RBUTTON_UP   //  closes window on WM_RBUTTON_UP
CBalloonHelp::unCLOSE_ON_MOUSE_MOVE   //  closes window when user moves mouse past 
                                      //  threshhold
CBalloonHelp::unCLOSE_ON_KEYPRESS     //  closes window on the next keypress message sent
                                      //  to this thread.
CBalloonHelp::unCLOSE_ON_ANYTHING;    //  all of the above
CBalloonHelp::unDELAY_CLOSE;          //  when a user action triggers the close, 
                                      //  begins timer.  closes when timer expires.
CBalloonHelp::unDELETE_THIS_ON_CLOSE  //  deletes object when window is closed.  Used by 
                                      //  LaunchBalloon(), use with care
CBalloonHelp::unSHOW_CLOSE_BUTTON     //  shows close button in upper right
CBalloonHelp::unSHOW_INNER_SHADOW     //  draw inner shadow in balloon
CBalloonHelp::unSHOW_TOPMOST          //  place balloon above all other windows
CBalloonHelp::unDISABLE_XP_SHADOW;    //  disable Windows XP's drop-shadow effect 
                                      //  (overrides system and user settings)
CBalloonHelp::unDISABLE_FADE          //  disable the fade-in/fade-out effects 
                                      //  (overrides system and user settings)
CBalloonHelp::unDISABLE_FADEIN        //  disable the fade-in effect
CBalloonHelp::unDISABLE_FADEOUT       //  disable the fade-out effect
      

If pParentWnd is NULL, the balloon will be anchored in screen coordinates, and owned by the application's main window (AfxGetMainWnd()). If there is no main window, and pParentWnd is NULL, creation will fail. strURL if not empty will be passed to ShellExecute() when the balloon is clicked. If not 0, unTimeout specifies the time in milliseconds until the balloon closes automatically. And hIcon if not NULL specifies the icon shown in the upper left corner of the balloon; it is copied on creation, so the icon can safely be destroyed after Create() returns.

<a name="API SetAnchorPoint"></a>void CBalloonHelp::SetAnchorPoint(CPoint ptAnchor, CWnd* pWndAnchor = NULL);      

Sets the point to which the balloon is anchored (the point the balloon's tail attaches to). Calling this before the balloon is created has no effect, since the anchor is a required parameter of Create(). If pWndAnchor is NULL, ptAnchor is assumed to be in screen coordinates, otherwise it is assumed to be relative to the client area of pWndAnchor

<a name="API SetBackgroundColor"></a>void CBalloonHelp::SetBackgroundColor(COLORREF crBackground);

Sets the background color of the balloon. Can be called before or after the balloon is created.

<a name="API SetForegroundColor"></a>void CBalloonHelp::SetForegroundColor(COLORREF crForeground);

Sets the foreground (borders & text) color of the balloon. Can be called before or after the balloon is created.

<a name="API SetTitle"></a>void CBalloonHelp::SetTitle(const CString& strTitle);

Sets the title of the balloon. Can be called before or after the balloon is created.

<a name="API SetContent"></a>void CBalloonHelp::SetContent(const CString& strContent);

Sets the content of the balloon. Can be called before or after the balloon is created.

<a name="API SetTitleFont"></a>void CBalloonHelp::SetTitleFont(CFont* pFont);

Sets the font used to draw the title of the balloon. Can be called before or after the balloon is created. The font and the CFont object are stored and eventually deleted by the balloon; do not use either after calling this function.

<a name="API SetContentFont"></a>void CBalloonHelp::SetContentFont(CFont* pFont);    

Sets the font used to draw the contents of the balloon. Can be called before or after the balloon is created. If this is called before creation, and the title font is not explicitly set (via SetTitleFont()) then a bold version of this font is used for the title (even if this font is already bold). The font and the CFont object are stored and eventually deleted by the balloon; do not use either after calling this function.

<a name="API SetURL"></a>void CBalloonHelp::SetURL(const CString& strURL);    

Sets the URL or file to be opened by the balloon when clicked. Set to "" to disable. Can be called before or after the balloon is created.

<a name="API SetIcon"></a>void CBalloonHelp::SetIcon(HICON hIcon);    

Sets the icon shown at the top left of the balloon. Pass in NULL to show no icon. Icon will not be scaled. Can be called before or after the balloon is created.

void CBalloonHelp::SetIcon(HBITMAP hBitmap, COLORREF crMask);
      

Sets the icon shown at the top left of the balloon. crMask indicates transparent color. Pass in NULL for hBitmap to show no icon. Icon will not be scaled. Can be called before or after the balloon is created.

void CBalloonHelp::SetIcon(HBITMAP hBitmap, HBITMAP hMask);

Sets the icon shown at the top left of the balloon. hMask indicates the transparent areas. Both parameters must be valid. Icon will not be scaled. Can be called before or after the balloon is created.

void CBalloonHelp::SetIcon(CImageList* pImageList, int nIconIndex);

Sets the icon shown at the top left of the balloon. nIconIndex indicates image to use. Both parameters must be valid. Icon will not be scaled. Can be called before or after the balloon is created.

<a name="API LaunchBalloon"></a>void CBalloonHelp::LaunchBalloon(const CString& strTitle, 
               const CString& strContent, 
               const CPoint& ptAnchor, 
               LPCTSTR szIcon /*= IDI_EXCLAMATION*/,
               unsigned int unOptions /*= unSHOW_CLOSE_BUTTON*/,
               CWnd* pParentWnd /*= NULL*/,
               const CString strURL /*= ""*/,
               unsigned int unTimeout /*= 10000*/)

Creates and shows a balloon. This is a static function, so calling this on an instance of CBalloonHelp is not too useful. If you need more control, create a derived class, or use Create() and associated property functions. See Use for more information.

Features

  • Easy to use interface.
  • Adjusts position depending on anchor position; window will always be completely visible, assuming content size is less than screen size.
  • Uses translucency effects if available.
  • Uses drop-shadow effect if available.

Compatibility

Tested on Windows XP, 2000, 98, and 95

Compiles with VC++ 6.0 / MFC 6 and VC++.NET / MFC 7

Internals

CBalloonHelp is an MFC class, derived from CWnd. The first time a balloon is created, a window class named “BalloonHelpClass” is registered. First, a window class with the CS_DROPSHADOW style is registered; if registration fails, the style is removed, and registration is attempted again. This allows use of the style on Windows XP, while avoiding problems on previous versions of Windows.

The window is created hidden, and then the size of the content and title are calculated. Margins and space for the tail are added to this, and the window is sized and positioned relative to the anchor point. Finally, the window region is set and the window is shown.

Tip: when doing shaped windows, put the shaped bits in the non-client area; it's a lot easier to deal with if you don't have to account for that stuff when dealing with drawing the client area.

AnimateWindow() is used for the fade-in/fade-out effects if available and requested.

Messsage hooks are used to determine when closing mouse actions occur.

Andrew Nosenko's CAuxThunk implementation (renamed to _ThunkImpl) is used for implementing message hooks.

Updates

8/2/02

  • Fixed bug in demo where div by zero balloon would be shown at wrong position.
  • Fixed bug where deallocated memory was accessed when using the strURL parameter to open a file or location when the balloon was clicked.
  • Added option: CBalloonHelp::unDELAY_CLOSE.
  • Added option: CBalloonHelp::unDISABLE_XP_SHADOW.

5/30/02

  • Posted Maximilian Hänel's WTL port.
  • Release #2 (arbitrary number, but needed something)
  • Added support for multiple monitors
  • Added support for closing on WM_*BUTTON_DOWN messages.
  • Added support for anchoring to windows (move with parent).
  • Reworked message hook code, taken mostly from Max's WTL port.

1/23/02

  • Posted Fil Mackay's ATL port

12/31/01

  • Changed utilization of transparency (again), hopefully this will workaround problems with Win2k
  • Altered border calculation code slightly
  • Fixed bug where no title would cause balloon to be full screen sized.

12/21/01

  • Expanded API to allow greater customization
  • Added example of balloon created manually that moves with parent window
  • Implemented keyboard hooks to allow close-on-keypress
  • Separate flags to disable fade-in/fade-out
  • Smooth scaling of small icons used for LauchBalloon() (on Win2k/XP only)
  • Misc. code cleanup.

12/12/01

  • Fixed bug with mouse not being released until fade-out had completed.
  • Added option for disabling fade effects; this is forced if the user has disabled them via the control panel.
  • Added option for making balloons topmost windows.

Related Articles

TODO

Clean up code a bit... most of it is pretty straight forward, but documentation could be better.

Move to straight Win32, not MFC derived class.

Add better code walkthrough to this article.

Thanks...

...Jan van den Baard for showing me the right way to use AnimateWindow(), and for demonstrating how WM_NCHITTEST can be used to provide hot tracking. Check out his ClassLib library on CP!

...Maximilian Hänel for his WTL port, and for demonstrating therein a nicer way to handle message hooks.

...To all the people who've provided feedback, positive and negative. It all helps.

...To Mustafa Demirhan, for his suggestion and information on using keyboard hooks.

...To The Code Project, for providing a useable forum for all of us.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Shog9
Software Developer
United States United States
Member
Poke...

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
BugFlicker free with fade flag.memberdchris_med7 Mar '12 - 21:42 
It seems that there is a big problem when using fade. At least on w7 aero it is quite annoying. This happens when fade flag is set. You can test the bug on the demo exe provided at the top of this page.
 
I found the cause of the problem.
 
Here is the fix. Find:
DWORD dwExStyle = WS_EX_TOOLWINDOW;
 
and add the correct flag for the window:
 
   if(NULL != m_fnAnimateWindow ){
	   if (!(m_unOptions&unDISABLE_FADEIN))
		   dwExStyle = WS_EX_TOOLWINDOW|WS_EX_LAYERED;
   }
 
This should give you a flicker free faded tray baloon. Wink | ;)
QuestionRight to Leftmembertomajabvs31 Aug '11 - 23:25 
Hello,
Is there support for RTL reading order?
 
Thanks,
Dragan.
GeneralVS 2010memberSteve Wisnieski23 Mar '11 - 5:09 
Will not compile on VS2010
 
balloonhelp.cpp(205): error C3867: 'CBalloonHelp::KeyboardHookProc': function call missing argument list; use '&CBalloonHelp::KeyboardHookProc' to create a pointer to member
balloonhelp.cpp(206): error C3867: 'CBalloonHelp::MouseHookProc': function call missing argument list; use '&CBalloonHelp::MouseHookProc' to create a pointer to member
balloonhelp.cpp(207): error C3867: 'CBalloonHelp::CallWndRetProc': function call missing argument list; use '&CBalloonHelp::CallWndRetProc' to create a pointer to member
balloonhelp.cpp(1085): error C2440: 'static_cast' : cannot convert from 'UINT (__thiscall CBalloonHelp::* )(CPoint)' to 'LRESULT (__thiscall CWnd::* )(CPoint)'
1> Cast from base to derived requires dynamic_cast or static_cast
GeneralRe: VS 2010memberliyuncheng25 Mar '11 - 17:35 
Just change KeyBoardHookProc to &CBalloonHelp::KeyBoardHookProc and it would help!
GeneralRuntime error 2 Stack corruption - Warning about this classmembernamezero1111118 Aug '10 - 15:48 
Hello everyone!
 
I just discovered that in Visual Studio 2010 this class will cause random stack corruption due to the line "pragma pack(push,1)". The data alignment instruction is NOT reset at the end of the header file, so classes that include this header may suffer from improper data alignment.
You can safely delete this line and that class still works!
 
Note that older visual studios may not show a stack corruption error, and that the error isn't always evident even in Vs2k10, but may manifest in strange behavior of the program.
GeneralRe: Runtime error 2 Stack corruption - Warning about this classmembershoek11 Oct '10 - 10:15 
There is a #pragma pack(pop) instruction at the end of the _ThunkImpl declaration. Wouldn't this reset things properly?
 
Do you remove that line as well?
AnswerCrash c0000005 on CBalloonHelp::Create()memberVasiliy Zverev23 Mar '10 - 3:13 
Versions that use class _ThunkImpl (Release #3, #2 and WTL port) are not Data Execution Prevention (DEP) compliant. I.e. _ThunkImpl dynamicly generates machine instructions, saves it as data and then tries to execute. If DEP is enabled (Start->right-click My Computer->Properties->Advanced System Settings->Performance, Settings->Data Execution Prevention tab->Turn on for all programs...), balloon window creation throws exception 0xc0000005 (access violation) with stack trace similar to this:
0105f920()	
user32.dll!_DispatchHookA@16()  + 0x52 bytes	
user32.dll!_fnHkINLPCWPRETSTRUCTA@20()  + 0x5e bytes	
user32.dll!___fnINLPCREATESTRUCT@4()  + 0x56 bytes	
ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x13 bytes	
user32.dll!_NtUserCreateWindowEx@60()  + 0xc bytes	
user32.dll!__CreateWindowEx@52()  + 0xb1 bytes	
user32.dll!_CreateWindowExA@48()  + 0x33 bytes	
mfc80.dll!AfxCtxCreateWindowExA() + 0x60 bytes
mfc80.dll!CWnd::CreateEx() + 0x29 bytes
mfc80.dll!CWnd::CreateEx() + 0x3f bytes
myapp!CBalloonHelp::Create() + 0x41 bytes
myapp!CBalloonHelp::CBalloonHelp()
 
To fix it, add in _ThunkImpl::InitThunk()
	DWORD dwOldProt = 0;
	VirtualProtect(this, sizeof(*this), PAGE_EXECUTE_READWRITE, &dwOldProt);
right before
	FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this));
So that the final function looks like:
  void InitThunk(TMFP method, T* pThis)
  {
    union { DWORD func; TMFP method; } addr;
    addr.method = (TMFP)method;
    m_mov = 0xB9;
    m_this = reinterpret_cast<DWORD>(pThis);
    m_jmp = 0xE9;
    m_relproc = addr.func - reinterpret_cast<DWORD>(this+1);
    DWORD dwOldProt = 0;
    VirtualProtect(this, sizeof(*this), PAGE_EXECUTE_READWRITE, &dwOldProt);
    FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this));
  }
 
I borrowed this solution from the latest sources of CAuxThunk by Andrew Nosenko who originally wrote _ThunkImpl class.
GeneralRe: Crash c0000005 on CBalloonHelp::Create()memberNaryoril30 Jun '10 - 0:37 
Thank you very much mate
 
This solved an issue i had.
Interestingly i only had this error when compiling the project with Visual Studio 2010. If the exe is compiled with Visual Studio 2005 it works fine even without your fix...
GeneralRe: Crash c0000005 on CBalloonHelp::Create()memberETA8 Oct '10 - 0:01 
Just found the same solution and was just adding my comment.
The I found your comment.... Same solution but some months ago...
Would have save my an hour or two. Thanks for sharing !
Greetings from The Netherlands

GeneralGetting crashed in IE8memberDec123430 Jun '09 - 1:14 
I am using this balloon with ActiveX component that runs under IE, everything is fine till IE7. But in IE8 it gets crashed(to be very specific in CreateEx()) funtion. Another clue is, this crash is not happening in all machines, but in few machines.
 
Your help is much appreciated.
QuestionHow to integrate with C#?memberMember 409275318 Jan '09 - 20:17 
Hi Shog,
Thank you for sharing the application.This was the one I searched for long time.Is it possible to integrate this Balloon Help in C# application .As a C# Developer, I need your help on this.
 
Thanks,
Mathi.
AnswerRe: How to integrate with C#?sitebuilderShog926 Jan '09 - 7:30 
There are several native .NET implementations. For instance:
http://www.codeproject.com/KB/miscctrl/balloonnet.aspx[^]
 
You must be careful in the forest
Broken glass and rusty nails
If you're to bring back something for us
I have bullets for sale...

QuestionDo not use the second screenmemberNacereddine31 Mar '08 - 0:10 
Hi, I'm using the balloon control a will in my app, but when i tried it on a configuration with two screens, it does not display on the second screen !
 
What's wrong ? please any indication to resolve this issue.
 
btw, good work Rose | [Rose]
GeneralRe: Do not use the second screensitebuilderShog931 Mar '08 - 4:54 
The balloon will appear on the same screen as the anchor point you specify.
 
Citizen 20.1.01
'The question is,' said Humpty Dumpty, 'which is to be master - that's all.'

QuestionCan we specify the side for the AnchorPoint?memberjlundberg19 Sep '07 - 6:26 
I want to have my Balloon on the top with the AnchorPoint at the bottom. Anyone know how to do this?
 
John
GeneralResource leakmemberbryan_f18 Sep '07 - 9:29 
In CBalloonHelp::SetIconScaled, there is a call to CBitmap::CreateCompatibleBitmap for bmpIcon, but there is no call to CBitmap::DeleteObject. According to the documentation for CreateCompatibleBitmap, deletion of the bitmap object is required.
GeneralRe: Resource leaksitebuilderShog911 Oct '07 - 17:43 
The call is made in the destructor for CGdiObject (from which CBitmap is derived).

 
every night, i kneel at the foot of my bed and thank the Great Overseeing Politicians for protecting my freedoms by reducing their number, as if they were deer in a state park. -- Chris Losinger, Online Poker Players?

GeneralClosingmemberjlundberg17 Sep '07 - 3:24 
Hello,
 
What is the best way to manually close a Balloon? I will be using one or both of these types:
 
CBalloonHelp::LaunchBalloon("test1",
"I'm here", CPoint(0,200), IDI_WARNING,
CBalloonHelp::unCLOSE_ON_RBUTTON_UP|CBalloonHelp::unSHOW_INNER_SHADOW, this, "", 0);
 
or
 

CRect rect;
GetClientRect(&rect);
bhPersistent.Create("2", "Press Here", (0,80), CBalloonHelp::unSHOW_TOPMOST|CBalloonHelp::unSHOW_INNER_SHADOW|CBalloonHelp::unDISABLE_XP_SHADOW, this);
 
I want to keep the original dialog up and just display balloons that I can close not using a timmer or user interface.
 
Please let me know if you can help.
 
Thanks,
 
John
 

GeneralWindow activation / fixmemberJoergen Sigvardsson13 Sep '07 - 1:19 
Hello again,
 
one thing that annoyed me a little, is that the balloon tip is activated when clicked. This produces unnecessary flicker. The solution is to return MA_NOACTIVATE from OnMouseActivate().
 

GeneralBugfixmemberJoergen Sigvardsson12 Sep '07 - 23:39 
Hey Shog,
 
there's a small bug regarding the delay close. If I interpret your header file correctly, the balloon should close itself after a delay, if I specify unDELAY_CLOSE. Unfortunately, its logic is reversed.
void ShowBalloon(void)
{
   ShowWindow(SW_SHOWNOACTIVATE);
   if ( !(m_unOptions&unDELAY_CLOSE) )
      SetTimeout(m_unTimeout);     // start close timer
}
You should remove the !, I think. Smile | :)
 

GeneralRe: BugfixsitebuilderShog913 Sep '07 - 4:43 
Joergen Sigvardsson wrote:
If I interpret your header file correctly, the balloon should close itself after a delay

Not quite - you can always specify a timeout after which the balloon will close; unDELAY_CLOSE changes the meaning of this timeout such that it doesn't start when the balloon is shown, but waits until some other action occurs.

 
every night, i kneel at the foot of my bed and thank the Great Overseeing Politicians for protecting my freedoms by reducing their number, as if they were deer in a state park. -- Chris Losinger, Online Poker Players?

Questionother IconsmemberTieter11 Sep '07 - 0:59 
Hello,
 
againt my cpmliment to this great work!
Does anybody know how to use my own icons in the balloon?
In the comment of tze code I found the following:
 
// szIcon | One of:
// IDI_APPLICATION
// IDI_INFORMATION IDI_ASTERISK (same)
// IDI_ERROR IDI_HAND (same)
// IDI_EXCLAMATION IDI_WARNING (same)
// IDI_QUESTION
// IDI_WINLOGO
// NULL (no icon)
// unIconID | ID of icon to display (loaded from resources)
 
I do not know how to handle the unIconID.
 
Thank you for your help
GeneralGreat, Thanks, and a couple of wrapersmemberDan Bloomquist10 Sep '07 - 13:55 

I think it great that I could just include your cpp and go. (vc7.1) Here are a couple of wrappers I added to hide the class where I will use it.
 
void ShowBalloonHelp( LPCTSTR strTittle, LPCTSTR strContent, HWND hControl )
{
     WINDOWINFO info;
     ::GetWindowInfo( hControl, &info );
     CRect rect( info.rcClient );
     CBalloonHelp::LaunchBalloon( strTittle, strContent, rect.BottomRight( ), IDI_ERROR,
          CBalloonHelp::unCLOSE_ON_KEYPRESS | CBalloonHelp::unDELAY_CLOSE, NULL, "", 3000 );  
}
 
void ShowBalloonHelpEdit( LPCTSTR strTittle, LPCTSTR strContent, CEdit& cEdit )
{
     ASSERT( DYNAMIC_DOWNCAST( CEdit, &cEdit ) );
     ShowBalloonHelp( strTittle, strContent, cEdit );
     ::SetFocus( cEdit );
     cEdit.SetSel( 0, -1 );
}
 
And the use becomes:
...
     cAdjust.GetWindowText( t );
     if( _ttol( t ) < -120 || _ttol( t ) > 120 )
     {
          ShowBalloonHelpEdit(
               _T("Out of Range Entry")
               ,_T("Please enter an 'Adjustment' between -120 and 120")
               ,cAdjust
          );
          pDX->Fail( );
     }
...
 
It works great!
Thanks, Dan.

GeneralUnable to pop up balloon from tray icon - pls helpmemberanuradhabhakta28 Aug '07 - 7:38 
Hi,
 
I am trying to use CBalloonHelp::LaunchBalloon() from a tray icon, which is launched using CSystemTray (downloaded from code project).
 
The balloon is popped up from the tray icon but when I move the cursor over the displayed balloon, mouse changes to hour glass. I am neither able to click the mouse or exit the balloon pop up. I have to explicitly kill the exe to come out of it.
 
CBalloonHelp::LaunchBalloon("Well...", "\tWhat do you think? Is this good? Is this useful? Does it need a lot of work? Or is it a complete waste of time... Let me know your thoughts!\n\n\tClick this balloon to send me some feedback...",
ptIcon, IDI_QUESTION, CBalloonHelp::unSHOW_CLOSE_BUTTON|
CBalloonHelp::unSHOW_TOPMOST |
CBalloonHelp::unCLOSE_ON_LBUTTON_DOWN,
this , "", 10);
Please let me know what could be wrong.
 
Also, strangely, if I launch the balloon from the dialog box, which is obtained by right clicking my icon, the balloon pop up works perfectly fine. Looks like the window pointer that is passed to the LaunchBalloon is causing issue. Can someone let me know what could be wrong.
 
Thanks in advance,
Anu

 
AnuradhaBhakta
GeneralA fixed versionmemberDaniel Cohen Gindi16 Aug '07 - 0:14 
I have modified the code to not use the dumb Thunk tehcnique,
because it does not allow you to port to another CPU architecture
I have implemented another technique, so still every instance of the class can get its own hook procedure!
And I have made also some more improvements...
 
I have sent the code to the author, hopefully he will post it here...
 
-----
Daniel Cohen Gindi
danielgindi (at) gmail dot com

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 8 Aug 2002
Article Copyright 2001 by Shog9
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid