Scrollbar Appearance Control in Windows 7 - c++

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?

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)

WinAPI check if a window has a regular title bar

I want my program to reliably determine if a window (given its handle) has a regular windows style title bar (like windows explorer, control panel and most of the desktop apps) or a custom one (google chrome, visual studio, spotify, store apps).
Is there a specific flag in GWL_STYLE or GWL_EXSTYLE, or is there an other way to check the title bar style?
You will have to define what you consider "regular" and, therefore, what is "custom".
For instance, typical applications will have WS_CAPTION and WS_BORDER set, if I recall correctly. If you consider that "normal", then it is easy to consider everything else custom and you are done.
To decide on your criteria, I suggest you inspect the applications you mention and others, and finally decide what is the set of conditions you need.
Further information:
Window Styles
Extended Window Styles
Window Types

How can I create a Spin Button Control dynamically in MFC using CSpinButtonCtrl class?

I realize that this is a trivial problem and I even looked at an MFC book(Programming Windows with MFC by Prosise). However, I couldn't really find a solution.
I am trying to create a Spin Button Control dynamically and here is a simplified code:
CEdit* m_editControl = new CEdit();
m_EditControl->Create(WS_VISIBLE | WS_CHILD , rectEdit, this, EditID);
CSpinButtonCtrl* m_spinControlCtrl = new CSpinButtonCtrl;
m_spinControlCtrl->Create(WS_VISIBLE | WS_CHILD, rectSpinButton, this, SpinID);
m_spinControlCtrl->SetBase(10);
m_spinControlCtrl->SetBuddy(m_editControl );
m_spinControlCtrl->SetRange(-55, 55);
My problem is that the spin button does not change the value of the CEdit. Am I missing something? How can I create a Spin Button Control dynamically?
Your spin control is missing the style UDS_SETBUDDYINT:
UDS_SETBUDDYINT Causes the up-down control to set the text of the
buddy window (using the WM_SETTEXT message) when the position changes.
The text consists of the position formatted as a decimal or
hexadecimal string.
I also suggest setting UDS_ARROWKEYS so the arrow keys can be used to increment or decrement the value when the focus is on the edit control.
For the edit control I would add WS_TABSTOP so the user can navigate using the TAB key and WS_EX_CLIENTEDGE so the edit control shows the regular themed border.
I also noticed that you use dynamic memory allocation for the controls, which is not necessary. Just create non-pointer member variables like CEdit m_EditControl; so you don't have to worry about deallocation.
Fixed code:
m_EditControl.CreateEx(WS_EX_CLIENTEDGE, L"Edit", L"0", WS_VISIBLE|WS_CHILD|WS_TABSTOP,
rectEdit, this, EditID);
m_spinControlCtrl.Create(WS_VISIBLE|WS_CHILD|UDS_SETBUDDYINT|UDS_ARROWKEYS,
rectSpinButton, this, SpinID);
m_spinControlCtrl.SetBase(10);
m_spinControlCtrl.SetBuddy(&m_EditControl);
m_spinControlCtrl.SetRange(-55, 55);
I also strongly suggest learning to use Spy++. This is how I actually arrived at this answer. Using the resource editor I just dropped an edit control and an up-down control onto a dialog and used Spy++ to observe the default window styles.

Tooltip is never shown again after I click on the button

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.

How do I get the window handle of the desktop?

The Windows API provides an API GetDesktopWindow( ) which returns the window handle
But I tested with Spy++ and I find that the window handle of the desktop and the window handle of the "Windows Desktop" is not the same.
As the "Windows Desktop" is a list view, do I need to do the following
1) HANDLE hWnd = GetDesktopWindow() ;
2) FindWindow(hWnd, ..... ) with the SyslistView32 as the Window class.
Once I get the Window handle, I want to use SendMessage() for operations like getting selected file name, the number of files selected , etc.
Please give your opinions. I am doing this using the Windows SDk
In light of a recent discussion on Meta complaining that questions like this one have "not been properly answered", I'm going to try and give answering this one a whirl. Not to imply that I think meklarian's answer is bad—in fact, far from it. But it's clearly been deemed unsatisfactory, so perhaps I can fill in some of the additional details.
Your problem results from a fairly widespread confusion over what the desktop window actually is. The GetDesktopWindow function does precisely what it's documented to do: it returns a handle to the desktop window. This, however, is not the same window that contains the desktop icons. That's a completely different window that appeared for the first time in Windows 95. It's actually a ListView control set to the "Large Icons" view, with the actual desktop window as its parent.
Raymond Chen, a developer on the Windows Shell team provides some additional detail in the following Windows Confidential article: Leftovers from Windows 3.0
[ . . . ] While in Windows 3.0, icons on the desktop represented minimized windows, in Windows 95, the desktop acted as an icon container.
The Windows 95 desktop was actually a window created by Explorer that covered your screen (but sat beneath all the other windows on your desktop). That was the window that displayed your icons. There was still a window manager desktop window beneath that (the window you get if you call Get­Desktop­Window), but you never saw it because it was covered by the Windows 95 desktop—the same way that the wood paneling in the basement of my colleague’s house covered the original wall and the time capsule behind the wall.
[ . . . ]
This desktop design has remained largely unchanged since its introduction in Windows 95. On a typical machine, the original desktop is still there, but it’s completely covered by the Explorer desktop.
In summary, then, the window returned by the GetDesktopWindow function is the actual desktop window, the only one we had way back in Windows 3.0. The Explorer desktop (the one that contains all your icons) is merely another window sitting on top of the desktop window (although one that completely covers the original) that wasn't added until Windows 95.
If you want to get a handle to the Explorer desktop window, you need to do some additional work beyond simply calling the GetDesktopWindow function. In particular, you need to traverse the child windows of the actual desktop window to find the one that Explorer uses to display icons. Do this by calling the FindWindowEx function to get each window in the hierarchy until you get to the one that you want. It has a class name of SysListView32. You'll also probably want to use the GetShellWindow function, which returns a handle to the Shell's desktop window, to help get you started.
The code might look like this (warning: this code is untested, and I don't recommend using it anyway!):
HWND hShellWnd = GetShellWindow();
HWND hDefView = FindWindowEx(hShellWnd, NULL, _T("SHELLDLL_DefView"), NULL);
HWND folderView = FindWindowEx(hDefView, NULL, _T("SysListView32"), NULL);
return folderView;
I noted there that I don't actually recommend using that code. Why not? Because in almost every case that you want to get a handle to the desktop window (either the actual desktop window, or the Explorer desktop), you're doing something wrong.
This isn't how you're supposed to interact with the desktop window. In fact, you're not really supposed to interact with it at all! Remember how you learned when you were a child that you're not supposed to play with things that belong to other people without their permission? Well, the desktop belongs to Windows (more specifically, to the Shell), and it hasn't given you permission to play with its toys! And like any good child, the Shell is subject to throwing a fit when you try to play with its toys without asking.
The same Raymond Chen has published another article on his blog that details a very specific case, entitled What's so special about the desktop window?
Beyond the example he gives, this is fundamentally not the way to do UI automation. It's simply too fragile, too problematic, and too subject to breaking on future versions of Windows. Instead, define what it is that you're actually trying to accomplish, and then search for the function that enables you to do that.
If such a function does not exist, the lesson to be learned is not that Microsoft simply wants to make life harder for developers. But rather that you aren't supposed to be doing that in the first place.
If you want the Desktop window as defined in GetDesktopWindow(), use that window handle. This is the window handle you should use to look for top-level windows and other related activities.
What you're seeing in Spy++ is just the content drawn as the desktop in your session. If you use the auto-locate in Spy++, you'll see that the SysListView32-declared window is a child window of your explorer shell. It is quite infrequent for someone to need access to this window. Also, the existence of this window may be subject to changes between versions of windows.
Edit (additional info)
If you are looking to interact or place things on the actual shell desktop, you may be better served by other APIs. Here are two such APIs that can accomplish this, depending on the target version of windows.
Windows Sidebar # MSDN
This is available on Vista and Windows 7
Using the Active Desktop # MSDN
This is available on Windows 2000 and XP, although frequently disabled by users and sysadmins.