If you use the auto upgrade to convert this to the 2008 format, you will find it no longer works properly. This has nothing to do with the code, but rather a change to the tooltip control implementation. The WM_NOTIFY message in the wndproc uses the NMHDR struct to get notifications on tooltip state changes via the 'code' struct member, in 2008, the 'code' integer always returns 0. I have no idea why this is, or what internal alteration precipitated the change, but I do have a simple fix for the code.
In the WndProc: WM_NOTIFY | WM_REFLECT case, add the following code:
nM.code = TTN_POP;
nM.code = TTN_SHOW;
So the beginning of the switch should now look like this:
case (WM_NOTIFY | WM_REFLECT):
NMHDR nM = new NMHDR(0);
RtlMoveMemory(ref nM, m.LParam, Marshal.SizeOf(nM));
if (nM.hwndFrom == _hTipWnd)
nM.code = TTN_POP;
nM.code = TTN_SHOW;
A really nice control, I've began using it after the windows ToolTip failed me miserably (not too hard to achieve that).
But, I'm having a problem here - I've registered to the RightMouseUp event and:
A. You have a small bug where you actually raise the RightMouseDown event instead (found easily via a Null reference exception).
B. SOMETIMES, can't really figure out yet when - the DrawEventArgs have invalid information, i.e. the Caption and other fields hold junk instead of the info of the clicked ToolTip. I noticed you get this info via a SendMessage but couldn't trace the source of the error.
first: thanks for this great control. I would like to to display the tooltip automatically from control load event handler. I tried Show method but it don't work. Is there any way to display control without hovering over bound control?
This is not what the 'show' command is for, (ex. would be: reshowing after a timeout, or manual mousemove trigger). Much of what is going on with timers and window itself, is being done inside (mfc)tooltip window class, not this hosting class, so mouse must be over control, and it must be visible in order to start timers. Not sure what you are trying to do, (intro window maybe?), but you could create a static window to do it.
Hi, I'm trying to show a tooltip in a modal dialog window fired from a VS add-in, but the tooltips don't work. Also, on my machine (Vista Ultimate), some of the borders and shadows of the tooltip drift a pixel or two from the tooltip itself. Do you know how it can be fixed?
Shadows are seperate windows drawn by the system not the tooltip or this class. I am also using Vista ultimate though, and it looks fine here. As for modal window from add in, are you passing in the handle of the dialog or the add in?
I have no idea what control/code you are using so.. what I would do, is set a breakpoint within the wndproc and see what messages are coming through. If messages are absent, then window target message pump might be consuming necessary messages. Also, some windows can not be subclassed, they will return no messages, I can't remember if system dialog is one of them, check msdn.
You make a convincing argument for the case of API over .NET and I'm not experienced enough to argue effectively either way. However, given the success of .NET there must be some advantage that translates to an advantage for the developer (besides being lazy enough to not want to learn the API calls). Arguably that advantage comes when performance and speed are not a critical factor. There are probably tens of thousands of small, targeted business applications written in .NET that work perfectly for the task with no perceptible disadvantage by the user - perhaps the true litmus test. BTW: excellent article, very well composed -- a true 5.
I think .Net methods offer a great many advantages, like solving many versioning issues (dll hell), regimentation and standardization of methods, and lends itself well to rapid deployment. I also think that the building block method of programming is the way of the future, as underlying systems evolve in complexity, it will necessitate a more distinct seperation between application developers and system designers. But.. we are not there yet. For the time being, I think in matters where speed and efficiancy are critical design elements in your application, the use of api must be considered, and that the best approach should be a marriage between .Net methods, and the use of api. The main point I am trying to drive home here is, that api is far from being depreciated, and is a very valuable tool in this language, and in a programmers skill set.
Congrats on the nice article and the efforts you have put in it (you've got my 5). I have one comment on the model you have chosen - you assume that as far as the Tooltip is Alive, it is associated with a Win32 Handle (a simple property set like Active uses the SendMessage API). However, you may want to use it in certain cases (like Design-time) where Handle is not needed. Or you may want to instanciate it and display it later on. I think it is a good practise to create (and destroy) its Handle on demand (like System.Windows.Forms.Control does).
I could move the createwindow call out of the constructor and allow it to be created manually, and I did consider this. The only problem is that I would have to test the handle for validity in every property/method, because developer may be attempting to set properties before creating the tooltip window with the creation method. Most implementations that I have seen (in C), create the tooltip as a standing member of the application, that is, it is alive and waiting from the point when the application is first initialized. The ToolTip class itself does not have a very large footprint, (basically a static window with timers and drawing functionality), so I think this is a reasonable way to implement the class.
It has nothing to do with the footprint - it is just a semantic used through all Windows Forms - there is a distinct separation between a Control and its Handle. The Control, as an object, may exists without a Handle created. Its Handle is created whenever needed, however you may alter its properties even if its Handle is NOT created (managed vs unmanaged resources). This gives you the ability to have a Design-Time support - as seen from 2 comments below, you will have troubles with instanciating your Tooltip at Design-Time. The Control class itself has CreateHandle and DestroyHandle methods which reallocate system resources and destroy them respectively.
So when are you gonna do a custom TabControl for us?
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001