How to update the text inside a window? - c

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;
}

Related

Why does BitBlt() Zoom in when copying the exact same pixels from the same bitmap onto itself?

I'm trying to make a window that copies the desktop, and mess around with the pixels on it. I do this by using BitBlt from the Desktop Handle to my Window handle. This works as expected - a window is created which looks exactly like the desktop. However, when I use BitBlt() again to move a segment of pixels from my Window to another area of my Window, the pixels are zoomed in. Why does this happen and how do I fix it?
Here is the code, I have commented on the section where the issue seems to be coming from:
#include <windows.h>
int myWidth, myHeight;
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
HDC DhWnd = GetDC(HWND_DESKTOP);
HDC MhWnd = GetDC(hwnd);
BitBlt(MhWnd, 0, 0, myWidth, myHeight, DhWnd, 0, 0, SRCCOPY);
ShowWindow(hwnd, SW_SHOW);
BitBlt(MhWnd, 300, 0, 100, 500, MhWnd, 300, 0, SRCCOPY);
/*^^^^ The above segment zooms in the pixels despite copy pasting the EXACT
SAME coordinates of the bitmap onto itself. ^^^^*/
ReleaseDC(hwnd, DhWnd);
ReleaseDC(hwnd, MhWnd);
return 0;
}
case WM_PAINT:
ValidateRect(hwnd, NULL);
return 0;
case WM_CLOSE:
case WM_DESTROY:
DestroyWindow(hwnd);
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
RECT Drc;
MSG msg;
HWND DhWnd = GetDesktopWindow();
HWND MyhWnd;
GetWindowRect(DhWnd, &Drc);
myWidth = Drc.right - Drc.left;
myHeight = Drc.bottom - Drc.top;
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyWindow";
if (!RegisterClass(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
MyhWnd = CreateWindow("MyWindow", NULL, WS_POPUP, 0, 0, myWidth, myHeight, NULL, NULL, hInstance, NULL);
if (MyhWnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

Background image fails to get set for a window in WinApi

I am learning to how to set a background image for a window in C.
Here is my code:
#include <stdio.h>
#include <windows.h>
char* window_name = "Window";
char* window_title = "Window Title";
char* background_name = "test.bmp";
int window_width = 600;
int window_height = 400;
HBITMAP hbackground_image;
WNDCLASSEX wc;
HWND hwnd, hbackground;
MSG msg;
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
hbackground = CreateWindow("STATIC", "background", SS_BITMAP | WS_CHILD | WS_VISIBLE, 0, 0, 300, 300, hwnd,
NULL, NULL, NULL);
hbackground_image = (HBITMAP)LoadImage(NULL, background_name, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
SendMessage(hbackground, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbackground_image);
break;
default:
return DefWindowProc(hwnd, msg, wp, lp);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
wc.lpszClassName = window_name;
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Windows registration failure", NULL, MB_RETRYCANCEL);
return 1;
}
hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, window_name, window_title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, window_width, window_height, NULL, NULL, hInstance, NULL);
// hwnd = CreateWindow("test", "test title", WS_OVERLAPPED | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL); // This fails
if (!hwnd) // If fails
{
MessageBox(NULL, "Window creation failed :(", NULL, MB_RETRYCANCEL);
return 2;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
However, the background image doesn't get set even though there is a bitmap in the same folder as the .exe. I also tried different bitmaps from the internet, and one I made in paint. Any help would be appreciated.
This line is wrong:
wc.lpfnWndProc = DefWindowProc;
You are not seeing your background image because you are not using your WindowProcedure() with the window class, and thus it is never called to load/display the bitmap.
That line needs to be this instead:
wc.lpfnWndProc = WindowProcedure;
Also, when processing WM_CREATE, you are not return'ing any value, so the result is indeterminate, which is undefined behavior. You need to return 0; for that message:
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
...
return 0;
...
}
return DefWindowProc(hwnd, msg, wp, lp);
}

C winapi hwnd returning null

I have tried everything to find the problem, but down below is my code and hwnd returns NULL when I run the program. What might be the reasons? The code seems fine. The program was working fine for a long while until 15 mins ago. I cut this part of the source code and ran it again but it still return NULL. This is that part that I cut.
#include <windows.h>
#define IDI_MYICON 103
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
//font
/*hFont = CreateFont(40,0,0,0,700,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("a"));
hFontIpAdres = CreateFont(25,0,0,0,700,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("a"));
hFontKurbanSecimi = CreateFont(30,0,0,0,700,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("a"));
*/
WNDCLASSEX wc;
HWND hwnd;
MSG msg;
char *windowClassName = "class1";
printf("%s\n", windowClassName);
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;//MAKEINTRESOURCE(IDR_MYMENU);
wc.lpszClassName = windowClassName;
wc.hIconSm = NULL;//(HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON), IMAGE_ICON, 16, 16, 0);
if(!RegisterClassEx(&wc))
{
printf("window registration failed\n");
}
printf("%s\n", windowClassName);
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE, windowClassName,"TTr",WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL
);
if(hwnd == NULL){
printf("could not create window hwnd %d\n", GetLastError());
}
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
while(GetMessage(&msg, NULL, 0, 0) > 0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Your WndProc() function doesn't return anything. CreateWindowEx() will actually call the window proc with some creation-based messages.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}

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;
}

ANSI C & WinAPI: how to get a handle to the window from hook procedure?

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.

Resources