setwindowplacement doesn't work for maximized window - c++

I have a multi monitor setup. When the window is maximized in secondary monitor, I maximize the window to half of the monitor size in OnSysCommand()
by doing the following:
MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
GetMonitorInfo(hMonitor, &monitorInfo);
CRect rc = monitorInfo.rcMonitor;
rc.left = rc.left / 2;
SetWindowPos(hWnd, rc.left, rc.right, rc.Width(), rc.Height(),0);
This works fine.
But,when the process is stopped and when the window is opened after process startup, the window is maximized to full monitor size, though the window placement is saved on process exit.(flags of WindowPlacement is WPF_RESTORETOMAXIMIZED , showCmd is SW_MAXIMIZE)
In OnShowWindow(), SetWindowPlacement() is used.

Maximized always ignore the size inside the windows placement structure.
This is completely by design.
The windows placement structure holds only the size of the none maximized / normal window. Only the top left corner of the maximized window is saved. And this cords are in screen coordinates to support multiple terminals.
So you get what you want, if you tell the system to restore the window maximized.
If you want to limit the maximization of the window you have to use a different approach. May be WM_GETMINMAXINFO will do it (I am not sure if it is also consulted, when the window is maximized).

Related

Is focus rect drawn automatically for listbox (WC_LISTVIEW)?

I have created a listbox similar to the code provided here. In my UI, will the tab focus rect be automatically drawn by DefWindowProc() or do I need to take care of that ? I don't see the focus rect being drawn on tab focus.
Thanks.
HWND CreateListView (HWND hwndParent)
{
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
RECT rcClient; // The parent window's client area.
GetClientRect (hwndParent, &rcClient);
// Create the list-view window in report view with label editing enabled.
HWND hWndListView = CreateWindow(WC_LISTVIEW,
L"",
WS_CHILD | WS_VISIBLE | LVS_LIST,
0, 0,
rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top,
hwndParent,
(HMENU)IDM_CODE_SAMPLES,
g_hInst,
NULL);
return (hWndListView);
}
Normally,the default window procedure draws a focus rectangle for the list box item drawn by the owner in response to the WM_DRAWITEM message.
In MSDN
For an empty list box or combo box, itemID can be -1. This allows
the application to draw only the focus rectangle at the coordinates
specified by the rcItem member even though there are no items in the
control. This indicates to the user whether the list box or combo box
has the focus. How the bits are set in the itemAction member
determines whether the rectangle is to be drawn as though the list box
or combo box has the focus.
If you are not using owner/custom draw then all Windows common controls will draw the focus rectangle for you automatically.
Windows 2000 (and later) hide keyboard accelerators and focus rectangles by default unless you are interacting with the window by using your keyboard.
Windows enables applications to hide or show various features in its UI. These settings are known as the UI state. The UI state includes the following settings:
focus indicators (such as focus rectangles on buttons)
keyboard accelerators (indicated by underlines in control labels)

Win32/Gdigrab - How to set another process window as borderless?

I am currently using GDIGRAB to capture a window. The problem is, because of the border, the mouse cursor has an offset on its position.
The idea is to put a window as borderless so the offset won't appear anymore. Given the handle of the aimed process, how can I change a window from windowed to borderless ?
Don't tinker with another process' windows. Instead, get the border offset.
HWND window = ...;
RECT wndRect, clientRect;
GetWindowRect(window,&wndRect);
GetClientRect(window,&clientRect);
POINT borderOffset={clientRect.left,clientRect.top};
ClientToScreen(window,&borderOffset);
borderOffset.x-=wndRect.left;
borderOffset.y-=wndRect.top;
// borderOffset now contains the x and y offsets for the window

WM_DPICHANGED event suggesting bad new position for window

I have two monitors connected to my desktop. A 3840x2160 main monitor on the left set to 150% scaling (144 DPI) and a 1920x1080 monitor on the right set to 100% scaling (96 DPI). The are aligned on the bottom edge. This is on Windows 8.1, but the same issue occurs on Windows 10.
My application is C++ using native Win32 windows. It is set at per-monitor DPI aware.
I have a dialog window that is a borderless (not title bar either) window with a custom title bar inside the client area. The user can drag this custom title bar to move the window, and internally it gets moved using SetWindowPos().
When this window is dragged from the High-DPI left monitor over to the regular monitor on the right, I get a WM_DPICHANGED message. The current RECT for the window is:
curRect = {LeftTop(3527, 1099) RightBottom(4157, 2098) WidthHeight[630 x 999]}
The new suggested RECT that the WM_DPICHANGED message gives me is:
newRect = {LeftTop(3527, 1099) RightBottom(3947, 1765) WidthHeight[420 x 666]}
If I pass the new RECT to SetWindowPos as the documentation for WM_DPICHANGED suggests, then the window is now considered back on my high-DPI monitor, and in the SetWindowPos() I get another WM_DPICHANGED message telling me to change the window pos/size again. This occurs before my original WM_DPICHANGED event has returned.
This makes sense based on the new suggested RECT since the left edge doesn't get moved, but the width is getting reduced.
The WM_DPICHANGED message for the same window doesn't have this issue if I'm using an actual non-client titlebar. The left edge is moved in the new suggested RECT.
Any suggestions on how to handle this? Any way to minimally change the new suggest RECT such that it ensures the window w/h is as suggested, but it's positioned so it doesn't fire another DPICHANGED event (stays on the new monitor).
Thanks!

restrict window maximum size in secondary monitor

I have a multi monitor setup. When a window is maximized on secondary monitor, I need to restrict the maximum size and position.
In MSDN, the documentation for MINMAXINFO mentions the following:
For systems with multiple monitors, the ptMaxSize and ptMaxPosition members describe the maximized size and position of the window on the primary monitor, even if the window ultimately maximizes onto a secondary monitor. In that case, the window manager adjusts these values to compensate for differences between the primary monitor and the monitor that displays the window. Thus, if the user leaves ptMaxSize untouched, a window on a monitor larger than the primary monitor maximizes to the size of the larger monitor.
So, I tried restriction by doing SetWindowPos in OnSysCommand if nId is SC_MAXIMIZE . It works, when the user clicks on maximize button/double click the title bar.
But, when the user uses Win+Up Arrow key or move the window to top of monitor to maximize, I am not able to handle the maximize restriction.
So, is there any common place to handle my all scenarios?
Is there any way to do trick on receiving WM_GETMINMAXINFO message.
I know this post is old, but I wish to share my code for those who still need a solution.
void CMyDialog::OnWindowPosChanging(WINDOWPOS * pos)
{
//let us do the default processing first
CDialogEx::OnWindowPosChanging(pos);
//We are only interested in setting the window size when our window is in maximized state.
//When maximized, the window will have a WS_MAIMIZE window style set
LONG_PTR lWndStyle = GetWindowLongPtr(this->m_hWnd, GWL_STYLE);
if ((lWndStyle & WS_MAXIMIZE) != WS_MAXIMIZE)
return;
//Use the proposed window from OS to identify the monitor.
//I found that, the MonitorFromWindow() API returns primary monitor info when I restore a minimized window from taskbar.
RECT rectWnd = {pos->x, pos->y, pos->x + pos->cx, pos->y + pos->cy};
HMONITOR hMon = MonitorFromRect(&rectWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO info;
info.cbSize = sizeof(info);
GetMonitorInfo(hMon, &info);
LONG nMaxWndWidth = (info.rcWork.right - info.rcWork.left);
LONG nMaxWndHeight = (info.rcWork.bottom - info.rcWork.top);
//The window and workspace height can be > or <
if (pos->cy != nMaxWndHeight)
{
pos->cy = nMaxWndHeight;
}
//The window and workspace width can be > or <
if (pos->cx != nMaxWndWidth)
{
pos->cx = nMaxWndWidth;
}
}

Troubles with ::MoveWindow - leaving blank space

I am quite desperate to resolve this very annoying issue :(
I am trying to display a child window on parent window. Some time the window need to be resized. But for some reason, when I using MoveWindow function it leaves blank space on the top of the parent window. I would like to present a picture here but I can not post a picture.
Here is the code example:
HWND hwnd // Comes from external function. Was defined as WS_CHILD previously
HWND hwndParent = ::GetParent(hwnd);
RECT parentRect = {0,0,0,0};
RECT childRect = {0,0,0,0};
::GetClientRect(hwndParent, &parentRect); // Suppose it returns {0,0,600,300}
BOOL ok = ::MoveWindow(hwnd, 0, 0, 600, 300, true);
::GetClientRect(hwnd, &childRect); // Will return {0,0,584,297}
WHY ?????
What am I doing wrong? Did I forgot some flags with window initialization?!
Rather than use GetClientRect, use GetWindowRect and MapWindowPoints(NULL,hwndParent,&parentRect,2) to adjust it to the parent window coordinates. GetWindowRect will include the non-client area that MoveWindow requires.
Edit: If you want a window that doesn't have a non-client area so the window rect and the client rect are the same size, you need to trim the window styles that you apply to the window. Avoid the WS_BORDER, WS_CAPTION, WS_DLGFRAME, WS_OVERLAPPED, WS_SIZEBOX, and WS_THICKFRAME styles.
MoveWindow updates window position, while GetClientRect gets a client-area part of the window, which does not have to be the same. If your window has non-client area, then everything is fine and works as expected.
If you are still under impression that child window does not fully cover parent's client area, then the spacing belongs to the child control/window, and you need to look for ways to remove it there (control flags, parameters etc).
MoveWindow operates on window coordinates -- including non-client area (borders, title bar, etc).
GetClientRect gets the area of the client portion of the window, ignoring borders, title bar, etc.
This is where the mismatch is. If you want to MoveWindow to a desired client size, you need to just AdjustWindowRect to try and predict what to pass into MoveWindow. Note that it's not always possible, and not always accurate. For example minimum / maximum sizes of windows, menus (which can wrap to multiple lines), etc.
The problem was WS_POPUP flag to the parent window.
Very strange. As far as I know it was not suppose to have such an effect.
Thanks for everyone!