Win32 - Make part of window a translucent while another part opaque? - c

I want one part of a window to display an image with a certain opacity while the other part to work as normal. Both parts shouldn't pass clicks through.
I have tried making the main window a certain colour then using SetLayeredWindowAttributes to make that colour transparent(so only the client area is transparent). Then having a child window over it with my translucent image. However the clicks pass through the window(even though I don't have WS_EX_TRANSPARENT). Alphablend doesn't seem to works since the bitmap isn't 32bmp. So now I am trying to use updatelayeredwindows but I am having trouble setting the region to update it.
case WM_CREATE:
hbmp = (HBITMAP)LoadImageA(NULL, "courtyard.bmp", IMAGE_BITMAP, 1920, 1080, LR_LOADFROMFILE);
HDC hdc = CreateCompatibleDC(NULL);
HBITMAP hbmp_old = (HBITMAP)SelectObject(hdc, hbmp);
POINT dcOffset = {0, 0};
SIZE size = {600, 395};
BLENDFUNCTION bf = {AC_SRC_OVER, 0, 100, 0};
RECT wrect;
GetClientRect(hwnd, &wrect);
wrect.top = wrect.top + 43;
UPDATELAYEREDWINDOWINFO info = {sizeof(info), GetDC(NULL), NULL, &size, hdc, &dcOffset, 0, &bf, ULW_ALPHA, &wrect};
UpdateLayeredWindowIndirect(hwnd, &info);
SelectObject(hdc, hbmp_old);
DeleteDC(hdc);
DeleteObject(hbmp);
HWND hbutton = CreateWindowExA(0,
"BUTTON",
"X",
WS_VISIBLE | WS_CHILD | BS_FLAT,
10,
10,
100,
100,
hwnd,
(HMENU)NULL,
NULL,
(LPVOID)NULL);
break;
The parts out of wrect are just a black translucent colour.
Here is my main window:
hwnd = CreateWindowExA(WS_EX_OVERLAPPEDWINDOW | WS_EX_LAYERED,
window_name,
window_title,
WS_OVERLAPPEDWINDOW,
(monitor_dimension.width - window_width) / 2,
(monitor_dimension.height - window_height) / 2 - 75,
window_width,
window_height,
(HWND)NULL,
(HMENU)NULL,
hInstance,
(LPVOID)NULL);

I get the result using SetLayeredWindowAttributes(hWnd, RGB(255, 0, 0), 0, LWA_COLORKEY); without manifest and the clicks don't pass through.
The following code adapted from SetLayeredWindowAttributes() causes mouse clicks to go through after minimizing window | WinAPI.
// WindowsProject2.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "WindowsProject2.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WINDOWSPROJECT2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT2));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW 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 = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT2));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(255, 0, 0));
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT2);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, RGB(255, 0, 0), 0 /*doesn't matter*/, LWA_COLORKEY);
HWND hbutton = CreateWindowExA(0,
"BUTTON",
"X",
WS_VISIBLE | WS_CHILD | BS_FLAT,
10,
10,
100,
100,
hWnd,
(HMENU)NULL,
NULL,
(LPVOID)NULL);
/*HWND hbackground = CreateWindowEx(0,
L"STATIC",
NULL,
WS_CHILD | WS_VISIBLE | SS_BITMAP,
0,
0,
600,
400,
hWnd,
NULL,
NULL,
(LPVOID)NULL);
setImage(hbackground, L"test.bmp", 600, 400);*/
//SetWindowLong(hbackground, GWL_EXSTYLE, GetWindowLong(hbackground, GWL_EXSTYLE) | WS_EX_LAYERED);
//SetLayeredWindowAttributes(hbackground, 0, (255 * 50) / 100, LWA_ALPHA);
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}

Related

How to hide the cursor completely?

When I call ShowCursor(0) (which by the way, does not take an HWND, this is weird), the cursor is hidden, but when I do a special action, for example resizing the window or drag-and-drop a file, the cursor corresponding to this action appears. I don't want to see the cursor whatever action the user is doing. If you wonder why, it's because I'd like to draw it with OpenGL.
I have a popup and layered window:
#define UNICODE
#include <windows.h>
#include <dwmapi.h>
LRESULT CALLBACK wnd_proc(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp){
switch(uMsg){
case WM_CREATE: return 0;
case WM_NCHITTEST: return HTBOTTOM;
case WM_DESTROY: PostQuitMessage(0); return 0;
default: return DefWindowProc(hWnd, uMsg, wp, lp);
}
}
HDC hDC; HGLRC hRC;
int main(void){
WNDCLASSEX wcx = {};
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = wnd_proc;
wcx.lpszClassName = L"Win32Class";
wcx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wcx.hbrBackground = CreateSolidBrush(0x00000000);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClassEx(&wcx);
HWND hWnd = CreateWindowEx(WS_EX_ACCEPTFILES | WS_EX_LAYERED, wcx.lpszClassName,
L"Win32Window", WS_POPUP | WS_VISIBLE, 50, 50, 800, 400, NULL, NULL, NULL, NULL);
SetLayeredWindowAttributes(hWnd, RGB(200, 0, 200), 0, LWA_COLORKEY);
ShowCursor(0);
/*DWM_BLURBEHIND blur = {0};
blur.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
blur.fEnable = 1;
blur.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
DwmEnableBlurBehindWindow(hWnd, &blur);*/
MSG msg; while(GetMessage(&msg, NULL, 0, 0)){
DispatchMessage(&msg);
}
}
This is a truncated part of my test file. OpenGL is not included, but I just need to know how to delete the cursor.
If you compile and execute it, you can see that when your cursor is on the window, it is not visible, but when you resize the window the cursor appears, same as when you drag-and-drop a file.

Win32 API Child window doesn't appear in parent's area

I am trying to write a simple app in Win32 API. The goal is to create a parent window with blue background and a child window (visible as a small red square) inside it.
I define a parent and child windows:
WNDCLASSEXW 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 = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAMEPRACTICE3));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 255));
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_GAMEPRACTICE3);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&wcex);
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE | WS_BORDER,
0,0, 400, 600, HWND_DESKTOP, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Child window
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpszClassName = childClass;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hInstance = hInst;
wc.hbrBackground = CreateSolidBrush(RGB(255, 0, 0));
wc.lpfnWndProc = WndProc;
RegisterClassEx(&wc);
HWND hwnd_child = CreateWindow(childClass, NULL,
WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
0, 0, 32, 32,
hWnd, 0, hInst, 0);
ShowWindow(hwnd_child, nCmdShow);
UpdateWindow(hwnd_child);
When I launch the app I get the following output:
It seems that the child window is not displaying at all.
I tried to search similar problems on the Internet but none of the solutions worked for me so far.
Source code:
#include "stdafx.h"
#include "GamePractice3.h"
#define MAX_LOADSTRING 100
HINSTANCE hInst;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
WCHAR childClass[MAX_LOADSTRING];
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_GAMEPRACTICE3, szWindowClass, MAX_LOADSTRING);
WNDCLASSEXW 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 = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAMEPRACTICE3));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 255));
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_GAMEPRACTICE3);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&wcex);
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GAMEPRACTICE3));
MSG msg;
hInst = hInstance;
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE | WS_BORDER,
0,0, 400, 600, HWND_DESKTOP, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpszClassName = childClass;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hInstance = hInst;
wc.hbrBackground = CreateSolidBrush(RGB(255, 0, 0));
wc.lpfnWndProc = WndProc;
RegisterClassEx(&wc);
HWND hwnd_child = CreateWindow(childClass, NULL,
WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
0, 0, 32, 32,
hWnd, 0, hInst, 0);
ShowWindow(hwnd_child, nCmdShow);
UpdateWindow(hwnd_child);
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Any help would be appreciated :).
For Child window doesn't appear in parent's area issue, in addition to #daniel_p's answer:
WS_OVERLAPPEDWINDOW style is not relevant here. This style gives the window a title bar, a window menu, a sizing border, and minimize and maximize buttons.
Error checking is necessary. You will find that register child window class failed and return 0.
Specify a valid null-terminated string for class name. Class name is NULL is one of factors cause RegisterClassEx fail.
Initialize WNDCLASSEX struct like: WNDCLASSEX wc = {0}; Without initialization, some value which you don't set explicitly later will be garbage value. This is another factor cause RegisterClassEx fail. Or you can set every value explicitly.
With the following editions your code will work:
WCHAR childClass[MAX_LOADSTRING] = L"Child Window";
// ...
WNDCLASSEX wc = {0};
Example for error checking of RegisterClassEx function:
DWORD errCode = 0;
ATOM childClassId = RegisterClassEx(&wc);
if (!childClassId)
{
errCode = GetLastError();
MessageBox(NULL, L"RegisterClassEx failed!", L"Error", MB_ICONERROR | MB_OKCANCEL);
return 0;
}
I managed to resolve the issue.
I removed WS_OVERLAPPEDWINDOW from the creation of the child window
I added seperate Window Procedure for the child window with
DefWindowProc
I created a string for childClass and loaded it (LoadStringW)
I initialized all 11 fields of WNDCLASSEXW structure (not sure if it's necessary)
Hope it helps.

DrawThemeBackground() is not painting tab properly

When I use DrawThemeBackground() with part TABP_TABITEMRIGHTEDGE and state TIRES_NORMAL it leaves a rect 2 pixels wide on the right unpainted. It doesn't happen with part TABP_TABITEM, TABP_TABITEMLEFTEDGE or TABP_TABITEMBOTHEDGE. What can I do to fix this?
Edit: This only happens in windows 10 and not in widnows xp. I could erase the whole background, then paint the tab and this would solve my problem, and I wouldn't see any flicker in windows 10, but it will flicker in older versions of windows and I don't want that, so I erase the background excluding the area occupied by the tab. In windows 10 it leaves a black rect 2 pixels wide to the right of the tab. Is there a theme function that tells you how much of the rect specified to DrawThemeBackground() will be painted by DrawThemeBackground()?
#include <windows.h>
#include <uxtheme.h>
#include <vsstyle.h>
#include <vssym32.h>
#pragma comment(lib, "uxtheme.lib")
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HTHEME hTheme;
static HBRUSH hbrBkg;
switch(msg)
{
case WM_CREATE:
hTheme = OpenThemeData(0, L"Tab");
hbrBkg = CreateSolidBrush(RGB(0, 120, 120));
break;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
if(hdc)
{
HBRUSH hbr = CreateSolidBrush(RGB(255, 0, 0));
if(hbrBkg) FillRect(hdc, &ps.rcPaint, hbrBkg);
if(hbr)
{
RECT rc = { 4, 4, 104, 44 };
FillRect(hdc, &rc, hbr);
if(hTheme) DrawThemeBackground(hTheme, hdc, TABP_TABITEMRIGHTEDGE, TIRES_NORMAL, &rc, 0);
DeleteObject(hbr);
}
EndPaint(hwnd, &ps);
}
}
break;
case WM_DESTROY:
if(hTheme) CloseThemeData(hTheme);
if(hbrBkg) DeleteObject(hbrBkg);
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
const WCHAR szClassName[] = L"Themes";
WNDCLASSEXW wc;
HWND hwnd;
MSG msg;
SecureZeroMemory(&wc, sizeof(WNDCLASSEXW));
wc.cbSize = sizeof(WNDCLASSEXW);
wc.hCursor = LoadCursorW(0, IDC_ARROW);
wc.hIcon = LoadIconW(0, IDI_APPLICATION);;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = szClassName;
if(!RegisterClassExW(&wc)) return 0;
hwnd = CreateWindowExW(0, szClassName, L"Test", WS_OVERLAPPEDWINDOW, 140, 140, 440, 240, 0, 0, hInstance, 0);
if(!hwnd) return 0;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessageW(&msg, 0, 0, 0) > 0)
{
if(!IsDialogMessageW(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}

How to update the text inside a window?

I am trying to create my first GUI Application. I just want to display a text(could be a number maybe), and then in a loop change/update it. I found some basic examples to create and display a window, with some text, but how do i update the text?
Could someone please show me a simple example? A good example would be displaying the time.
Thanks in advance!
Update:
Here is my code. It is nothing special, i just took an example from MSDN.
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T( "win32app" );
static TCHAR szTitle[] = _T( "Win32 Guided Tour Application" );
HINSTANCE hInst;
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 = LoadIcon( hInstance, MAKEINTRESOURCE( IDI_APPLICATION ) );
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon( wcex.hInstance, MAKEINTRESOURCE( IDI_APPLICATION ) );
if ( !RegisterClassEx( &wcex ) )
{
MessageBox( NULL, _T( "Call to RegisterClassEx failed!" ), _T( "Win32 Guided Tour" ), NULL );
return 1;
}
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL );
if ( !hWnd )
{
MessageBox( NULL, _T( "Call to CreateWindow failed!" ), _T( "Win32 Guided Tour" ), NULL );
return 1;
}
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
HDC hdc;
PAINTSTRUCT ps;
// Main message loop:
MSG msg;
char test[ 100 ] = { 0 };
int i = 0;
while ( GetMessage( &msg, NULL, 0, 0 ) )
{
i++;
hdc = BeginPaint( hWnd, &ps );
sprintf(test, "%d", i);
TextOutA( hdc, 5, 5, test, strlen( test ) );
EndPaint( hWnd, &ps );
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return ( int )msg.wParam;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T( "Hello, World!" );
switch ( message )
{
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
TextOut( hdc, 5, 5, greeting, _tcslen( greeting ) );
EndPaint( hWnd, &ps );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
break;
}
return 0;
}
1) Do not do the drawing in your loop.
2) Only draw in WM_PAINT
3) Create a variable that contains what you want to draw
4) If you want to redraw your window, call InvalidateRect(hWnd, NULL, NULL) and it will post a WM_PAINT message to your window proc.
5) I'd suggest creating a timer that redraws maybe once every 5 seconds. Ideally, you would redraw when something changes the state of your data. If you redraw every time through your message loop, it's going to continuously redraw and be very unresponsive.
This example shows you how a number is printed in the center of the window and incremented and updated whenever your press with the left mouse button anywhere on the window's client area.
#include <windows.h>
#include <cstdio>
LRESULT __stdcall wndProc(HWND, UINT, WPARAM, LPARAM);
void register_window_class(HINSTANCE hInstance)
{
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX);
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(COLOR_BTNFACE + 1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "wndclass";
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wndclass);
}
HWND create_window(HINSTANCE hInstance)
{
HWND hwnd = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
"wndclass",
"My first window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
hInstance,
NULL);
return hwnd;
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* szCmdLine, int iCmdShow)
{
try{
register_window_class(hInstance);
HWND hwnd = create_window(hInstance);
ShowWindow(hwnd, SW_SHOWNORMAL);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return EXIT_SUCCESS;
}
catch(...){
return EXIT_FAILURE;
}
}
LRESULT __stdcall wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
RECT rect;
PAINTSTRUCT ps;
static int iCount = 0;
static char buffer[256];
switch(msg){
case WM_LBUTTONDOWN:
++iCount;
snprintf(buffer, 256, "%d", iCount);
InvalidateRect(hwnd, NULL, true);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
SetTextAlign(hdc, TA_CENTER);
TextOut(hdc, rect.right / 2, rect.bottom / 2, buffer, strlen(buffer));
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
So when you click with the left mouse button, the message
WM_LBUTTONDOWN
is sent to your window procedure by Windows. Whenever that occurs, a static int is incremented, written to a char buffer. Finally, the call
InvalidateRect(hwnd, NULL, true);
invalidates the window's entire client area. This means that WM_PAINT will be called because there is a portion of the client area that is invalid. Also, the last argument which is set to true makes sure that when
hdc = BeginPaint(hwnd, &ps);
is executed, the invalid section of the client area is painted over with the background brush specified in the window class. This effectively erases any previous window contents so that
TextOut(hdc, rect.right / 2, rect.right / 2, buffer);
has a clean area to write on.
It is a good habit to structure your program so that all information is accumulated so a complete re-paint can be done in WM_PAINT (basically quoting the Win32 bible "Programming Windows" by Charles Petzold).
You need to do all your drawing in the WM_PAINT handler in your message loop between the BeginPaint/EndPaint calls, otherwise it'll get overwritten.
Here's an example that displays the time. I use a timer to invalidate the window which generates a WM_PAINT message but you can do it a different way if you like.
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
HINSTANCE hInst;
HWND hWnd;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch(message)
{
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
SYSTEMTIME time;
GetLocalTime(&time);
wchar_t timeString[30] = {};
GetTimeFormatEx(nullptr, 0, &time, nullptr, timeString, 30);
RECT clientRect;
GetClientRect(hWnd, &clientRect);
DrawText(hdc, timeString, -1, &clientRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint(hWnd, &ps);
}
break;
case WM_TIMER:
InvalidateRect(hWnd, nullptr, false);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
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 = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"TestClass";
wcex.hIconSm = NULL;
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
RECT sz = {0, 0, 128, 64};
AdjustWindowRect(&sz, WS_OVERLAPPEDWINDOW, TRUE);
hWnd = CreateWindow(L"TestClass", L"Test Window", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, sz.right - sz.left, sz.bottom - sz.top,
NULL, NULL, hInstance, NULL);
if(!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MyRegisterClass(hInstance);
if(!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
SetTimer(hWnd, 1, 1000, nullptr);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}

WinApi, Push button are not displayed

I'm trying to create simple windows app uisng WinAPi.
Here is the code:
#include "stdafx.h"
#include "APIup.h"
#define MAX_LOADSTRING 100
HWND hWnd,cw13;
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
ATOM Register(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc_dla13(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_APIUP, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
Register(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_APIUP));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
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 = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APIUP));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_APIUP);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
ATOM Register(HINSTANCE hInstance)
{
WNDCLASSEX cw13class;
cw13class.cbSize = sizeof(WNDCLASSEX);
cw13class.style = CS_HREDRAW | CS_VREDRAW;
cw13class.lpfnWndProc = WndProc_dla13;
cw13class.cbClsExtra = 0;
cw13class.cbWndExtra = 0;
cw13class.hInstance = hInstance;
cw13class.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APIUP));
cw13class.hCursor = LoadCursor(NULL, IDC_ARROW);
cw13class.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
cw13class.lpszMenuName = NULL;
cw13class.lpszClassName = L"13class";
cw13class.hIconSm = LoadIcon(cw13class.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&cw13class);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 100, 100, NULL, NULL, hInstance, NULL);
cw13=CreateWindow(L"13class",L"Ćwiczenie 13",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,300,300,NULL,NULL,hInst,NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case ID_32771:
ShowWindow(cw13, 1);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProc_dla13 (HWND hWnd, UINT msg/*message*/, WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
CreateWindowW(L"button", L"Beep",
WS_VISIBLE | WS_CHILD ,
20, 50, 80, 25,
cw13, (HMENU) 1, hInst, NULL);
CreateWindowW(L"button", L"Quit",
WS_VISIBLE | WS_CHILD ,
120, 50, 80, 25,
cw13, (HMENU) 2, NULL, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == 1) {
Beep(40, 50);
}
if (LOWORD(wParam) == 2) {
PostQuitMessage(0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
And the problem is that: when i create window 'cw13' it is created and displayed, but push buttons are not.I created two separate WndProc functions. Other messages are executed correctly( like WM_QUIT), only CreateWindowW under WM_CREATE,witch should create and show Push buttons aren't. Where is the problem?
When processing the WM_CREATE message, your call to CreateWindow(L"13class") is still running. Your cw13 variable has not been assigned yet, so you are assigning an invalid HWND as the parent of your buttons. That is why they do not appear. Use the hwnd parameter of WndProc_dla13() instead as the parent. That will be the same HWND that gets assigned to the cw13 variable once CreateWindow(L"13class") exits.

Resources