opengl win32 not drawing to screen - c

I am trying to use glClearBufferfv(GL_COLOR, 0, red) to draw a red screen.
The program displays a white screen and the loading icon on the cursor is continually rotating.
I am using glew. I am also using visual studio and i think i have linked to all the necessary libraries. I employed the whole create a temporary context to use the wglCreateContextAttribsARB extension thing.
I have 2 functions for setting things up. the first one creates the window and sets up the pfd: (the editor is not formatting my code correctly so i will leave out the function names)
int pf;
HDC hDC;
HWND hWnd;
WNDCLASS wc;
PIXELFORMATDESCRIPTOR pfd;
static HINSTANCE hInstance = 0;
if (!hInstance) {
hInstance = GetModuleHandle(NULL);
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = L"OpenGL";
if (!RegisterClass(&wc)) {
MessageBox(NULL, (LPCWSTR)L"RegisterClass() failed: ", (LPCWSTR)L"Error", MB_OK);
return NULL;
}
}
hWnd = CreateWindow(TEXT("OpenGL"), TEXT("Pie"), WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, width, height, NULL, NULL, hInstance, NULL);
if (hWnd == NULL) {
MessageBox(NULL, TEXT("CreateWindow() failed: Cannot create a window."),
TEXT("Error"), MB_OK);
return NULL;
}
hDC = GetDC(hWnd);
/* there is no guarantee that the contents of the stack that become
the pfd are zeroed, therefore _make sure_ to clear these bits. */
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0) {
MessageBox(NULL, L"ChoosePixelFormat() failed: "
"Cannot find a suitable pixel format.", L"Error", MB_OK);
return 0;
}
if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
MessageBox(NULL, L"SetPixelFormat() failed: "
"Cannot set format specified.", L"Error", MB_OK);
return 0;
}
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
ReleaseDC(hWnd, hDC);
return hWnd;
The second one creates the context and starts the message loop:
HDC hDC;
HGLRC hRCt, hRC;
HWND hWnd;
MSG msg;
hWnd = CreateOpenGLWindow("minimal", 0, 0, 256, 256, PFD_TYPE_RGBA, 0);
if (hWnd == NULL)
exit(1);
hDC = GetDC(hWnd);
hRCt = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRCt);
glewExperimental = true;
glewInit();
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
WGL_CONTEXT_MINOR_VERSION_ARB, 5,
WGL_CONTEXT_FLAGS_ARB, 0,
0
};
hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
wglMakeCurrent(hDC, NULL);
wglDeleteContext(hRCt);
wglMakeCurrent(hDC, hRC);
ShowWindow(hWnd, nCmdShow);
while (GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
wglMakeCurrent(NULL, NULL);
ReleaseDC(hWnd, hDC);
wglDeleteContext(hRC);
DestroyWindow(hWnd);
return msg.wParam;
Here is my wndproc:
static PAINTSTRUCT ps;
switch (uMsg) {
case WM_PAINT:
display();
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_SIZE:
//glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;
case WM_CHAR:
switch (wParam) {
case 27: /* ESC key */
PostQuitMessage(0);
break;
}
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
and here is my display function:
glClearBufferfv(GL_COLOR, 0, red);
glFlush();
red is a global variable defined as:
GLfloat red[4] = {1, 0, 0, 1};
Any help on why it's not drawing to the screen?

Please put display() between BeginPaint and EndPaint.
Start the painting operation by calling the BeginPaint function.
This function fills in the PAINTSTRUCT structure with information on
the repaint request.
After you are done painting, call the EndPaint function. This function
clears the update region, which signals to Windows that the window has
completed painting itself.
Refer: Painting the Window
Use an example to quickly restore the problem:
HDC hdc = GetDC(hWnd);
case WM_PAINT:
{
PAINTSTRUCT ps;
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 2));
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
Debug:
HDC hdc = GetDC(hWnd);
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 2));
EndPaint(hWnd, &ps);
}
Debug:

Related

Why can't I replace BeginPaint() with ValidateRect()?

From my understanding, BeginPaint and EndPaint helps paint the screen and validates the rectangle that it paints, this also prevents WM_PAINT messages from being spammed since there will be no more invalid regions in the window.
With my understanding, I thought that theoretically speaking, if I were to use BitBlt() to paint the window in WM_CREATE, then use ValidateRect to Validate the entire client region, the code would work. However, I tried it and it doesn't, suggesting that there could be something possibly wrong with my understanding, or code. Could someone please explain to me where I went wrong?
Here is the code that I used, IDB_BITMAP1 can be replaced with any appropriate Bitmap. Do note the comment in WM_PAINT to reproduce the issue. Thanks for reading!
#include <windows.h>
#include "resource.h"
HBITMAP hBitMap = NULL;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
BITMAP infoBM;
hBitMap = LoadBitmap(GetModuleHandle(NULL), IDB_BITMAP1);
if (hBitMap == NULL)
{
MessageBoxA(NULL, "COULD NOT LOAD CAT BITMAP", "ERROR", MB_OK);
}
HDC winDC = GetDC(hwnd);
HDC hMem = CreateCompatibleDC(winDC);
GetObject(hBitMap, sizeof(infoBM), &infoBM);
HBITMAP hMemOld = SelectObject(hMem, hBitMap);
BitBlt(winDC, 0, 0, infoBM.bmWidth, infoBM.bmHeight, hMem, 0, 0, SRCCOPY);
SelectObject(hMem, hMemOld);
DeleteDC(hMem);
ReleaseDC(hwnd,winDC);
break;
}
case WM_PAINT: //<<<--------- I replaced the entire segment here with ValidateRect(hwnd,NULL);break; And the whole window doesnt show anymore, why is that so?
{
BITMAP infoBM;
PAINTSTRUCT ps;
HDC winDC = BeginPaint(hwnd, &ps);
GetObject(hBitMap, sizeof(infoBM), &infoBM);
HDC hMem = CreateCompatibleDC(winDC);
HBITMAP hOldMem = SelectObject(hMem, hBitMap);
BitBlt(winDC, 0, 0, infoBM.bmWidth, infoBM.bmHeight, hMem, 0, 0, SRCCOPY);
SelectObject(hMem, hOldMem);
DeleteObject(hMem);
EndPaint(hwnd, &ps);
break;
}
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:return DefWindowProcA(hwnd, msg, wParam, lParam);
}
return 0;
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc = { sizeof(WNDCLASSEX),0,WindowProc,0,0,hInstance,NULL,LoadCursor(NULL,IDC_ARROW),(HBRUSH)(COLOR_WINDOW+1),NULL,"WindowClass",LoadIcon(NULL,IDI_APPLICATION)};
if (!RegisterClassEx(&wc))
{
MessageBoxA(NULL, "WINDOW REGISTRATION FAILED", "ERROR", MB_OK);
}
HWND hwnd = CreateWindowEx(WS_EX_LAYERED, "WindowClass", "Title", WS_POPUP, 200, 200, 300, 300, NULL, NULL, hInstance, NULL);
if (!hwnd)
{
MessageBoxA(NULL, "WINDOW CREATION FAILED", "ERROR", MB_OK);
}
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
if (!SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 255, LWA_ALPHA))
{
MessageBoxA(NULL, "WINDOW LAYERED ATTRIBUTES FAILED", "ERROR", MB_OK);
}
MSG msg;
while (GetMessage(&msg, hwnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Typically,
You use the GetDC function to carry out drawing that must occur
instantly rather than when a WM_PAINT message is
processing.
And if you'd like, you can ValidateRect the entire client area instead of real painting when a WM_PAINT message is processing.
The following code is adapted from the thread.
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int i = 0;
switch (message)
{
case WM_PAINT:
{
if (i++ < 100)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rect;
GetClientRect(hWnd, &rect);
COLORREF clrbak = SetBkColor(hdc, RGB(255, 0, 0));
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
int x = (rect.right - rect.left) / 8;
int y = (rect.bottom - rect.top) / 8;
rect.left += x; rect.right -= x;
rect.top += y; rect.bottom -= y;
SetBkColor(hdc, RGB(0, 255, 0));
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect.left += x; rect.right -= x;
rect.top += y; rect.bottom -= y;
SetBkColor(hdc, RGB(0, 0, 255));
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect.left += x; rect.right -= x;
rect.top += y; rect.bottom -= y;
SetBkColor(hdc, RGB(0, 0, 0));
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
SetBkColor(hdc, clrbak);
EndPaint(hWnd, &ps);
}
else
{
ValidateRect(hWnd,NULL);
}
}
break;
case WM_ERASEBKGND:
return 1;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

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

How to make a fade effect in WINAPI GDI?

Below I have a code snippet showing what I have tried.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <windowsx.h>
#define WC_MAIN "MainClass"
#define WC_NUMBER "NumberClass"
LRESULT CALLBACK NumberProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void InitClasses(void)
{
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpfnWndProc = MainWndProc;
wc.lpszClassName = WC_MAIN;
RegisterClass(&wc);
wc.lpfnWndProc = NumberProc;
wc.lpszClassName = WC_NUMBER;
RegisterClass(&wc);
}
#define NUMBER_SPEED 2
#define NUMBER_TICK_SPEED 25
#define NUMBER_TICKS 55
typedef struct {
UINT ticks;
HBITMAP buffer;
} NUMBERINFO;
HWND CreateNumber(HWND parent, const char *text, int x, int y, COLORREF color)
{
NUMBERINFO *ni = malloc(sizeof(*ni));
HDC hdc = GetDC(NULL);
HFONT oldFont = NULL;
SIZE s;
GetTextExtentPoint32(hdc, text, strlen(text), &s);
SelectObject(hdc, oldFont);
BITMAPINFO bmi;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = s.cx;
bmi.bmiHeader.biHeight = s.cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32; // four 8-bit components
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = s.cx * s.cy * 4;
COLORREF *pvBits;
HBITMAP buffer = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &pvBits, NULL, 0);
HDC bufferDc = CreateCompatibleDC(hdc);
HBITMAP oldBmp = SelectObject(bufferDc, buffer);
oldFont = NULL;
SetTextAlign(bufferDc, TA_TOP | TA_LEFT);
SetBkMode(bufferDc, TRANSPARENT);
SetTextColor(bufferDc, color);
TextOut(bufferDc, 0, 0, text, strlen(text));
SelectObject(bufferDc, oldFont);
SelectObject(bufferDc, oldBmp);
DeleteDC(bufferDc);
ReleaseDC(NULL, hdc);
ni->buffer = buffer;
return CreateWindow(WC_NUMBER, text, WS_VISIBLE | WS_CHILD, x - (s.cx >> 1), y - (s.cy >> 1), s.cx, s.cy, parent, NULL, NULL, ni);
}
LRESULT CALLBACK NumberProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
NUMBERINFO *info = (NUMBERINFO*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch(msg)
{
case WM_CREATE:
info = ((CREATESTRUCT*) lParam)->lpCreateParams;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) info);
SetTimer(hWnd, 0, NUMBER_TICK_SPEED, NULL);
info->ticks = NUMBER_TICKS;
return 0;
case WM_DESTROY: return 0;
case WM_TIMER:
{
RECT rc;
GetWindowRect(hWnd, &rc);
HWND parent = GetParent(hWnd);
MapWindowPoints(HWND_DESKTOP, parent, (POINT*) &rc, 2);
rc.top -= NUMBER_SPEED;
if(!--info->ticks)
{
DestroyWindow(hWnd);
return 0;
}
SetWindowPos(hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top - NUMBER_SPEED, SWP_NOREDRAW | SWP_NOCOPYBITS);
// redraw parent call erases last shown number
RedrawWindow(GetParent(hWnd), &rc, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
return 0;
}
case WM_ERASEBKGND: return 1;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT r;
GetClientRect(hWnd, &r);
HDC bufferDc = CreateCompatibleDC(hdc);
HBITMAP oldBmp = SelectObject(bufferDc, info->buffer);
BLENDFUNCTION bfn;
bfn.BlendOp = AC_SRC_OVER;
bfn.BlendFlags = 0;
bfn.SourceConstantAlpha = info->ticks * 0xFF / NUMBER_TICKS;
bfn.AlphaFormat = 0;
//TransparentBlt(hdc, 0, 0, r.right, r.bottom, bufferDc, 0, 0, r.right, r.bottom, 0);
AlphaBlend(hdc, 0, 0, r.right, r.bottom, bufferDc, 0, 0, r.right, r.bottom, bfn);
SelectObject(bufferDc, oldBmp);
DeleteDC(bufferDc);
EndPaint(hWnd, &ps);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY: PostQuitMessage(0); return 0;
case WM_ERASEBKGND: return 1;
case WM_PAINT:
{
InvalidateRect(hWnd, NULL, FALSE);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// draw gradient (red to green)
RECT r;
GetClientRect(hWnd, &r);
GRADIENT_RECT gr;
gr.UpperLeft = 0;
gr.LowerRight = 1;
TRIVERTEX pVertex[2] = {
{ 0, 0, 0xFF00, 0x0000, 0x0000, 0xFF00 },
{ r.right, r.bottom, 0x0000, 0xFF00, 0x0000, 0xFF00 }
};
GradientFill(hdc, pVertex, 2, &gr, 2, GRADIENT_FILL_RECT_H);
EndPaint(hWnd, &ps);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int main()
{
InitClasses();
HWND mainWindow = CreateWindow(WC_MAIN, "Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);
ShowWindow(mainWindow, 1);
UpdateWindow(mainWindow);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// adding a number at mouse position if pressed (testing)
if(msg.message == WM_LBUTTONDOWN)
{
RECT r;
GetClientRect(mainWindow, &r);
int x = GET_X_LPARAM(msg.lParam);
int y = GET_Y_LPARAM(msg.lParam);
CreateNumber(mainWindow, "123", x, y, 0xFFFF00);
}
}
return 0;
}
This draws some text with any color and every time a timer ticks, the text becomes more faded (more transparent), but the black background of the bitmap the text was drawn on, is drawn, but I want no background to be present, just the text.
I would assume I need a combination of TransparentBlt and AlphaBlend.
How would I go on to solve this?
The solution was quite simple. It was to use AC_SRC_ALPHA for the AlphaFormat member of BLENDFUNCTION and in order for that to work, set the alpha values of the HBITMAP, the buffer.
After the buffer (the one inside of NUMBERINFO) is created (in CreateNumber; check question code for reference), one must loop over all the colors and set the alpha value to 255 where needed.
for(int i = s.cx * s.cy; i--; pvBits++)
{
if(*pvBits)
*pvBits |= 0xFF000000; // make non black pixels opaque
}
And setting the flag in WM_PAINT: bfn.AlphaFormat = AC_SRC_ALPHA;

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

MSDN (Owner Drawn) Listbox control freeze after scrolling

I'm working on an Owner-Drawn Listbox Control that i managed to create and populate without errors.
Here's my problem :
When i scroll it, the listbox and its parent window becomes unresponsive after scrolling for a few seconds.(with PgDown)
Note that :
There's a lot of items in it (more than 4k)
The messages are still being processed, i can monitor them on the console and they are being sent and received. Only difference is, WM_DRAWITEM is no longer sent...
The items of the listbox are added via LB_ADDSTRING
What i tried :
Using the PeekMessage function instead of the GetMessage
-> Program crashes after the list is filled
Redrawing the windows after the problem occurs (via a WM_LDOUBLECLICK event for example)
-> No effets
Code snippets :
Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HBRUSH Brush;
HBRUSH BLANK_BRUSH;
HBRUSH BLUE_BRUSH;
Brush = CreateSolidBrush(RGB(163, 255, 249));
BLANK_BRUSH = CreateSolidBrush(RGB(255,255, 255));
BLUE_BRUSH = CreateSolidBrush(RGB(0,0, 255));
int tabs[13]={140,256,261,287,318,353,422,460,500,530,550,570,610};
switch(msg)
{
HDC hdc ;
PAINTSTRUCT ps ;
PMEASUREITEMSTRUCT pmis;
LPDRAWITEMSTRUCT Item;
RECT rect ;
rect.top=-50;
rect.bottom=0;
RECT rect2 ;
rect.top=10;
case WM_MEASUREITEM:
pmis = (PMEASUREITEMSTRUCT) lParam;
pmis->itemHeight = 17;
return TRUE;
break;
case WM_DRAWITEM:
Item = (LPDRAWITEMSTRUCT)lParam;
if (Item->itemState & ODS_FOCUS)
{
SetTextColor(Item->hDC, RGB(255,255,255));
SetBkColor(Item->hDC, RGB(0, 0, 255));
FillRect(Item->hDC, &Item->rcItem, (HBRUSH)BLUE_BRUSH);
}
else
{
SetTextColor(Item->hDC, RGB(0,0,0));
SetBkColor(Item->hDC, RGB(255, 255, 255));
FillRect(Item->hDC, &Item->rcItem, (HBRUSH)BLANK_BRUSH);
}
int len = SendMessage(Item->hwndItem , LB_GETTEXTLEN, (WPARAM)Item->itemID, 0);
if (len > 0)
{
LPCTSTR lpBuff = malloc((len+1)*sizeof(TCHAR));
len = SendMessage(Item->hwndItem , LB_GETTEXT, (WPARAM)Item->itemID, (LPARAM)lpBuff);
if (len > 0) {
TabbedTextOut(Item->hDC,Item->rcItem.left, Item->rcItem.top,(LPARAM)lpBuff,len,13,&tabs,140);
}
}
return TRUE;
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect(hwnd, &rect);
SetBkColor(hdc, RGB(230,50,2));
SetBkMode(hdc,TRANSPARENT);
FillRect(hdc,&ps.rcPaint,Brush);
DrawText(hdc, TEXT("Liste des messages décodés: "), -1, &rect, DT_CENTER );
DrawText(hdc, TEXT("Numéro d'engin (4xxxy): "), -1, &rect, DT_LEFT );
EndPaint (hwnd, &ps);
return 0 ;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_ERASEBKGND:
return TRUE;
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Message Loop
BOOL bRet;
while (1)
{
bRet = GetMessage(&Msg, NULL, 0, 0);
if (bRet > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
else if (bRet == 0){
break;
}
else
{
printf("error\n");
return -1;
}
}
return Msg.wParam;
Window creation
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,g_szClassName,"List of messages",WS_OVERLAPPEDWINDOW,0, 0, 1500, 1000,NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
if(hwnd == NULL)
{
return 0;
}
hwnd2 = CreateWindowEx(0,"LISTBOX" ,"Data",WS_CHILD |WS_HSCROLL |WS_VSCROLL |WS_BORDER|WS_THICKFRAME | LBS_USETABSTOPS | LBS_OWNERDRAWFIXED | LBS_NOTIFY | LBS_HASSTRINGS,15,70,1450,450,hwnd,(HMENU) NULL,hInstance,NULL);
It looks like there's a timer somewhere, and if a keyboard touch stays too long down, it somehow messes everything up...
Has someone encountered a problem like this before or could help me understand what is going on ?
You have a significant GDI resource leak in your code.
At the top of your WndProc function you're creating three brushes, and you never delete them. These brushes are created every time your window processes a message.
You should only create the brushes when you actually need them for painting, and call DeleteObject to release them when you're done with them.

Resources