Related
I want to blur a window, and I have used DwmEnableBlurBehindWindow(), DwmExtendFrameIntoClientArea() and DwmSetWindowAttribute() (to enable the client area rendering). However, it fails to blur, and instead makes the client area white.
Minimum reproducible code:
#include <dwmapi.h>
#include <gdiplus.h>
#include <stdio.h>
#include <windows.h>
HWND hwnd;
HRESULT enableNCRendering(HWND hWnd)
{
enum DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED;
HRESULT hr = DwmSetWindowAttribute(hWnd,
DWMWA_NCRENDERING_POLICY,
&ncrp,
sizeof(ncrp));
if (!SUCCEEDED(hr))
printf("Failed 0\n");
return hr;
}
HRESULT EnableBlurBehind(HWND hwnd)
{
DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
HRESULT hr = DwmEnableBlurBehindWindow(hwnd, &bb);
if (!SUCCEEDED(hr))
printf("Failed 1\n");
return hr;
}
HRESULT ExtendIntoClientAll(HWND hwnd)
{
MARGINS margins = {-1};
HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
if (!SUCCEEDED(hr))
printf("Failed 2\n");
return hr;
}
ATOM MyRegisterClass(HINSTANCE hInst, LPCWSTR name, UINT styles, COLORREF bkg_colour, WNDPROC proc)
{
WNDCLASSEXW wc;
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = styles;
wc.lpfnWndProc = proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
wc.hbrBackground = (HBRUSH)CreateSolidBrush(bkg_colour); // CreateSolidBrush(RGB(255, 0, 0))
wc.lpszMenuName = NULL;
wc.hIconSm = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.lpszClassName = (LPCWSTR)name;
return RegisterClassExW(&wc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_NCHITTEST:
return HTCAPTION;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wp, lp);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance, L"Main", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, RGB(255, 0, 0), WndProc);
hwnd = CreateWindowExW(WS_EX_LAYERED, L"Main", L"main", WS_POPUP, 0, 0, 1000, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
return 1;
SetLayeredWindowAttributes(hwnd, 0, 100, LWA_ALPHA);
enableNCRendering(hwnd);
EnableBlurBehind(hwnd);
ExtendIntoClientAll(hwnd);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
I have also tried SetWindowCompositionAttributes() but it was undefined in Mingw, and I wasn't able to find much information on using that. It also doesn't give the desired effect and gives barely any blur:
#include <Winerror.h>
#include <dwmapi.h>
#include <gdiplus.h>
#include <stdio.h>
#include <windows.h>
HWND hwnd;
struct ACCENTPOLICY
{
int na;
int nf;
int nc;
int nA;
};
struct WINCOMPATTRDATA
{
int na;
PVOID pd;
ULONG ul;
};
typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
void makeBlur()
{
const HINSTANCE hm = LoadLibraryW(L"user32.dll");
if (hm)
{
const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hm, "SetWindowCompositionAttribute");
if (SetWindowCompositionAttribute)
{
struct ACCENTPOLICY policy = {3, 0, 0, 0};
struct WINCOMPATTRDATA data = {19, &policy, sizeof(ACCENTPOLICY)};
SetWindowCompositionAttribute(hwnd, &data);
}
FreeLibrary(hm);
}
}
ATOM MyRegisterClass(HINSTANCE hInst, LPCWSTR name, UINT styles, COLORREF bkg_colour, WNDPROC proc)
{
WNDCLASSEXW wc;
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = styles;
wc.lpfnWndProc = proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
wc.hbrBackground = (HBRUSH)CreateSolidBrush(bkg_colour); // CreateSolidBrush(RGB(255, 0, 0))
wc.lpszMenuName = NULL;
wc.hIconSm = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.lpszClassName = (LPCWSTR)name;
return RegisterClassExW(&wc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_NCHITTEST:
return HTCAPTION;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wp, lp);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
//getting accent colors
DWORD color = 0;
BOOL opaque = FALSE;
DwmGetColorizationColor(&color, &opaque);
BYTE blue = color;
color = color >> 8;
BYTE green = color;
color = color >> 8;
BYTE red = color;
color = color >> 8;
BYTE alpha = color;
MyRegisterClass(hInstance, L"Main", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, RGB(red, green, blue), WndProc);
hwnd = CreateWindowExW(WS_EX_LAYERED, L"Main", L"main", WS_POPUP, 0, 0, 1000, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
return 1;
SetLayeredWindowAttributes(hwnd, 0, 100, LWA_ALPHA);
makeBlur();
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
How can I make my window blur?
The DwmEnableBlurBehindWindow documentation states:
Beginning with Windows 8, calling this function doesn't result in the blur effect, due to a style change in the way windows are rendered.
Aero Glass was officially discontinued in Windows 8. However, Aero Glass made a comeback (sort of) in Windows 10, as the Taskbar and some system notifications still use it. You have to use the undocumented SetWindowCompositionAttribute() API to enable the blur effect now, see:
How do you set the glass blend colour on Windows 10?
You are looking for the ACCENT_ENABLE_BLURBEHIND option.
For the next question of Strange Efficiency Decrease when Localizing a Global Variable into a Subthread, resently I found the question of the performance decreasement is actually caused by moving the GetDC code into a thread, where it was originally placed in a WindowProc/WndProc function, but I have no idea with the detail.
Could anyone help me?
After all, here is my code:
Quick one:
#include <stdio.h>
#include <math.h>
#include <windows.h>
#define num 4
#define width 1
double position[num][2] = {{733, 434}, {633, 384}, {733, 284}, {733, 684}};
double velocity[num][2] = {{-5, 2.5}, {5, -2.5}, {0, 2.5}, {10, -2.5}};
COLORREF color[num] = {0xffffff, 0x00ffff, 0x0000ff, 0xffff00};
COLORREF background_color = 0x000000;
double distance;
int count, i, j;
HDC hdc[num];
HPEN hpen[num];
inline double sqr(double x) {return x * x;}
DWORD WINAPI threadProc(LPVOID lpParamter) {
Sleep(1000);
while(1) {
for(i=0; i<num; ++i) {
LineTo(hdc[i], position[i][0], position[i][1]);
position[i][0] += velocity[i][0];
position[i][1] += velocity[i][1];
}
}
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR pCmdLine, int nCmdShow) {
const char *CLASS_NAME = "SUGEWND";
void *pHWND = &hInstance;
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(0, CLASS_NAME, "SUGE",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if(hwnd == NULL) return 0;
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
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;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc2=BeginPaint(hwnd, &ps);
FillRect(hdc2, &ps.rcPaint, CreateSolidBrush(background_color));
EndPaint(hwnd, &ps);
return 0;
}
case WM_CREATE: {
for(i=0; i<num; ++i) {
hdc[i] = GetDC(hwnd);
hpen[i] = CreatePen(PS_SOLID, width, color[i]);
SelectObject(hdc[i], hpen[i]);
MoveToEx(hdc[i], position[i][0], position[i][1], 0);
}
HANDLE hThread = CreateThread(NULL, 0, threadProc, NULL, 0, NULL);
CloseHandle(hThread);
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Slow one:
#include <stdio.h>
#include <math.h>
#include <windows.h>
#define num 4
#define width 1
double position[num][2] = {{733, 434}, {633, 384}, {733, 284}, {733, 684}};
double velocity[num][2] = {{-5, 2.5}, {5, -2.5}, {0, 2.5}, {10, -2.5}};
COLORREF color[num] = {0xffffff, 0x00ffff, 0x0000ff, 0xffff00};
COLORREF background_color = 0x000000;
double simulate_acc = 0.00001;
double distance;
int count, i, j;
HDC hdc[num];
HPEN hpen[num];
inline double sqr(double x) {return x * x;}
DWORD WINAPI threadProc(LPVOID lpParamter) {
HWND hwnd = *(HWND*)lpParamter;
for(i=0; i<num; ++i) {
hdc[i] = GetDC(hwnd);
hpen[i] = CreatePen(PS_SOLID, width, color[i]);
SelectObject(hdc[i], hpen[i]);
MoveToEx(hdc[i], position[i][0], position[i][1], 0);
}
Sleep(1000);
while(1) {
for(i=0; i<num; ++i) {
LineTo(hdc[i], position[i][0], position[i][1]);
position[i][0] += velocity[i][0];
position[i][1] += velocity[i][1];
}
}
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR pCmdLine, int nCmdShow) {
const char *CLASS_NAME = "SUGEWND";
void *pHWND = &hInstance;
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(0, CLASS_NAME, "SUGE",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if(hwnd == NULL) return 0;
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
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;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc2=BeginPaint(hwnd, &ps);
FillRect(hdc2, &ps.rcPaint, CreateSolidBrush(background_color));
EndPaint(hwnd, &ps);
return 0;
}
case WM_CREATE: {
HANDLE hThread = CreateThread(NULL, 0, threadProc, &hwnd, 0, NULL);
CloseHandle(hThread);
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
You are passing a pointer to a local variable to your threadProc. After exiting from WindowProc it's local variables are no more valid.
You can pass HWND by value:
case WM_CREATE: {
HANDLE hThread = CreateThread(NULL, 0, threadProc, (LPVOID)hwnd, 0, NULL);
CloseHandle(hThread);
return 0;
}
and read it's value so:
DWORD WINAPI threadProc(LPVOID lpParamter) {
HWND hwnd = (HWND)lpParamter;
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;
}
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;
}
I'm writing a very simple program, which prints color of selected pixel.
Here is my code:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define UNICODE
LRESULT CALLBACK mouse_hook_low_level(int nCode, WPARAM wParam, LPARAM lParam)
{
if(wParam == WM_MOUSEMOVE) {
//Need to get a handle to the window!
InvalidateRect(window, NULL, FALSE);
UpdateWindow(window);
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK window_process(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC dc = GetDC(NULL);
HDC hdc;
HFONT font;
PAINTSTRUCT ps;
int r, g, b;
POINT p;
RECT background_rect, color_rect;
wchar_t buffer[256];
switch(message) {
case WM_PAINT:
GetCursorPos(&p);
r = GetRValue(GetPixel(dc, p.x, p.y));
g = GetGValue(GetPixel(dc, p.x, p.y));
b = GetBValue(GetPixel(dc, p.x, p.y));
hdc = BeginPaint(window, &ps);
background_rect.left = 0;
background_rect.right = 199;
background_rect.top = 0;
background_rect.bottom = 99;
FillRect(hdc, &background_rect, (HBRUSH)(COLOR_WINDOW+1));
font = CreateFont(
14,
0,
0,
0,
FW_DONTCARE,
FALSE,
FALSE,
FALSE,
DEFAULT_CHARSET,
OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY,
VARIABLE_PITCH,
TEXT("Times New Roman")
);
SelectObject(hdc, font);
swprintf_s(buffer, 256, L"Coordinates: (%d, %d)", p.x, p.y);
TextOut(hdc, 70, 10, buffer, wcslen(buffer));
swprintf_s(buffer, 256, L"RGB: (%d, %d, %d)", r, g, b);
TextOut(hdc, 70, 40, buffer, wcslen(buffer));
color_rect.left = 10;
color_rect.right = 60;
color_rect.top = 10;
color_rect.bottom = 60;
FillRect(hdc, &color_rect, (HBRUSH)CreateSolidBrush(RGB(r, g, b)));
EndPaint(window, &ps);
break;
case WM_CLOSE:
DestroyWindow(window);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
ReleaseDC(window, hdc);
return DefWindowProc(window, message, wParam, lParam);
}
ReleaseDC(window, hdc);
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
LPCWSTR class_name = L"name";
MSG message;
WNDCLASSEX window_class;
HWND window;
HHOOK MouseHook;
window_class.cbSize = sizeof(WNDCLASSEX);
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpfnWndProc = window_process;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
window_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
window_class.lpszMenuName = NULL;
window_class.lpszClassName = class_name;
window_class.hInstance = hInstance;
window_class.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&window_class);
window = CreateWindow(
class_name,
L"Pixel color",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT,
CW_USEDEFAULT,
200,
100,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(window, SW_SHOWNORMAL);
MouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouse_hook_low_level, hInstance, 0);
while(GetMessage(&message, NULL, 0, 0)) {
TranslateMessage(&message);
DispatchMessage(&message);
}
UnhookWindowsHookEx(MouseHook);
return message.wParam;
}
The question is: how can I get a handle to the window for further window update in hook procedure at line 9? And what can you say generally about my code? I'm a student and have a little C-programming experience, could you point out my errors?
Thanks in advance.
First, try WindowFromPoint. If it fails to find a window, i.e. it's not your process window, then enumerate all top-level windows and all its child windows to find a topmost window under the mouse pointer.