Win32 - Child Window Painting - c++

I have a main window that contains two child windows (Child1 & Child2). Moving Child2 on top of Child1 and then moving Child1 away, the Child 2 client area and non-client area gets painted onto Child 1.
See image here: child windows
Any help please?
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndChildProc1(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndChildProc2(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow)
{
WNDCLASS wndclass;
HWND hwndMain, hwndChild1, hwndChild2;
MSG msg;
//register main window class
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hIcon = 0;
wndclass.hCursor = LoadCursor(0, IDC_ARROW);
wndclass.hInstance = hInstance;
wndclass.hbrBackground = (HBRUSH) COLOR_WINDOW;
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = TEXT("MainWindow");
if(!RegisterClass(&wndclass)) return 0;
//register child window class
wndclass.lpfnWndProc = WndChildProc1;
wndclass.lpszClassName = TEXT("ChildWindow1");
if(!RegisterClass(&wndclass)) return 0;
wndclass.lpfnWndProc = WndChildProc2;
wndclass.lpszClassName = TEXT("ChildWindow2");
if(!RegisterClass(&wndclass)) return 0;
//create main window
hwndMain = CreateWindow(TEXT("MainWindow"), TEXT("Main Window"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, hInstance, 0);
if(!hwndMain) return 0;
//create child windows
hwndChild1 = CreateWindow(TEXT("ChildWindow1"), TEXT("Child Window 1"),
WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_VISIBLE,
10, 10, 200, 300,
hwndMain, 0, hInstance, 0);
hwndChild2 = CreateWindow(TEXT("ChildWindow2"), TEXT("Child Window 2"),
WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_VISIBLE,
250, 10, 200, 300,
hwndMain, 0, hInstance, 0);
ShowWindow(hwndMain, SW_SHOW);
UpdateWindow(hwndMain);
while(GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK WndChildProc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK WndChildProc2(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Thanks.

Related

How to get window control by position (win32 API)?

Is there a way to get the control handle using the coordinate position of the control? In other words, is there a way to find the control in the window area provided that we know its coordinate position?
You can use WindowFromPoint:
Here is the sample:
#include <Windows.h>
#include <iostream>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szCmdLine, _In_ int iCmdShow)
{
static TCHAR szAppName[] = TEXT("hello windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
100,
100,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
POINT pt;
char bf[100];
HWND h;
HDC hdc;
RECT rc;
case WM_LBUTTONDOWN:
pt.x = 10;
pt.y = 10;
hdc = GetDC(hwnd);
h = WindowFromPoint(pt);
GetClientRect(hwnd, &rc);
sprintf_s(bf, 100, "%p\n", h);
TextOut(hdc,rc.right/2,rc.bottom/2,bf,strlen(bf));
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
When I press the left button, the handle for setting the coordinates is displayed in the middle of the screen.

Forcing the recall of WM_PAINT

I've created a window using CreateWindowEx and that is working fine. The window opens.
In the function where I process messages, specifically WM_PAINT, I grab the cursor position using GetCursorPos and then draw a rectangle there. However, I would like the window to continuously update and redraw this rectangle, acting like a cursor.
I've created a thread like the following to try and force this:
DWORD WINAPI RedrawLoop(LPVOID lpParam) {
HWND handle = (HWND)lpParam;
while (true) {
RECT lpRect;
GetClientRect(handle, &lpRect);
InvalidateRect(handle, &lpRect, TRUE);
UpdateWindow(handle);
}
return 0;
}
However, this is not working. I've already checked that the handle passed in is the same as the window handle outside the thread.
I've also tried sending SendMessage(handle, WM_PAINT, 0, 0); and RedrawWindow(handle, NULL, NULL, 0); continuously with no luck.
First, you can get the current cursor position by processing the WM_MOUSEMOVE message and invalidate the current window.
Then draw a rectangle through the Rectangle function in the WM_PAINT message. (Note: The origin of coordinates is the upper left corner of the screen)
Here is the sample:
#include <Windows.h>
#include <commctrl.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("hello windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
static POINT pt;
switch (message)
{
case WM_CREATE:
{
}
case WM_MOUSEMOVE:
{
Sleep(100);
GetCursorPos(&pt);
InvalidateRect(hwnd, NULL, FALSE);
return 0;
}
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
Rectangle(hdc, pt.x-rect.right/4 , pt.y-rect.bottom/4, pt.x + rect.right / 4, pt.y + rect.bottom / 4);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

How to correctly draw simple non-client area (4 px red border)?

I'm trying to draw a custom painted non-client area, instead of default theme border (Windows 10).
I handled WM_NCCALCSIZE to resize the non-client area to 4 pixels on each side and then handled WM_NCPAINT to draw the red border.
My custom painting succeeds when application is first displayed, but fails to redraw either when application is resized, or when minimized and restored, despite the fact that both WM_NCCALCSIZE and WM_NCPAINT are called during resizing or when window is restored.
#pragma comment(lib, "UxTheme")
#include <windows.h>
#include <uxtheme.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = (HICON) LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(0,128,0));
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "window";
wcex.hIconSm = NULL;
RegisterClassEx(&wcex);
HWND hWnd = CreateWindowEx(
WS_EX_COMPOSITED,
"window",
NULL,
WS_OVERLAPPEDWINDOW,
100,
100,
600,
400,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CREATE:
SetWindowTheme(hWnd, L"", L"");
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCCALCSIZE:
{
RECT rect;
GetWindowRect(hWnd, &rect);
LPNCCALCSIZE_PARAMS ncParams = (LPNCCALCSIZE_PARAMS) lParam;
ncParams->rgrc[0].top = rect.top + 4;
ncParams->rgrc[0].left = rect.left + 4;
ncParams->rgrc[0].bottom = rect.bottom - 4;
ncParams->rgrc[0].right = rect.right - 4;
return 0;
}
case WM_NCPAINT:
{
RECT rect;
GetWindowRect(hWnd, &rect);
HDC dc = GetDCEx(hWnd, (HRGN) wParam, DCX_WINDOW | DCX_CACHE | DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
HPEN pen = CreatePen(PS_INSIDEFRAME, 4, RGB(255, 0, 0));
HGDIOBJ old = SelectObject(dc, pen);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
Rectangle(dc, 0, 0, width, height);
SelectObject(dc, old);
DeleteObject(pen);
ReleaseDC(hWnd, dc);
return 0;
}
case WM_NCACTIVATE:
RedrawWindow(hWnd, NULL, NULL, RDW_UPDATENOW);
return 0;
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
The wParam of WM_NCPAINT message sometimes returns 1 instead of a handle to a region (HRGN). In that case HRGN must be created using CreateRectRgn function.
#pragma comment(lib, "UxTheme")
#include <windows.h>
#include <uxtheme.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = (HICON) LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(0,128,0));
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "window";
wcex.hIconSm = NULL;
RegisterClassEx(&wcex);
HWND hWnd = CreateWindowEx(
NULL,
"window",
NULL,
WS_OVERLAPPEDWINDOW,
100,
100,
600,
400,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CREATE:
SetWindowTheme(hWnd, L"", L"");
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCCALCSIZE:
{
LPNCCALCSIZE_PARAMS ncParams = (LPNCCALCSIZE_PARAMS) lParam;
ncParams->rgrc[0].top += 4;
ncParams->rgrc[0].left += 4;
ncParams->rgrc[0].bottom -= 4;
ncParams->rgrc[0].right -= 4;
return 0;
}
case WM_NCPAINT:
{
RECT rect;
GetWindowRect(hWnd, &rect);
HRGN region = NULL;
if (wParam == NULLREGION) {
region = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
} else {
HRGN copy = CreateRectRgn(0, 0, 0, 0);
if (CombineRgn(copy, (HRGN) wParam, NULL, RGN_COPY)) {
region = copy;
} else {
DeleteObject(copy);
}
}
HDC dc = GetDCEx(hWnd, region, DCX_WINDOW | DCX_CACHE | DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
if (!dc && region) {
DeleteObject(region);
}
HPEN pen = CreatePen(PS_INSIDEFRAME, 4, RGB(255, 0, 0));
HGDIOBJ old = SelectObject(dc, pen);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
Rectangle(dc, 0, 0, width, height);
SelectObject(dc, old);
ReleaseDC(hWnd, dc);
DeleteObject(pen);
return 0;
}
case WM_NCACTIVATE:
RedrawWindow(hWnd, NULL, NULL, RDW_UPDATENOW);
return 0;
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

How to update WC_EDIT control margins when resized

This program creates WC_EDIT control inside the main window. The main window resizes edit control whenever the window itself is resized. I am trying to set margins of edit control content by updating formatting rectange of WC_EDIT control whenever it is resized.
Main window responds to WM_SIZE message and resizes edit control, then edit control responds to its own WM_SIZE message and tries to update formatting rectangle using EM_SETRECT, but nothing happens.
#include <windows.h>
#include <commctrl.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK EditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND hwnd;
HWND editHwnd;
WNDPROC origEditProc;
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR pCmdLine, int nCmdShow)
{
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = "Window Class";
RegisterClass(&wc);
hwnd = CreateWindow(
wc.lpszClassName,
"",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
editHwnd = CreateWindow(
WC_EDIT,
"Lorem ipsum",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0,
0,
100,
100,
hwnd,
NULL,
hInstance,
NULL
);
origEditProc = (WNDPROC) GetWindowLongPtr(editHwnd, GWLP_WNDPROC);
SetWindowLongPtr(editHwnd, GWLP_WNDPROC, (LONG_PTR)EditWindowProc);
ShowWindow(hwnd, nCmdShow);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
return 0;
case WM_SIZE:
RECT clientRect;
GetClientRect(hwnd, &clientRect);
SetWindowPos(editHwnd, NULL, 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK EditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
RECT rect;
GetClientRect(editHwnd, &rect);
rect.left += 50;
rect.top += 50;
rect.right -= 50;
rect.bottom -= 50;
SendMessage(editHwnd, EM_SETRECT, NULL, (LPARAM)&rect);
}
return CallWindowProc(origEditProc, hwnd, uMsg, wParam, lParam);
}
Original window procedure of the WC_EDIT control should be called before updating formatting rectangle:
LRESULT CALLBACK EditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT result = CallWindowProc(origEditProc, hwnd, uMsg, wParam, lParam);
switch (uMsg)
{
case WM_SIZE:
RECT rect;
GetClientRect(editHwnd, &rect);
rect.left += 50;
rect.top += 50;
rect.right -= 50;
rect.bottom -= 50;
SendMessage(editHwnd, EM_SETRECT, NULL, (LPARAM)&rect);
}
return result;
}

Can i put my window code in function or header

I have this code for crearing a window and i was wondering if i could put it in aheader or in a separate function to optimize my projects. And if so, could I manipulate its size and content from the separate program The code is:
#include <windows.h>
#include <windowsx.h>
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = "WindowClass1";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, "WindowClass1",
"Our First Windowed Program",
WS_OVERLAPPEDWINDOW,
300,
300,
500,
400,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}