Moving fullscreen window from primary to secondary monitor causes visual artifact on primary monitor - c++

I am trying to move a fullscreen window from the primary monitor to the secondary monitor. However, while the window appears as it should on the secondary monitor, it also still appears on the primary monitor. This is just a visual artifact as clicking the 'window' on the primary monitor causes the program to minimize just like clicking outside of a program normally would.
After maximizing the program the function works as intended and is able to move the program between the two monitors problem free.
What is causing this visual artifact and more importantly, how can it be fixed?
This is the code I am using, mostly found through trial and error by looking at what decreases the visual artifacts and what doesn't.
void MoveFullscreenWindowToMonitor(HWND hwnd, HMONITOR fromMonitor, HMONITOR hMonitor) {
MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
if (GetMonitorInfo(hMonitor, &monitorInfo)) {
RECT monitorRect = monitorInfo.rcMonitor;
int width = monitorRect.right - monitorRect.left;
int height = monitorRect.bottom - monitorRect.top;
// Get the current window style
LONG style = GetWindowLong(hwnd, GWL_STYLE);
// Temporarily remove the WS_POPUP style to exit fullscreen mode
SetWindowLong(hwnd, GWL_STYLE, style & ~WS_POPUP);
// Move the window off the screen before moving it to the new monitor
SetWindowPos(hwnd, NULL, -width, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
// Move the window to the new monitor and resize it to fit the monitor
SetWindowPos(hwnd, NULL, monitorRect.left, monitorRect.top, width, height, SWP_FRAMECHANGED);
// Add the WS_POPUP style back to enter fullscreen mode
SetWindowLong(hwnd, GWL_STYLE, style);
// Move the window to the new monitor to fix the visual artifact
SetWindowPos(hwnd, NULL, monitorRect.left, monitorRect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
// Create a window that spans the entire work area of the original monitor
//This part fixes another weird visual artifact on the target monitor
MONITORINFOEX mi;
mi.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(fromMonitor, &mi);
RECT rect = mi.rcWork;
HWND extrahwnd = CreateWindowEx(0, L"STATIC", NULL, WS_VISIBLE | WS_POPUP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
// Force a screen refresh on the original monitor
UpdateWindow(extrahwnd);
// Destroy the window
DestroyWindow(extrahwnd);
// Restore the window and move it to the new monitor to fix the visual artifact
ShowWindow(hwnd, SW_RESTORE);
SetWindowPos(hwnd, NULL, monitorRect.left, monitorRect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
// Give the window focus
SetForegroundWindow(hwnd);
// Invalidate the window to force a redraw on the original monitor
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
}
}
EDIT: Everything works perfectly fine if I minimize and then maximize the application before running the code.

Related

CreateWindowEx creates old (Windows 7) style border on Windows 10

Whenever I create a window with CreateWindowEx(...) (exact parameters can be found in the code below), it shows up like an old style window:
Only when I start it on a remote desktop, close the connection and reconnect, it changes to the desired Windows 10 style:
Does it have something to do with the several WM_SETTINGCHANGE messages the application receives when doing this?
Obviously, I want the window to have a modern style upon creation, and not after handling some message.
I've tried different combinations of WS_... style arguments. Oddly enough, the application only reliably shows up with WS_OVERLAPPEDWINDOW | WS_VISIBLE.
I've tried ShowWindow (with various arguments) and UpdateWindow in both orders.
I've also tried messing with the target platform and toolset, but to no avail (using VS2015, v140).
Code snippet:
WNDCLASSEX wc = {sizeof(WNDCLASSEX), NULL, WindowController::globalEventProcessor,
0L, 0L, GetModuleHandle(NULL), NULL,
LoadCursor(NULL, IDC_ARROW), NULL, NULL,
_T("Window"), NULL};
RegisterClassEx(&wc);
HWND handle = CreateWindowEx(
NULL,
wc.lpszClassName,
_T("Test"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
parentWindow ? parentWindow->getHandle() : NULL,
NULL,
wc.hInstance,
reinterpret_cast<LPVOID>(this)
);
if (handle != NULL)
{
... // resizing the window's contents
UpdateWindow(handle);
}
Strangely enough, the solution seems to be to remove WS_VISIBLE from the style flags, and show the window manually:
if (handle != NULL)
{
... // resizing the window's contents
ShowWindow(handle, 1); /* Add this */
UpdateWindow(handle);
}
Which I'm 100% sure I've tried already, but suddenly works. Whatever...

How to make a Win32 control created without WS_VISIBLE visible?

Suppose hCtl is a handle to a control created without the WS_VISIBLE flag such as:
HWND hCtl = CreateWindowEx(0, WC_STATIC, L"some text",
WS_CHILD | SS_NOTIFY, // no WS_VISIBLE flag
0, 0, 0, 0, hWndParent, (HMENU)IDC_STATIC1, g_hInst, 0);
Is there a more straightforward way to make it visible than the following?
void make_visible(HWND hCtl, HWND hWndParent) {
SetWindowLongPtr(hCtl, GWL_STYLE,
GetWindowLongPtr(hCtl, GWL_STYLE) | WS_VISIBLE);
RECT rc{};
GetClientRect(hCtl, &rc);
MapWindowRect(hCtl, hWndParent, &rc);
InvalidateRect(hWndParent, &rc, TRUE);
UpdateWindow(hWndParent);
//ShowWindow(hCtl, SW_SHOW); // no use: does not update window
//SetWindowPos(hCtl, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // no use: does not update window
}
To make a child control visible, call SetWindowPos like this:
SetWindowPos(hCtl, 0, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
Your code to call MapWindowRect, InvalidateRect, UpdateRect etc. should be removed.
Perhaps the real problem you have is that you have created the static control with zero width and height.
The normal way to make a window visible is only the function ShowWindow. There is no need dealing with flags and so on. Usually you use SW_SHOW as a parameter for a child window. Check the other values and use what you think is appropriate.
If the window has a visible rectangle and isn't covered by another window it will show up. Even UpdateWindow calls are not needed. The window will show up in the next paint cycle. If your control has a size of 0,0,0,0 (as it was created) it will never show up.
There is also a ShowWindowAsync function for the use if the window is on a different thread to avoid blocking.
BTW: I don't understand what you try with invalidating the parent window area. If there is a child window clipping (WS_CLIPCHILDREN) it has no effect.
I believe your problem is that you're explicitly setting the WS_VISIBLE style yourself and then calling ShowWindow, which confuses Windows into believing that the window is already visible and doesn't need to be repainted.
Just call ShowWindow. There should be no need to explicitly set WS_VISIBLE yourself because ShowWindow already does it. You should not need to forcibly repaint your control.
Additionally, if you find some need to explicitly invalidate your control, it should be sufficient to just do InvalidateRect(hCtl, NULL) and not bother with GetClientRect and MapWindowRect.

Child window disappears on scrolling

HWND hwndDlg=GetDesktopWindow();
HWND hImage=CreateWindow(_T("STATIC"), _T(""), SS_CENTERIMAGE | SS_REALSIZEIMAGE | SS_BITMAP | WS_CHILD | WS_VISIBLE,
550, 480, 10, 10, hwndDlg, NULL,
(HINSTANCE)GetWindowLong(hwndDlg, GWLP_HINSTANCE),
NULL);
LPWSTR imgPath = getImagePath();
HBITMAP bitmap = (HBITMAP)LoadImageW(NULL,imgPath, IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
SendMessage(hImage, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmap);
With this piece of code i'm able to create a child window to the current window and make a picture appear on that window. It works as expected. But my problem is when i scroll the child window and the picture disappear. What am I doing wrong? I'm totally new with windows programming. Please help me out.
http://i.stack.imgur.com/VO0uD.png
You may see the screenschot in the above link

Up-Down control doesn't show its position in its buddy window

I created an up-down control by the following code.
HWND hEdit, hUpDown;
hEdit = CreateWindowExW(WS_EX_CLIENTEDGE,
L"EDIT",
Content.c_str(),
ES_LEFT | WS_VISIBLE | WS_CHILD,
600,
260,
100,
25,
hWndParent,
NULL,
hInstance,
NULL);
INITCOMMONCONTROLSEX iccx;
iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccx.dwICC = ICC_UPDOWN_CLASS;
InitCommonControlsEx(&iccx);
hUpDown = CreateWindowExW( 0,
UPDOWN_CLASSW,
L"",
UDS_ARROWKEYS | UDS_ALIGNRIGHT | WS_VISIBLE | WS_CHILD,
0,
0,
0,
0,
hWndParent,
NULL,
hInstance,
NULL);
SendMessageW(hUpDown, UDM_SETBUDDY, (WPARAM) hEdit, (LPARAM) NULL);
SendMessageW(hUpDown, UDM_SETRANGE32, (WPARAM) 0, (LPARAM) 100);
Sleep(5000);
SendMessageW(hUpDown, UDM_SETPOS32, (WPARAM) NULL, (LPARAM) 20);
Sleep(5000);
SendMessageW(hUpDown, UDM_SETPOS32, (WPARAM) NULL, (LPARAM) 60);
I checked the return values of the SendMessageW() functions. They terminate successfully by returning the previous position value as documented.
The created up-down control looks normal:
The problem is, sending the UDM_SETPOS32 message, clicking the up and down arrows and pressing the up and down keys on the keyboard have no effect. I can't change the contents of the edit control (the buddy window of the up-down control) without directly typing something into it. It just stays empty.
I am able to type anything in it manually by using keyboard:
How do I change the position/value of this up-down control by pressing keyboard arrow keys, by clicking the arrows in the GUI and by sending UDM_SETPOS32 in the code? What am I missing in my code?
Use the style UDS_SETBUDDYINT to the up-down control while creating it.
From MSDN documentation:
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.
Change the creation code of the up-down control like this by adding the UDS_SETBUDDYINT style:
hUpDown = CreateWindowExW( 0,
UPDOWN_CLASSW,
L"",
UDS_SETBUDDYINT | UDS_ARROWKEYS | UDS_ALIGNRIGHT | WS_VISIBLE | WS_CHILD,
0,
0,
0,
0,
hWndParent,
NULL,
hInstance,
NULL);

Win32: How to create a bordless popup window

Win32 API provides many styles for window creating and I'm looking for a style that can remove a one-pixel border from the window that I created with this code:
DWORD dwExtStyle = 0;
DWORD dwStyle = WS_POPUPWINDOW;
m_hWnd = CreateWindowEx(
dwExtStyle,
className,
windowName,
dwStyle,
300,
300,
100,
100,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(m_hWnd, SW_SHOW);
and I got the result:
What combination of flags can remove the black border from the window.
Just use WS_POPUP instead of WS_POPUPWINDOW.
The macro WS_POPUPWINDOW is actually a set of flags:
#define WS_POPUPWINDOW (WS_BORDER | WS_POPUP | WS_SYSMENU)
The WS_BORDER flag is the one responsible of your black square.