Win32 C++ Resizing Window Leaves Artifacts in RDP - c++

I have a simple Win32 program that does the following
1) Creates a Window
HWND hWnd = CreateWindowEx(
WS_EX_LEFT |
WS_EX_LTRREADING |
WS_EX_RIGHTSCROLLBAR |
WS_EX_WINDOWEDGE |
WS_EX_APPWINDOW,
wc.lpszClassName,
L"App Name",
WS_CAPTION |
WS_VISIBLE |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN |
WS_SYSMENU |
WS_OVERLAPPED |
WS_MINIMIZEBOX, 0, 0, 540, 180, 0, 0, hInstance, NULL);
Then
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
// code here (not shown) calculates pixel size of text with GetTextExtentPoint32
// resizes window to fit text with MoveWindow
MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, height + borderSize, false);
// writes text to window with DrawText
EndPaint(hWnd, &ps);
}
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
This works fine on desktop without an issue, Window looks fine and displays as expected.
However on RDP the following artifacts are present:
The pre-resized versions of Window remains i.e. you can see both the old border and the new border
An image from the background of where Window was created is blended into the Window
Moving the Window around the screen does not remove the artifacts
Minimizing the Window and opening it again does remove the artifacts
If I minimize the Remote Desktop client, and switch back to it, the Window is displayed as expected.
Other programs don't show this behavior during the RDP session.
RDP client is on Win10 x64, target machines are Server 2008 R2 or Windows 7 SP1 x64.
Tried with repaint set to TRUE in MoveWindow but this had no affect.

Fixed this by removing WS_VISIBLE from my CreateWindowEx command, resized the Window first, then after resizing Window called
ShowWindow(hWnd,SW_SHOW);
I also removed the window resize from WM_PAINT, however this did not fix the issue.

Related

Drawing a picture using GDI+ in WinAPI [duplicate]

I need a window featuring no title bar, none of the control boxes, no system menu, and no frames (all that functionality is provided with separate controls).
I suspect that this should be possible to do with CreateWindowExA's window styles argument dwStyle and possibly lpWindowName, as described here: https://learn.microsoft.com/en-us/windows/desktop/winmsg/window-styles
This is how the arguments look like originally:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_OVERLAPPEDWINDOW, // Window style.
// Size and position.
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
However, in dwStyle, the normal window style WS_OVERLAPPEDWINDOW is defined as
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
with WS_OVERLAPPED being 0x00000000L.
Simply providing 0 and omitting the rest doesn't work, as also the documentation implies: "The window is an overlapped window. An overlapped window has a title bar and a border."
(The funny thing is, I am perfectly able to do this task in VB.NET (and even in VB6) by setting the ControlBox property to False and then by removing the titlebar using Text = "", so I strongly suspect that when possible in VB...)
How would I do my task in C++?
Just in case the WindowProc is needed in order to process a different message, here it is in its minimalistic version:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
(Compiling with VS 2017.)
The non-client area of a top-level window can be removed by using only the WS_POPUP style:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_POPUP, // Window style.
// Size and position.
100, 100, 400, 300,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
Note that CW_USEDEFAULT for size and position is only valid for overlapped windows. For popup windows you have to be explicit.
Depending on your use case, the technique described by this answer might be better suitable. Using the DWM API, it allows you to remove the non-client area, but keep the drop shadow to make the window stand out better from the background.

Textbox hide behind animation of gif

I'm make window in c++ with supporting winapi(not MFC), and I made gif animation on window with gdi++, and I create TextBox, it showing, but some part is behind gif. Image in this link : 1
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
hMWDC = GetDC(hwnd);
pGphcs = new Graphics(hMWDC);
WCHAR path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
PathRemoveFileSpecW(path);
PathAppendW(path, L"gifs\\test.gif");
pImg = new Image(path);
if (pImg) {
nFrmCnt = pImg->GetFrameCount(&FrameDimensionTime);
SetTimer(hwnd, DRAW_ANIM, 100, NULL);
}
break;
case WM_TIMER:
if (wParam == DRAW_ANIM)
{
pImg->SelectActiveFrame(&FrameDimensionTime, nFrm);
Rect DRC(0, 0, pImg->GetWidth(), pImg->GetHeight());
pGphcs->Clear(Color(128, 128, 128));
pGphcs->DrawImage(pImg, DRC);
if (nFrm < (nFrmCnt - 1)) nFrm++; else nFrm = 0;
}
break;
hwndText = CreateWindow(L"EDIT",
L"",
WS_CHILD | WS_VISIBLE,
350, 480, 55, 20,
hWnd, NULL, NULL, NULL);
I expected gif as background and TextBox will be front of it.
But nothing, :(
For performance reasons by default device context for given HWND does not clip a child window from the parent window's client area.
If parent window draws something in the same location as the child window, it draws also over child window. Accepting some (nowadays minimal) performance hit you can automatically clip children windows form main frame window painting area, by adding WS_CLIPCHILDREN style when creating main frame window. With this style any HDC obtained for main frame window will have area occupied by child control excluded form painting area. This protects child window from overpainting by it's parent window activity.
Setting WS_CLIPCHILDREN for main frame window should solve your problem.
hwnd = CreateWindow( class_name, title, some_styles | WS_CLIPCHILDREN, ... );
Sometimes child windows overlap each other and then they can overdraw each other. In this case WS_CLIPSIBLINGS applied to child windows (of the same parent window), protects one child form another painting.

How can I remove a window's non-client area completely?

I need a window featuring no title bar, none of the control boxes, no system menu, and no frames (all that functionality is provided with separate controls).
I suspect that this should be possible to do with CreateWindowExA's window styles argument dwStyle and possibly lpWindowName, as described here: https://learn.microsoft.com/en-us/windows/desktop/winmsg/window-styles
This is how the arguments look like originally:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_OVERLAPPEDWINDOW, // Window style.
// Size and position.
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
However, in dwStyle, the normal window style WS_OVERLAPPEDWINDOW is defined as
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
with WS_OVERLAPPED being 0x00000000L.
Simply providing 0 and omitting the rest doesn't work, as also the documentation implies: "The window is an overlapped window. An overlapped window has a title bar and a border."
(The funny thing is, I am perfectly able to do this task in VB.NET (and even in VB6) by setting the ControlBox property to False and then by removing the titlebar using Text = "", so I strongly suspect that when possible in VB...)
How would I do my task in C++?
Just in case the WindowProc is needed in order to process a different message, here it is in its minimalistic version:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
(Compiling with VS 2017.)
The non-client area of a top-level window can be removed by using only the WS_POPUP style:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_POPUP, // Window style.
// Size and position.
100, 100, 400, 300,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
Note that CW_USEDEFAULT for size and position is only valid for overlapped windows. For popup windows you have to be explicit.
Depending on your use case, the technique described by this answer might be better suitable. Using the DWM API, it allows you to remove the non-client area, but keep the drop shadow to make the window stand out better from the background.

Button Control disappears on click - Click Handler does not get fired on Clicking Button - Win32

I am working on Zoom SDK which is based on win32 gui.
I have created 3 buttons using CreateWindow method on the window handle, which is provided by the ZoomSDK.
Code + Screenshot - 1
Now there are two problems with this.
As soon as I click the buttons, they disappear.
See the Screen Shots BEFORE
See the Screen Shots AFTER
I want to know the reason why this is happening and how can I fix this?
HWND hFirstView, hSecondView;
cntrl->GetMeetingUIWnd(hFirstView, hSecondView);
cntrl->MoveFloatVideoWnd(100, 100);
HWND btnHwnd = CreateWindow(
TEXT("button"),
L"Open App",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
0, 0,
50, 25,
hFirstView,
(HMENU)100,
hInst,
NULL);
HWND btnHwnd2 = CreateWindow(
TEXT("button"),
L"Other",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
50, 0,
50, 25,
hFirstView,
(HMENU)101,
hInst,
NULL);
HWND btnHwnd3 = CreateWindow(
TEXT("button"),
L"Raise Hand",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
100, 0,
50, 25,
hFirstView,
(HMENU)103,
hInst,
NULL);
HDC hdc = GetDC(btnHwnd);
SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
SetTextColor(hdc, GetSysColor(COLOR_BACKGROUND));
ReleaseDC(btnHwnd, hdc);
int btnId = GetDlgCtrlID(btnHwnd);
//oldWndProc = (WNDPROC) GetWindowLong(hFirstView, GWL_WNDPROC);
oldWndProc = (WNDPROC) SetWindowLong(hFirstView,
GWL_WNDPROC, (LONG)WndProc);
SendMessage(btnHwnd, BM_SETSTATE, 1, 0);
SetWindowText(hFirstView, L"Title");
I want to handle click event for these buttons. I have tried to use SetWindowsLong to set another WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int id = GetWindowLong(hWnd, GWL_ID);
switch (message)
{
case WM_COMMAND: {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
if (wParam == 1023) {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
}
}
break;
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}
Now, this WndProc gets called for other events such mouse move etc. It is not working for my three buttons. I want to handle click event i.e WM_COMMAND or any other technique possible.
Because I can not go inside the sdk (they don't provide sources, only .lib) so I can not change their WndProc, nor their internal WM_PAINT. The buttons are sort of overlay on top.
You should not be calling SetBkColor() and SetTextColor() from outside a WM_PAINT handler. The correct way to color a button is to either:
have the parent window handle the WM_CTLCOLORBTN notification.
The WM_CTLCOLORBTN message is sent to the parent window of a button before drawing the button. The parent window can change the button's text and background colors. 
give the button the BS_OWNERDRAW style, and then have the parent window handle the WM_DRAWITEM notification.
Sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
Also, when a button sends a BN_CLICKED notification to its parent window, your subclass WndProc() doesn't need to use GetWindowLong(GWL_ID). First, you are calling it on the wrong HWND. And second, the button ID is carried in the message's wParam data.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_COMMAND: {
if (HIWORD(wParam) == BN_CLICKED) {
switch (LOWORD(wParam)) {
case 100:
case 101:
case 103:
MessageBox(NULL, L"Sign of relief!", L"Whoaa!", 0);
break;
}
}
break;
}
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}

MDI Child Window Size

I am trying to create a child window within an MDI MainWindow...The main window is 1024 x 768 in size...when I try to use CreateWindowEx() to create a child window the size seems to be offset somehow...in other words a 1024 x 768 child window is smaller than its parent...how can I account for this difference? When I use GetCLientRect() with the main window's handle...the size is still smaller...I don't care to make the child window the same size. I want the child window to encompass the exact size of an image that is 750x563. When I set that size within the parameters of CreateWindowEx(), the child window is too small...
Here is the code I use within the MainWndProc to create a child window:
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch(Msg)
{
case WM_CREATE:
{
//OnCreate(hWnd, NULL);
CLIENTCREATESTRUCT ccs;
ccs.hWindowMenu = GetSubMenu(GetMenu(hWnd), 2);
ccs.idFirstChild = StartChildrenNo;
hWndChildFrame = CreateWindowEx(WS_EX_CLIENTEDGE,
L"MDICLIENT",
NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL
| WS_HSCROLL | WS_VISIBLE,
0,
0,
1024,
768,
hWnd,
(HMENU)IDM_FILE_NEW,
GetModuleHandle(NULL),
(LPVOID)&ccs);
if(hWndChildFrame == NULL)
MessageBox(hWnd, L"Could not create MDI client.", L"Error", MB_OK | MB_ICONERROR);
CreateNewMDIChild(hWndChildFrame);
return 0;
}
...
}
To determine size how the MDI child window can be large, use GetClientRect() of the MDI client window.
To compute needed window size for the MDI child window use AdjustWindowRect() or AdjustWindowRectEx(). Those can convert between window and client size.