How would I find the height of the task bar? - c++

In my windows application, I am trying to find the height of the task bar. While I can hard program this into my program, I would like to find it programmatically to support past, present (win7) and future windows versions.
So, how would I do this?

You get it from GetMonitorInfo(), MONITORINFOEX.rcWork member.
Get the HMONITOR that you need to call this function from, say, MonitorFromRect(), passing your window rectangle. Or MonitorFromPoint() or EnumDisplayMonitors(), depends where you want to display your window. (0,0) is always the upper left corner of the primary monitor.

Ask Windows about it using the ABM_GETTASKBAR message and specifying the hwnd for the taskbar.

By searching Google for "height of taskbar c++", I got the following result:
Here's how to get the height of the Windows task bar using the windows functions FindWindow and GetWindowRect.
int MyClass::getTaskBarHeight()
{
RECT rect;
HWND taskBar = FindWindow(L"Shell_traywnd", NULL);
if(taskBar && GetWindowRect(taskBar, &rect)) {
return rect.bottom - rect.top;
}
}
Getting the width (should the task bar be on the left or right of the
screen) can be done using:
rect-right - rect.left
You may want to check if the width is greater than the height. If the width is greater, this means the bar is at the top or bottom. Otherwise, it is on the left/right side of the screen.

Probably, you want not only Taksbar, but all other 'bars' on the screen?
All you actually need is SystemParametersInfo(SPI_GETWORKAREA)
SystemParametersInfo, passing SPI_GETWORKAREA as a parameter
Retrieves the size of the work area on the primary display monitor.
The work area is the portion of the screen not obscured by the system
taskbar or by application desktop toolbars. The pvParam parameter must
point to a RECT structure that receives the coordinates of the work
area, expressed in virtual screen coordinates.

There are numerous methods depending on your needs. I used EnumDisplayMonitors() as I needed to test every display to see if it had a taskbar. A method of doing this is:
Use EnumDisplayMonitors() to get a list of all the monitors.
MyInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
Inside the callback will give you a handle to a display.
Warning this function will enumerate virtual displays as well: Using the handle to the display, use GetMonitorInfo() with the handle to the display.
This will return the name of the display along with two RECT structures one of the display position and resolution, the other RECT will be the work-area. You will need to do two checks (One for the X, one for the Y) to see if there is a taskbar on the monitor and the height or width of the taskbar.
For example first we check the Y axis:
if(monitor->rcMonitor.top == monitor->rcWork.top &&
monitor->rcMonitor.bottom == monitor->rcWork.bottom)
{
std::cout << "There is no taskbar on the Y axis" << std::endl;
}
else
{
std::cout << "There is a taskbar on the Y axis" << std::endl;
int height = monitor->rcMonitor.bottom - monitor->rcMonitor.top;
int hieghtOfTaskbar = height - (monitor.rcWork.bottom - monitor.rcWork.top);
std::cout << "The height of the taskbar is: " << heightOfTaskbar << std::endl;
}
Then we check the X axis:
if(monitor->rcMonitor.right == monitor->rcWork.right &&
monitor->rcMonitor.left == monitor->rcWork.left )
{
std::cout << "There is no taskbar on the X axis" << std::endl;
}
else
{
std::cout << "There is a taskbar on the X axis" << std::endl;
int width = monitor->rcMonitor.left - monitor->rcMonitor.right;
int widthOfTaskbar = height - (monitor.rcWork.left - monitor.rcWork.right);
std::cout << "The width of the taskbar is: " << heightOfTaskbar << std::endl;
}
The height or width, depending on position, of the taskbar will usually be the height or the width of the monitor respectively, though this may not always be the case.

Related

Windows: Getting a window title bar's height

I was trying to get the height of the title bar of a specific window on Windows. You can replicate it with Notepad. I'm using C++ and none of the codes I found online yielded the correct result. Using e.g. Screenpresso I measured 31 pixels for my window bar height.
The functions I tried are the following:
TitleBarHeight.h:
#pragma once
#include <windows.h>
inline int get_title_bar_thickness_1(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
return window_rectangle.bottom - window_rectangle.top -
(client_rectangle.bottom - client_rectangle.top);
}
inline int get_title_bar_thickness_2(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
return (window_rectangle.right - window_rectangle.left - client_rectangle.right) / 2;
}
Results:
auto window_handle = FindWindow("Notepad", nullptr);
auto a = get_title_bar_thickness_1(window_handle); // 59
auto b = get_title_bar_thickness_2(window_handle); // 8
auto c = GetSystemMetrics(SM_CXSIZEFRAME); // 4
auto d = GetSystemMetrics(SM_CYCAPTION); // 23
Getting the system metrics with GetSystemMetrics() does not work because windows can have different title bar heights obviously and there is no argument for the window handle.
How can I really get the result of 31?
Assuming that you don't have menu bar, you can map points from client coordinate system to screen one
RECT wrect;
GetWindowRect( hwnd, &wrect );
RECT crect;
GetClientRect( hwnd, &crect );
POINT lefttop = { crect.left, crect.top }; // Practicaly both are 0
ClientToScreen( hwnd, &lefttop );
POINT rightbottom = { crect.right, crect.bottom };
ClientToScreen( hwnd, &rightbottom );
int left_border = lefttop.x - wrect.left; // Windows 10: includes transparent part
int right_border = wrect.right - rightbottom.x; // As above
int bottom_border = wrect.bottom - rightbottom.y; // As above
int top_border_with_title_bar = lefttop.y - wrect.top; // There is no transparent part
Got 8, 8, 8 and 31 pixels (96DPI aka 100% scaling setting)
You should also take into account DPI awareness mode. Especially GetSystemMetrics is tricky because it remembers state for System DPI when your application was launched.
Send a message WM_GETTITLEBARINFOEX to the window, and you will get the bounding rectangle of the title bar.
TITLEBARINFOEX * ptinfo = (TITLEBARINFOEX *)malloc(sizeof(TITLEBARINFOEX));
ptinfo->cbSize = sizeof(TITLEBARINFOEX);
SendMessage(hWnd, WM_GETTITLEBARINFOEX,0, (LPARAM)ptinfo);
int height = ptinfo->rcTitleBar.bottom- ptinfo->rcTitleBar.top;
int width = ptinfo->rcTitleBar.right - ptinfo->rcTitleBar.left;
free(ptinfo);
First, make sure your application is high DPI aware so that the system doesn't lie to you.
Options:
Trust GetSystemMetrics. Nearly any top-level window that actually has a different caption size is doing custom non-client area management which is going to make it (nearly) impossible. The obvious exception is a tool window (WS_EX_TOOLWINDOW) which probably has a SM_CYSMCAPTION height if the WS_CAPTION style is also set.
Get the target window rect and the target window's style. Use AdjustWindowRectEx to determine the size differences with the WS_CAPTION style toggled. I'm not sure if this will work because there may be some interaction between on whether you can have a caption without some kind of border.
Get the target window rect and send WM_HITTEST messages for coordinates that move down the window. Count how many of those get HT_CAPTION in return. Bonus points if you do this with a binary search rather than a linear search. This is probably the hardest and the most reliable way to do it, assuming the window has a rectangular caption area.
If I've understood correctly, it looks like you want to take the border size of the window (which we should be able to gather from the width as there is no title bar) and subtract it from the the verticle size minus the client window...
inline int get_title_bar_thickness(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
int height, width;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
height = (window_rectangle.bottom - window_rectangle.top) -
(client_rectangle.bottom - client_rectangle.top);
width = (window_rectangle.right - window_rectangle.left) -
(client_rectangle.right - client_rectangle.left);
return height - (width/2);
}

SDL2 Toggle fullscreen: Window position gets reset

I'm attempting to toggle fullscreen in SDL2 and so far it works. However when the mode returns to windowed mode, the position gets reset to 0, 0. I tried storing the last position of the window before the window goes fullscreen but after it returns to windowed, the positon gets reset to 0,0 still.
I'm outputting the last position and it seems correct, yet it still gets reset to 0,0 when returning to windowed. Do I need to listen for an event or something?
void ToggleFullscreen(SDL_Window* window) {
Uint32 flag = SDL_WINDOW_FULLSCREEN;
bool isFullscreen = SDL_GetWindowFlags(window) & flag;
if(!isFullscreen){
SDL_GetWindowPosition(window, &lastWindowX, &lastWindowY);
}
SDL_SetWindowFullscreen(window, isFullscreen ? 0 : flag);
if(isFullscreen){
cout << "set window to: " << lastWindowX << " " << lastWindowY << endl;
SDL_SetWindowPosition(window, lastWindowX, lastWindowY);
}
}
Looking at one of my projects that has a function to set either windowed, fullscreen or fullscreen desktop I found these two lines:
// Fixes problem when Game::changeResolution is called in fullscreen or fullscreen desktop and then return to windowed.
SDL_SetWindowSize(m_pWindow, m_width, m_height);
SDL_SetWindowPosition(m_pWindow, SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED);
With the SDL_SetWindowSize done first, everything works fine. Then I commented out the SDL_SetWindowSize line and ran again. When returning from SDL_WINDOW_FULLSCREEN_DESKTOP, it reset it's position to (0,0).
Although when returning to windowed from SDL_WINDOW_FULLSCREEN, it was placed okay. Try adding that line and see if it fixes the problem for you. Also try adding in SDL_Delay(2000); between calls.

Client rectangle coordinates on screen

How can I get coordinates of a window's client area relative to screen?
I thought about using GetClientRect and ClientToScreen. Also, in a browser window what is ClientRect? Only rectangle with HTML document shown in it, or it includes browser bars and pop-up menus, that can possibly shrink dimension for HTML doc?
I've tried this:
HWND hWnd;
RECT rc;
if (GetClientRect(hWnd, &rc)) // get client coords
{
MapWindowPoints(hWnd, NULL, reinterpret_cast<POINT*>(&rc), 2); // converts rect rc points
return rc.top;
}
But the sad thing is that browser's client rectangle includes all those pop-up browser menus and bars, therefore can't be used to detect accurate coordinates of browsers HTML document space. If anyone got suggestions how it can be done, will try it gladly.
Yes, you can do this with the ClientToScreen function:
RECT rc;
GetClientRect(hWnd, &rc); // get client coords
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.left)); // convert top-left
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.right)); // convert bottom-right
What is the "client" rectangle in a browser depends on the browser implementation. You can use Spy++ to discover this for yourself.
To translate a window's client rectangle to screen coordinates, call the MapWindowPoints function. It implements special handling to always return a valid RECT, even when used in scenarios that involve windows with right-to-left layout:
If hWndFrom or hWndTo (or both) are mirrored windows (that is, have WS_EX_LAYOUTRTL extended style) and precisely two points are passed in lpPoints, MapWindowPoints will interpret those two points as a RECT and possibly automatically swap the left and right fields of that rectangle to ensure that left is not greater than right.
Calling ClientToScreen on both points in contrast fails to account for RTL layouts, and can produce an invalid RECT. It fails to adhere to one of the rectangle coordinate invariants:
The coordinate value of a rectangle's right side must be greater than that of its left side. Likewise, the coordinate value of the bottom must be greater than that of the top.
A reliable function to return a window's client rectangle in screen coordinates would look like this:
RECT client_rect_in_screen_space(HWND const hWnd) {
RECT rc{ 0 };
if (!::GetClientRect(hWnd, &rc)) {
auto const err_val{ ::GetLastError() };
throw std::system_error(err_val, std::system_category());
}
::SetLastError(ERROR_SUCCESS);
if(::MapWindowPoints(hWnd, nullptr, reinterpret_cast<POINT*>(&rc), 2) == 0) {
auto const err_val{ ::GetLastError() };
if (err_val != ERROR_SUCCESS) {
throw std::system_error(err_val, std::system_category());
}
}
return rc;
}
The question update asks for a different, unrelated issue. There is no API built into the system, that allows you to query a web browser's display area for its HTML content. The most promising solution would be to employ UI Automation. The question, however, is too broad to provide a more detailed answer here.
As commented by Raymond Chen, the preferred way of doing this should be something like the following:
inline POINT get_client_window_position(const HWND window_handle)
{
RECT rectangle;
GetClientRect(window_handle, static_cast<LPRECT>(&rectangle));
MapWindowPoints(window_handle, nullptr, reinterpret_cast<LPPOINT>(& rectangle), 2);
const POINT coordinates = {rectangle.left, rectangle.top};
return coordinates;
}
POINT origin;
origin.x = 0;
origin.y = 0;
ClientToScreen(hWnd, &origin);
Now origin is, in screen coords, the top left corner of the client area.
To convert (x,y) from client-area coords to screen coords, add origin.
To do the reverse, subtract.

C++ MFC button disappears at window resize

I have a Dialog in MFC C++ that has a CButton attached.
I want to modify OnSize() so that the button will anchor to bottom-left.
if (btn.m_hWnd) {
CRect winRect;
GetWindowRect(&winRect);
int width = winRect.right - winRect.left;
int height = winRect.bottom - winRect.top;
int x = width - wndWidth;
int y = height - wndHeight;
CRect rect;
btn.GetWindowRect(&rect);
rect.left += x;
rect.top += y;
btn.MoveWindow(&rect);
ScreenToClient(&rect);
btn.ShowWindow(SW_SHOW);
}
x and y are the difference of how much the window has changed and will be added to the button's start coordinates.
I am not sure about the last 2 commands (I might as well delete them) but then I run the program the button disappears.
I need to know a way to move the button by x and y.
The original code was using the wrong coordinate system for both the parent dialog, and the button.
A correct way to dock to the bottom left would be like this:
if (btn.m_hWnd) {
CRect winRect;
GetClientRect(&winRect);
CRect rect;
btn.GetWindowRect(&rect);
ScreenToClient(&rect);
int btnWidth = rect.Width();
int btnHeight = rect.Width();
rect.left = winRect.right-btnWidth;
rect.top = winRect.bottom-btnHeight;
rect.right = winRect.right;
rect.bottom = winRect.bottom;
btn.MoveWindow(&rect);
}
OR
if (btn.m_hWnd) {
CRect winRect;
GetClientRect(&winRect);
CRect rect;
btn.GetWindowRect(&rect);
ScreenToClient(&rect);
int btnWidth = rect.Width();
int btnHeight = rect.Width();
btn.SetWindowPos(NULL,winRect.right-btnWidth,winRect.bottom-btnHeight,0,0,SWP_NOSIZE|SWP_NOZORDER);
}
Basically, the answer should be to do ScreenToClient before MoveWindow!
Some more detail: You need to familiarize yourself with what function returns or uses client coordinates (and relative to what these client coordinates are) and which screen coordinates; this is one of the parts of MFC which can be really confusing. As to your question:
CWnd::GetWindowRect returns screen coordinates; CWnd::MoveWindow expects coordinates relative to the parent CWnd (or to the screen if it's a top level window). So before calling MoveWindow, you have to convert the rect returned by GetWindowRect to client coordinates of your parent window; suppose pParent is the CWnd * to the parent window of btn, then your moving code should look like this:
CRect rect;
btn.GetWindowRect(&rect);
pParent->ScreenToClient(&rect); // this line and it's position is important
rect.left += x;
rect.top += y;
btn.MoveWindow(&rect);
If you're in a method of the parent window (as I think you are, since you mention OnSize of the dialog), then just leave out the pParent->. The way you do ScreenToClient at the moment, it has no effect on MoveWindow, since it's executed after it!

How to remove scrollbars in console windows C++

I have been checking out some Rogue like games (Larn, Rogue, etc) that are written in C and C++, and I have noticed that they do not have the scrollbars to the right of the console window.
How can I accomplish this same feature?
To remove the scrollbar, simply set the screen buffer height to be the same size as the height of the window:
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
// get handle to the console window
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
// retrieve screen buffer info
CONSOLE_SCREEN_BUFFER_INFO scrBufferInfo;
GetConsoleScreenBufferInfo(hOut, &scrBufferInfo);
// current window size
short winWidth = scrBufferInfo.srWindow.Right - scrBufferInfo.srWindow.Left + 1;
short winHeight = scrBufferInfo.srWindow.Bottom - scrBufferInfo.srWindow.Top + 1;
// current screen buffer size
short scrBufferWidth = scrBufferInfo.dwSize.X;
short scrBufferHeight = scrBufferInfo.dwSize.Y;
// to remove the scrollbar, make sure the window height matches the screen buffer height
COORD newSize;
newSize.X = scrBufferWidth;
newSize.Y = winHeight;
// set the new screen buffer dimensions
int Status = SetConsoleScreenBufferSize(hOut, newSize);
if (Status == 0)
{
cout << "SetConsoleScreenBufferSize() failed! Reason : " << GetLastError() << endl;
exit(Status);
}
// print the current screen buffer dimensions
GetConsoleScreenBufferInfo(hOut, &scrBufferInfo);
cout << "Screen Buffer Size : " << scrBufferInfo.dwSize.X << " x " << scrBufferInfo.dwSize.Y << endl;
return 0;
}
You need to make the console screen buffer the same size as the console window. Get the window size with GetConsoleScreenBufferInfo, srWindow member. Set the buffer size with SetConsoleScreenBufferSize().
Using #include <winuser.h>, you can simply do
ShowScrollBar(GetConsoleWindow(), SB_VERT, 0);
You can specify which scroll bar to hide using different parameters.
To remove scrollbars from the console, we can make the console screen buffer the same size as the console window. This can be done as follows:
#include <Windows.h>
#include <iostream>
int main() {
CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
// Get console handle and get screen buffer information from that handle.
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole, &screenBufferInfo);
// Get rid of the scrollbar by setting the screen buffer size the same as
// the console window size.
COORD new_screen_buffer_size;
// screenBufferInfo.srWindow allows us to obtain the width and height info
// of the visible console in character cells.
// That visible portion is what we want to set the screen buffer to, so that
// no scroll bars are needed to view the entire buffer.
new_screen_buffer_size.X = screenBufferInfo.srWindow.Right -
screenBufferInfo.srWindow.Left + 1; // Columns
new_screen_buffer_size.Y = screenBufferInfo.srWindow.Bottom -
screenBufferInfo.srWindow.Top + 1; // Rows
// Set new buffer size
SetConsoleScreenBufferSize(hConsole, new_screen_buffer_size);
std::cout << "There are no scrollbars in this console!" << std::endl;
return 0;
}