Related
I am trying to load some bitmaps when starting up the application. I am trying to load them in WM_CREATE but only the last bitmap i load will stay loaded.
I can load the pictures in WM_PAINT but i have been told it's better to load them in WM_CREATE.
//before switch statement
static HBITMAP bitmap1, bitmap2;
case WM_CREATE: {
HINSTANCE hInstance = GetModuleHandle(NULL);
bitmap1 = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
bitmap2 = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(IDB_BITMAP2),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
if (!bitmap1 || !bitmap2) MessageBox(NULL, _T("Error while loading images"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
case WM_PAINT:{
//Draw bitmap...
}
I expected that both bitmaps got loaded as they do when loaded inside WM_PAINT
EDIT:
The problem weren't were i thought. The problem is it draws behind the filled area i had made. I still don't know how to fix.
//Draw bitmap function
bool DrawBitmap(HBITMAP hBitmap, int posX, int posY, int sizeX, int sizeY)
{
BITMAP bmp;
HWND hWnd = FindWindow(windowClassName, NULL);
if (!hWnd) return false;
HDC hdc = GetDC(hWnd);
if (!hdc) return false;
HDC hBitmapDC = CreateCompatibleDC(hdc);
if (!hBitmapDC) return false;
GetObject(hBitmap, sizeof(bmp), &bmp);
SelectObject(hBitmapDC, hBitmap);
BitBlt(hdc, posX, posY, sizeX, sizeY, hBitmapDC, 0, 0, SRCCOPY);
DeleteObject(hBitmap);
ReleaseDC(hWnd, hBitmapDC);
ReleaseDC(hWnd, hdc);
return true;
}
//Before switch
RECT recRect;
STATIC HBITMAP bitmap1;
//case WM_CREATE:
case WM_CREATE: {
HINSTANCE hInstance = GetModuleHandle(NULL);
bitmap1 = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
if (!bitmap) MessageBox(NULL, _T("Error while loading images"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
return 0;
break;
//case WM_PAINT
case WM_PAINT:
DefWindowProc(hwnd, msg, wParam, lParam);
hdc = GetWindowDC(hwnd);
recRect = { -1, -1, 50 + 1, 30 + 1 };
FillRect(hdc, &recRect, (HBRUSH)CreateSolidBrush(RGB(30, 30, 30)));
if (DrawBitmap(bitmap1, 5, 5, 10, 10) == false) MessageBox(NULL, _T("Error while drawing images"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
return DefWindowProc(hwnd, msg, wParam, lParam);
return 0;
break;
The problem does not occur when i declare the bitmap in WM_PAINT
GetWindowDC returns the dc for the whole window, including the non-client area. You usually need GetDC instead.
Always use BeginPaint/EndPaint when responding to WM_PAINT and return 0.
CreateSolidBrush is a GDI resource leak. After creating brush or other GDI objects, you have to destroy those objects, otherwise you have resource leak, the program will crash after 10,000 GDI leaks.
In your draw function you have DeleteObject(hBitmap) This will destroy the bitmap immediately. But you probably want to keep the bitmap handle and destroy it only after the program is finished.
Suggestion:
bool DrawBitmap(HDC hdc, HBITMAP hBitmap, int posX, int posY, int sizeX, int sizeY)
{
HDC memdc = CreateCompatibleDC(hdc);
HGDIOBJ oldbmp = SelectObject(memdc, hBitmap);
BitBlt(hdc, posX, posY, sizeX, sizeY, memdc, 0, 0, SRCCOPY);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
return true;
}
...
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HBRUSH hbrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &ps.rcPaint, hbrush);
DeleteObject(hbrush);
BITMAP bm1;
GetObject(bitmap1, sizeof(bm1), &bm1);
DrawBitmap(hdc, bitmap1, 0, 0, bm1.bmWidth, bm1.bmHeight);
int x = bm1.bmWidth;
int y = bm1.bmHeight;
BITMAP bm2;
GetObject(bitmap2, sizeof(bm2), &bm2);
DrawBitmap(hdc, bitmap2, x, y, bm2.bmWidth, bm2.bmHeight);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
DeleteObject(bitmap1);
DeleteObject(bitmap2);
PostQuitMessage(0);
return 0;
I'm need to draw border on top another application's window (the main purpose is to highlight window user chooses from running applications list). I'm trying to draw border on top of native window border, but the border isn't drawn. Here is the code:
HPEN framePen = ::CreatePen(PS_SOLID, 5, RGB(255, 0, 0));
HWND handle = FindWindow(L"ConsoleWindowClass", L"C:\\WINDOWS\\system32\\cmd.exe");
WINDOWPLACEMENT winPlacement;
GetWindowPlacement(handle, &winPlacement);
if (winPlacement.showCmd == SW_SHOWMINIMIZED)
{
ShowWindow(handle, SW_RESTORE);
}
SetWindowPos(handle, HWND_TOP, 0, 0, 0, 0, SWP_ASYNCWINDOWPOS | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(handle);
PAINTSTRUCT ps;
RECT rect = {};
::GetClientRect(handle, &rect);
HDC hdc = ::BeginPaint(handle, &ps);
::SelectObject(hdc, framePen);
::Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
::EndPaint(handle, &ps);
In this example used handle of cmd window, but in fact it doesn't matter.
Could you please tell why border isn't drawn and how to draw it?
Thanks.
You can't draw directly on another window, because the system may refresh the window at any time, overwriting your drawing.
To make your drawing persistent, create a layered window, positioned on top of the other window.
Create the window with WS_EX_LAYERED flag.
Pass a color key to SetLayeredWindowAttributes().
In your WM_PAINT handler, draw the inside of the rectangle with the color key (by using it for the brush). Everything you draw with the color key will become transparent. Draw the border of the rectangle with the desired color (by using it for the pen).
Here is a minimal example to get you started. The frame can be moved around by drag-n-drop.
Note there is no error handling to keep the sample code concise. You should check the return value of each Windows API call.
#include <windows.h>
const COLORREF MY_COLOR_KEY = RGB( 255, 0, 255 );
int APIENTRY wWinMain(
HINSTANCE hInstance, HINSTANCE /*hPrevInst*/, LPWSTR /*lpCmdLine*/, int nCmdShow )
{
WNDCLASSW wc{ sizeof( wc ) };
wc.hInstance = hInstance;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hCursor = LoadCursor( nullptr, IDC_ARROW );
wc.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_BTNFACE + 1 );
wc.lpszClassName = L"MyTransparentFrame";
wc.lpfnWndProc = []( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) -> LRESULT
{
switch( msg )
{
case WM_PAINT:
{
PAINTSTRUCT ps{};
HDC hdc = BeginPaint( hwnd, &ps );
RECT rc{}; GetClientRect( hwnd, &rc );
HPEN hPen = CreatePen( PS_SOLID, 20, GetSysColor( COLOR_HIGHLIGHT ) );
HBRUSH hBrush = CreateSolidBrush( MY_COLOR_KEY );
HGDIOBJ hOldPen = SelectObject( hdc, hPen );
HGDIOBJ hOldBrush = SelectObject( hdc, hBrush );
Rectangle( hdc, rc.left, rc.top, rc.right, rc.bottom );
if( hOldPen )
SelectObject( hdc, hOldPen );
if( hOldBrush )
SelectObject( hdc, hOldBrush );
if( hPen )
DeleteObject( hPen );
if( hBrush )
DeleteObject( hBrush );
EndPaint( hwnd, &ps );
}
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
case WM_NCHITTEST:
return HTCAPTION; // to be able to drag the window around
break;
default:
return DefWindowProcW( hwnd, msg, wp, lp );
}
return 0;
};
RegisterClassW( &wc );
HWND hwnd = CreateWindowExW( WS_EX_LAYERED, wc.lpszClassName, L"", WS_POPUP,
200, 200, 800, 600, nullptr, nullptr, hInstance, nullptr );
SetLayeredWindowAttributes( hwnd, MY_COLOR_KEY, 255, LWA_COLORKEY );
ShowWindow( hwnd, nCmdShow );
MSG msg;
while( GetMessage( &msg, nullptr, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return (int) msg.wParam;
}
Finally I managed to solve the problem with the following code:
const COLORREF MY_COLOR_KEY = RGB(255, 128, 0);
HWND cmdHanlde = NULL;
constexpr unsigned int timerIdWindowUpdate = 1;
constexpr unsigned int timerIdFrameColor = 2;
bool tick = false;
bool minimized = false;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpszClassName = L"MyTransparentFrame";
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpfnWndProc = [](HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) -> LRESULT
{
switch (msg)
{
case WM_PAINT:
{
PAINTSTRUCT ps{};
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc{}; GetClientRect(hwnd, &rc);
HPEN hPen = CreatePen(PS_SOLID, 5, tick ? RGB(255, 128, 1) : RGB(255, 201, 14));
HBRUSH hBrush = CreateSolidBrush(MY_COLOR_KEY);
HGDIOBJ hOldPen = SelectObject(hdc, hPen);
HGDIOBJ hOldBrush = SelectObject(hdc, hBrush);
Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
if (hOldPen)
SelectObject(hdc, hOldPen);
if (hOldBrush)
SelectObject(hdc, hOldBrush);
if (hPen)
DeleteObject(hPen);
if (hBrush)
DeleteObject(hBrush);
EndPaint(hwnd, &ps);
}
break;
case WM_TIMER:
{
if (wp == timerIdWindowUpdate)
{
WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT), };
if (::GetWindowPlacement(cmdHanlde, &windowPlacement))
{
if (windowPlacement.showCmd == SW_SHOWMINIMIZED
|| !IsWindowVisible(cmdHanlde))
{
ShowWindow(hwnd, SW_HIDE);
minimized = true;
}
else
{
RECT rect = {};
DwmGetWindowAttribute(cmdHanlde, DWMWA_EXTENDED_FRAME_BOUNDS, &rect, sizeof(rect));
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfoW(MonitorFromWindow(cmdHanlde, MONITOR_DEFAULTTONEAREST), &monInfo);
if (cmdHanlde != NULL && ::IsZoomed(cmdHanlde))
{
rect.left = monInfo.rcWork.left;
rect.top = monInfo.rcWork.top;
rect.bottom = monInfo.rcWork.bottom > rect.bottom ? rect.bottom : monInfo.rcWork.bottom;
rect.right = monInfo.rcWork.right > rect.right ? rect.right : monInfo.rcWork.right;
}
if (minimized)
{
::SetWindowPos(hwnd, cmdHanlde, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
minimized = false;
}
else
{
::SetWindowPos(cmdHanlde, hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
::SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_SHOWWINDOW);
}
}
}
}
else if (wp == timerIdFrameColor)
{
tick = !tick;
::RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, msg, wp, lp);
}
return 0;
};
RegisterClassEx(&wc);
HWND hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_LAYERED | WS_EX_TRANSPARENT, wc.lpszClassName, L"", WS_POPUP | WS_VISIBLE | WS_DISABLED,
0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
::SetTimer(hwnd, timerIdWindowUpdate, 50, NULL);
::SetTimer(hwnd, timerIdFrameColor, 500, NULL);
SetLayeredWindowAttributes(hwnd, MY_COLOR_KEY, 255, LWA_COLORKEY);
ShowWindow(hwnd, SW_SHOW);
cmdHanlde = FindWindow(L"ConsoleWindowClass", L"C:\\WINDOWS\\system32\\cmd.exe");
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
May be it is not the best solution, but it works for me. Could you please take a look on it and tell if there something to improve?
How can I stop displaying the bitmap in my Win32 Project. I have a method that I'm calling in WM_PAINT called LoadBitmap. It's code looks like this:
bool LoadBitmap(LPTSTR szfilename, HDC winhdc, int x, int y) {
HBITMAP bitmap;
bitmap = (HBITMAP)LoadImage(NULL, szfilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (bitmap == NULL) {
::MessageBox(NULL, _T("Bitmap failed"), NULL, MB_OK);
return false;
}
HDC hdc;
hdc = ::CreateCompatibleDC(winhdc);
if (hdc == NULL)
{
::MessageBox(NULL, _T("HDC FAILED"), NULL, MB_OK);
return false;
}
BITMAP qbitmap;
int ireturn = GetObject(reinterpret_cast<HGDIOBJ>(bitmap), sizeof(BITMAP), reinterpret_cast<LPVOID>(&qbitmap));
if (!ireturn) {
::MessageBox(NULL, _T("RETURN FAILED"), NULL, MB_OK);
return false;
}
HBITMAP holdbitmap = (HBITMAP)::SelectObject(hdc, bitmap);
if (holdbitmap == NULL) {
::MessageBox(NULL, _T("HOLD FAILED"), NULL, MB_OK);
return false;
}
BOOL qRetBlit = ::BitBlt(winhdc, x, y, qbitmap.bmWidth, qbitmap.bmHeight, hdc, 0, 0, SRCCOPY);
if (!qRetBlit)
{
::MessageBox(NULL, _T("BLIT FAILED"), NULL, MB_OK);
return false;
}
::SelectObject(hdc, holdbitmap);
::DeleteDC(hdc);
::DeleteObject(bitmap);
return true;
}
NOTE x and y change continuously.
When x and y change however, the previous instance of them stays behind.
How can I stop displaying a bitmap once it has been painted in a new position?
If there is background brush then the old bitmap is erased with each paint call. If there is no background then erase it manually for example with FillRect Here is example with double buffering, assumes there is no background brush.
case WM_PAINT:
{
...
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);
//double-buffer ready, do custom paintings here:
FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
LoadBitmap(filename, memdc, x, y);
//BitBlt to hdc
BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(hdc, oldbitmap);
DeleteObject(membitmap);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
Edit *************
It will be faster to load the bitmap file only once. For each paint request, we need only to draw the bitmap, instead of LoadImage every time + draw.
You can declare HBITMAP handles as static values in window's procedure. Set it up once in WM_CREATE, and clean it up in WM_NCDESTROY. Now we can use them anywhere in side window procedure:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
static HBITMAP hbitmap_background = NULL;
static HBITMAP hbitmap_sprite = NULL;
switch (msg)
{
case WM_CREATE:
{
hbitmap_background = (HBITMAP)LoadImage(NULL,
L"background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hbitmap_background)
OutputDebugStringW(L"!hbitmap_background\n");
hbitmap_sprite = (HBITMAP)LoadImage(NULL,
L"sprite.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hbitmap_sprite)
OutputDebugStringW(L"!hbitmap_sprite\n");
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
//setup double-buffering:
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);
//double-buffer ready, do custom paintings here:
FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
DrawBitmap(hbitmap_background, memdc, 0, 0);
DrawBitmap(hbitmap_sprite, memdc, 0, 0);
//BitBlt to hdc
BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(hdc, oldbitmap);
DeleteObject(membitmap);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCDESTROY:
{
//cleapup bitmap handles
if (hbitmap_background)
DeleteObject(hbitmap_background);
if (hbitmap_sprite)
DeleteObject(hbitmap_sprite);
}
}
return DefWindowProc(hwnd, msg, wp, lp);
}
We can change DrawBitmap so it only needs HBITMAP handle
void DrawBitmap(HBITMAP hbitmap, HDC hdc, int x, int y)
{
if (!hbitmap)
{
OutputDebugStringW(L"error\n");
return;
}
BITMAP bm;
GetObject(hbitmap, sizeof(BITMAP), &bm);
HDC memdc = CreateCompatibleDC(hdc);
HGDIOBJ oldbitmap = SelectObject(memdc, hbitmap);
BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);
SelectObject(memdc, oldbitmap);
DeleteDC(memdc);
}
Note, in this example I assume background.bmp is very large, and sprite.bmp is very small. If it is painted the other way around then background will hide the sprite.
I am trying to paint(draw) text on the client area on a window in response to some event(not in the WM_PAINT message), so how can I preserve the state of the client area between calls to WM_PAINT? I understand that every time there is a WM_PAINT message(or window refreshes) the window gets redrawn and everything out side WM_PAINT doesn't matter anymore. I think I will be able to communicate better with code, so here is what I have now.
HDC mdc;
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance,
LPSTR lpszArgument, int nFunsterStil)
{
LoadBitmap(...); // for skinning the app.
stuff..
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
BITMAP bm;
HDC dcSkin = CreateCompatibleDC(hdc);
GetObject(hSkinBmp, sizeof(bm), &bm);
SelectObject(dcSkin, hSkinBmp);
BitBlt(dcSkin, 0, 0, wWidth, wHeight, mdc, 0, 0, SRCCOPY);
BitBlt(hdc, 0, 0, wWidth, wHeight, dcSkin, 0, 0, SRCCOPY);
DeleteDC(dcSkin);
EndPaint(hwnd, &ps);
break;
case WM_LBUTTONDOWN;
HDC hdc = GetDC( hwnd );
mdc = CreateCompatibleDC( hdc );
LPRECT rect;
GetClientRect( hwnd, rect);
SelectObject( mdc, CreateCompatibleBitmap( hdc, rect->right, rect->bottom ) );
BitBlt( mdc,0,0,rect->right,rect->bottom,hdc,0,0,SRCCOPY );
HFONT hfont = CreateFont( 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, DEFAULT_PITCH | FF_SWISS , 0 );
HFONT hOldFont = (HFONT)SelectObject( mdc, hfont );
SetTextColor( mdc, RGB(255,0,0) );
SetBkColor( mdc, RGB(255,255,0) );
TextOut( mdc, 50, 150, logintext.c_str(), strlen( logintext.c_str() ) );
SelectObject( mdc, hOldFont );
ReleaseDC( hwnd, hdc);
InvalidateRect( hwnd, 0, TRUE );
break;
}
As you can see, I have to paint the client area of the window with a bmp, then when mouse button down message comes, I have to output some text on top of the skinned client area.
What I am doing is saving the memory dc created in the WM_LBUTTONDOWN message and trying to paint the window dc first with the dc for skin then the dc for text(memory dc created in WM_LBUTTONDOWN).
The skin bitmap show as it is supposed to, but the Text doesn't.
How do I achieve this ?
If I understand you correctly you want to draw things outside of WM_PAINT and have them persist. Unfortunatly that's not how windows works.
You need to be able to redraw everything in your WM_PAINT handler as the contents of the window can be destroyed at any moment and redrawn, so you have to structure your program to be able to do this. Instead of drawing anything outside of the WM_PAINT hander instead set some flags or other state telling the program what should be on the screen and then invalidate the area of the screen so that a WM_PAINT will be issued to draw that area.
One alternative which might be easier for you is to draw everything to an offscreen bitmap whenever it needs updating, and have the WM_PAINT function just draw that bitmap on the screen so it's always up to date.
I have created a window whose handle is handle_parent. Then I created a child window as following:
hwnd_child = CreateWindow(child_class_name, _T(""),
WS_CHILDWINDOW, 0, 0, 0, 0, hwnd_parent, (HMENU)0, ghinst, NULL);
ShowWindow(win->hwndSplitterBar, SW_SHOW);
UpdateWindow(win->hwndSplitterBar);
I would like to set the color of child window "child". If I do nothing, the color is grey by default.
How could I set its color? I would like to keep the color as black permanent, do change in anycase.
Create a brush of the desired color and then pass it in the hbrBackground member of the WNDCLASS struct when calling RegisterClass to register your window class.
The system will delete this brush automatically when you call UnregisterClass so once you have passed this brush to RegisterClass you can forget all about it and must not attempt to delete it yourself.
This example may be helpful:
//Setting the background color of a window during window class registration
WNDCLASS wc = { 0 } ( or WNDCLASS wc; memset(&wc, 0, sizeof(wc)); )
...
...
...
wc.hbrBackground = CreateSolidBrush(0x000000ff); // a red window class background
...
...
RegisterClass(&wc);
// Setting the background during WM_ERASEBKGND
LRESULT CALLBACK YourWndProc(HWND hwnd, UINT umsg, WPARAM,LPARAM)
{
switch( umsg )
{
case WM_ERASEBKGND:
{
RECT rc;
GetClientRect(hwnd, &rc);
SetBkColor((HDC)wParam, 0x000000ff); // red
ExtTextOut((HDC)wParam, 0, 0, ETO_OPAQUE, &rc, 0, 0, 0);
return 1;
}
// or in WM_PAINT
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
HDC hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetBkColor(hdc, 0x000000ff); // red
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, 0, 0, 0);
EndPaint(hwnd, &ps);
break;
}
...
...
...
default:
return DefWindowProc(...);
}
return 0;
}
Use CreateSolidBrush()::
WNDCLASS wc = { 0 } ( or WNDCLASS wc; memset(&wc, 0, sizeof(wc)); )
...
wc.hbrBackground = CreateSolidBrush(RGB(255,0,0)) or CreateSolidBrush(0x000000ff); // a red window class background