Tooltip is never shown again after I click on the button - c++

I want to create a simple tooltip that will pop when user hovers over a button.
To do that I have studied this example from MSDN.
Everything works fine when I first time hover over the button, but after that tooltip never shows up again ( I have checked return values for HWND of the tooltip and for SendMessage( ..., TTM_ADDTOOL, ... ) and there were no errors ).
I have tried to find the solution online, but have failed. The only resource I have found that might be useful is this tutorial but it suggests to subclass the control in order to relay mouse messages to the tooltip control-I will not accept this type of solution because I believe what I ask for is the basic functionality tooltip control provides.
EDITED ON JANUARY 21st 2014:
Following instructions from the link member Stuart suggested* I was able to partially solve the problem. Now tooltip is shown after clicking on the main window's client area and then hovering back over the button.
However, after I click on the button tooltip never shows up again .
Browsing through Internet, I have found this example and after adding these directives:
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")
#pragma comment( lib, "comctl32.lib")
the problem seemed to disappear. Now I was able to click on a button, hover over edit control and edit control's tooltip would appear.
However, after clicking on a button, then clicking on the client area of the main window, and then hovering over the button again its tooltip did not show!
Then I have continued to search over the Internet and have found this article on CodeProject and it does exactly what I need.
So I have started to analyze the source code of the first example and this article. I was unable to see the difference. However, appearances were different! It seems that the article did not use Visual Styles, and taking into the consideration MSDN article member Stuart mentioned, I have started to suspect that this might be the manifest issue.
So I have tried to compile all the programs without the first pragma comment submitted above, but in my test application ( the one created as default Win32 project ) InitCommonControlsEx failed, in the example program I have got error Failed to save the updated manifest to the file ".\Debug\foosyerdoos tooltip.exe.embed.manifest". The parameter is incorrect., and the article application failed to create tooltip controls.
After creating the fresh blank project, and after copying the code from the first example-only this time without pragma comment-SendMessage failed to add both tooltips.
So, without first pragma comment submitted above, I can not use tooltip controls or so it seems.
END OF EDIT
Here are the instruction for creating the minimal example that illustrates the problem:
Create default Win32 project in MS Visual Studio;
Add the bellow WM_CREATE handler:
case WM_CREATE:
{
HWND hButton = CreateWindowEx( 0, L"Button", L"test me!",
WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON,
50, 150, 150, 25, hWnd, (HMENU)8003, hInst, 0 );
HWND hwndTip = CreateWindowEx( NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hWnd, NULL, hInst, NULL );
// Associate the tooltip with the tool.
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hWnd;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hButton;
toolInfo.lpszText = L"test 1";
SendMessage( hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo );
}
return 0L;
Compile and run-tooltip should show on first hover, but never again.
I work on Windows XP, using MS Visual Studio Express 2008.
Visual Styles are enabled, I have linked comctl32.lib and have initiated INITCOMMONCONTROLSEX structure's dwICC member with ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_BAR_CLASSES.
EDIT ( January 31st, 2014 ) :
After testing this very same code snippet on my laptop, which has Windows 7 I can confirm that everything works fine. This is the problem with my Windows XP I guess...
END OF EDIT:
My question is really simple:
How to adjust my code so the tooltip is shown every time user hovers over the button?
Thank you.
Best regards.

You are chasing the wrong problem, this behavior is by design for tooltips. The exact rules it uses are not documented anywhere I know of and I never personally found any need to reverse-engineer it so I can only tell you what I've seen.
The bigger idea behind the feature is that it avoids wearing out the user with info that he already knows. Tooltips were very much designed to be tips, just a sliver of information that isn't crucial to proper operation of the program. It appears to be implemented by keeping track of a tip for a tool already having been displayed and not display it again if the tool was used. Which of course makes a lot of sense, the user doesn't need to be reminded what a tool does after he used it.
There is no message to reset that "the tip was displayed" state. It will reset when it displays the tip for another tool. Altering the tip resets it as well.
I'd reiterate that this is something you should not try to fix. The behavior is perfectly sensible. If it is important anyway then you'll have to take control and display the tip yourself, TTM_ACTIVATE message.

Your code works on my laptop with Windows 7 as you are expecting.
Since this is Microsoft's example, I highly doubt that there is a mistake in it.
To follow the advice of Sherlock Holmes: "Once you eliminate the impossible, all what is left, no matter how improbable, is truth." Since code works, then it must be problem with Windows XP, which can be confirmed with the above follow up comments to your question.
I would check if I have downloaded all automatic updates or would reinstall and try your code again. You could also test your code on other machine running Windows XP to see if your own is the problem.
Good luck.

Related

Pin window to desktop / Glue window to desktop / "Always-on-bottom" window

I'm working on a basic desktop app in C++ / Win32.
My goal right now is to create a basic "sticky note" app that would be pinned / glued to the desktop, i.e always in front of the desktop but always behind of any other application.
Really a personal project there, just to fight my bad memory and have my tasks/notes always visible on the desktop so I couldn't miss them when starting the computer & so on.
The behaviour I'm aiming for would be similar to Stardock Fences ("kind of" because I'm not going to store any desktop icon in there, but you hopefully get the idea)
I started with the sample code from the Get Started with Win32 and C++ docs to have the most basic Win32 minimal window setup.
What I got so far :
I managed to keep my window on bottom of every other app and in front of the desktop by calling SetWindowPos in the window procedure (WindowProc), when handling the event WM_SETFOCUS (I first tried with the event WM_WINDOWPOSCHANGING as suggested in this answer but this resulted in an annoying flickering when dragging the window).
case WM_SETFOCUS:
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
The problem : my window stays in front of the desktop, except when I click on the "Show Desktop" button in the taskbar (or hit the Windows + D shortcut). As I often use this shortcut myself, I'd like my window to stay over the desktop no matter what.
A not-satisfying-enough-but-still-something I managed to do is to bring back my window in front of the desktop when clicking on any other window after hitting Windows + D (this mostly makes sense with multiple monitors, as opening a random app on the first one for example, will toggle back my own app in front of the desktop on another screen).
I could do this using this time the event WM_SIZE and calling ShowWindow then SetWindowPos, still in the WindowProc
case WM_SIZE:
ShowWindow(hwnd, SW_SHOWNORMAL);
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
Not ideal though, as I'd really want my app to always remain in front of the desktop and "survive" to the Show Desktop action.
What I tried :
I checked out those answers but couldn't figure out how to achieve what I want.
How to make 'always-on-bottom'-window
Window “on desktop” : Note on this one, I tried the trick with SetParent like this in the wWinMain
HWND desktop = FindWindow(L"ProgMan", L"Program Manager");
if (desktop == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
SetParent(hwnd, desktop);
However, my app isn't visible at all anymore with this, even though the FindWindow didn't return NULL but an actual handle.
Make aplication always on Bottom (pinned to desktop, behind all other apps) in C++/WinAPI [duplicate]
Disable Minimize, Maximize, Close buttons in Win32 I tried those to "intercept" the Show Desktop event but it seems this event doesn't get fired with the Show Desktop action.
Did I miss something ?
As #JonathanPotter pointed out, when hitting Windows + D or the Show Desktop button, the event WM_WINDOWPOSCHANGING gets fired, and the window gets moved to -32 000, -32 000 (its size also gets changed)
NOTE : a window without the style WS_MINIMIZEBOX seems not receiving WINDOWPOSCHANGING event when hitting Windows + D. Thus, no -32 000 coordinates detection in that case... Also noticed the same issue when using the ex style WS_EX_TOOLWINDOW (as this one gets rid of the minimize box, even if you set the style flag WS_MINIMIZEBOX).
Didn't find a solution for that case, so I'm sticking to an overlapped window.
To prevent this movement, just set the flags SWP_NOMOVE and SWP_NOSIZE on the WINDOWPOS structure passed in the lParam
So as a final result, to achieve the wanted behaviour (i.e always behind every other window but always in front of the desktop), the only needed code to add to the doc's sample is the following, placed in the window procedure WindowProc's switch statement :
EDIT : the best place to force the Z order with HWND_BOTTOM thus ensuring the window is always on bottom is also in the WM_WINDOWPOSCHANGING event. Indeed, calling SetWindowPos to force it in the WM_SIZE event when dragging the window over, as I was doing previously, causes some flickering on the window when resizing it, whereas no flickering occurs when setting directly the hwndInsertAfter property of the WINDOWPOS structure in WM_WINDOWPOSCHANGING.
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* pos = (WINDOWPOS*)lParam;
// Show desktop (Windows + D) results in the window moved to -32000, -32000 and size changed
if (pos->x == -32000) {
// Set the flags to prevent this and "survive" to the desktop toggle
pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
}
// Also force the z order to ensure the window is always on bottom
pos->hwndInsertAfter = HWND_BOTTOM;
return 0;
}
I had the same problem and found a solution via using "autohotkey". autohotkey is a powerful free scripting language for automation in windows that you can download from here. Below scripts are an instance of making sticky notes always on top when you execute it inside a .ahk file (you can copy these codes to a simple notepad and then change .txt to .ahk if you already had installed autohotkey on your computer). by right clicking on .ahk file, you can also see option of Compiling .ahk into .exe which enables you to share it with your other friends too:
#SingleInstance Force
GroupAdd, ontop, Sticky Notes ; you can replace sticky note by any application,
; if you know the name of that application window
; (and its ahk_class for more specific cases).
; for example you can replace "Sticky Notes"
; with "Calculator" to make calculator stay always
; on top.
Loop {
WinWait, ahk_group ontop
WinSet, AlwaysOnTop, On
SoundBeep, 1500
WinWaitClose
SoundBeep, 1000
}
(main codes are credit of mikeyww)

how to make a mfc dialog's height unsizeable?

i am playing with a MFC github project xtrader on github. I managed to get it up running and having one question i cannot understand.
This project is a dialog based MFC based app, the main dialog xTraderDlg, when i run it, i found the height of the dialog is not sizable, however the width does.
i have being read this source for quite some time and review every place that handles SetWindowPos() or OnSize(). There is not traces how this done. Even i comment out the OnSize() or OnInitDialog(), the height remains unchangeable.
the code has some tricks to save the width and height in a config file and reload it next time it is up. but i believe it doesnot matter.
the code also has this line.
::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
However even i remove this line the result is still the same. And SWP_NOSIZE wont cause only the height unsizeable. it is a myth to me indeed.
Can anyone advise me why? main dialog code is here.
https://github.com/lpswufe/xTrader/blob/master/xTraderDlg.cpp
This is done in OnGetMinMaxInfo WM_GETMINMAXINFO.

Flags Windows 7 window always on top INCLUDING the Win7 taskbar (Custom error)

I know a few flags that make the window always on top (eg Qt :: ToolTip, Qt :: WindowStaysOnTopHint, Qt :: Popup), but each time the method is the same problem.
By clicking on the start menu, the area tray, empty field between programs and tray - window and so is hiding.
Everything is fine when I switch between different applications and I click anywhere except the above-mentioned places.
Just run other applications that I used to use, so it might be a function of the uninvited Windows.
Code does not make sense given, because at the same time where do dumb mistake, and indeed act as a flag to be apart of this "small" problem.
These things work:
HWND hWnd = reinterpret_cast(this->winId());
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
But it turns out that exactly the same as the flag of the subject. : (
Explanation of what exactly is the problem:
http://youtu.be/k5TCtr1hPKY
The solution is, regular exercise such thing:
if(this->isActiveWindow() == false} {
this->raise();
}
Only the minimized window does not always work, but to me it is unnecessary.

Scrollbar Appearance Control in Windows 7

I have an application that has a ListView control with scrollbars, and it has the cool looking scrollbars in it automatically:
CreateWindowExW(WS_EX_WINDOWEDGE,L"SysListView32",L"MyList",
WS_CHILD|WS_VISIBLE|LVS_NOSCROLL|LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VSCROLL|LVS_SHOWSELALWAYS| LVS_SINGLESEL,
0,0,500,290,ownerhWnd, (HMENU)0,hInst,NULL);
However, when I create a Scrollbar control manually for another part of the application, it has the older 3d-style look:
CreateWindow(TEXT("SCROLLBAR"), TEXT("MyScrollBar"),
WS_CHILD | WS_VISIBLE | SBS_VERT,0,0, CW_USEDEFAULT,
100, ownerhWnd, (HMENU)10 , NULL, NULL);
How do I get it to have the new look? Is there another control I use, or a style that I can apply to the standard control? I looked into the Flat Scroll Bar, however it says that it is not supported from XP onwards?
Thanks
First, you need to create a manifest for your program that indicates it uses Common Controls version 6. Then you have to call InitCommonControls at program startup.
Details are found on this Microsoft page:
http://msdn.microsoft.com/en-us/library/bb773175%28v=vs.85%29.aspx
Maybe an open door, but you have added a Windows XP/Vista/7 manifest to your application's resources?

Using a manifest causes window to remain partially blank

I am in the process of trying to make an app that has most of its development done in Visual C++ 6.0 adhere to Windows theming, or to be precise the visual styles aspect of it. The application in question is a MFC application with the MBCS characterset. Getting theming to kick in in the first place required the InitCommonControlsEx(...); trick combined with the proper manifests for the Common Controls 6.0. Nothing special thus far.
With all that done, I have tons of windows which have some semblance of drawing glitches showing - white rectangles on the background where there used to be gray like there is in the rest of the window, but they do not hinder.
The biggest troublemaker is in a CDialog descendant that implements an (archaic) 'did you know...' tip dialog. It refuses to draw anything other than the buttons, checkbox and decorative frame the moment the manifest is in place. However, if I take the manifest OUT, everything works fine.
Comparison images right after invoking the dialog
I have already stepped through the OnPaint code (which draws the icon and the 'did you know' text, and all functions return sensible and successful values. I also tried removing the entire customdrawn bits (commented out the mappings for the WM_PAINT and WM_CTLCOLOR messages), but even that caused nothing to show or act different for that matter.
Once I click the 'Next Tip' button, it will properly paint the next tip in the list. However, the customdrawn header with the bulb icon remains missing.
The code really does nothing special that I can spot, and I'm at a loss. Since I suspect the dialog definition is of most help, I'll include that, although I can post other things if people have ideas on where the problems are hiding.
IDD_TIP DIALOG DISCARDABLE 0, 0, 231, 164
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Tip of the Day"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,12,11,207,123
LTEXT "Some String",IDC_TIPSTRING,28,63,177,60
CONTROL "&Show Tips on StartUp",IDC_STARTUP,"Button",
BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,13,146,85,10
PUSHBUTTON "&Next Tip",IDC_NEXTTIP,109,143,50,14,WS_GROUP
DEFPUSHBUTTON "&Close",IDOK,168,143,50,14,WS_GROUP
CONTROL "",IDC_BULB,"Static",SS_BITMAP,20,17,190,111
END
The machine I am testing this on is a W7 64-bit machine running VS2010. The application in question itself is 32-bit.
Edit:
A new day provides new insights. Somehow, the issue is with the handling of the WM_CTLCOLOR message. When I set it to return a NULL_BRUSH, I finally saw things being drawn (that of course blurred on top of another after initial drawing). Nailing it down even further, it seems that when nCtlColor == CTLCOLOR_STATIC, if I return a NULL_BRUSH, stuff will display. The moment I make it a WHITE_BRUSH nothing gets drawn again, however.
Original code:
HBRUSH CTipDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if (pWnd->GetDlgCtrlID() == IDC_TIPSTRING)
return (HBRUSH)GetStockObject(WHITE_BRUSH);
else if (nCtlColor == CTLCOLOR_STATIC)
/* Visual styles enabled causes the things we draw in our WM_PAINT
* to get cleared (and not redrawn) if we do not use a hollow brush here.
* Likely the default behaviour differs when using theming. */
return (HBRUSH)GetStockObject(HOLLOW_BRUSH);
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
Problem solved! The lines that are in bold are what I changed to fix my problem, including the obligatory comments. :)
As far as I know, version 6 of the Common Controls only officially supports Unicode.
According to a blog entry by Raymond Chen, those controls work with the ANSI character set to a degree, but only for backwards compatibility reasons. No one should be using that intentionally.
If you're an ANSI application and you create controls from the common controls library, you may encounter strange behavior. It'll mostly work, but things may be weird at the fringe.
...
And it means that all you folks who are using version 6 of the common controls but haven't converted to Unicode are relying on a compatibility loophole. The ANSI support is there for the old programs that thought they were talking to a version 5 common control; it isn't there for you.
I've never tried doing such a thing so I cannot say for sure, but you may be encountering some of this "strange behavior". If that is the case, then the only officially supported options would be to either convert to Unicode or go back to using version 5 of the controls. Otherwise you would be left trying to find workarounds to any odd behavior you might find, and that doesn't sound like a good situation to be in.