In C++ Win32, how do I prevent the window from flickering? - c++

For my own amusement, I have been creating a 3D graphics program in C++ with Win32 that does not use any floating point numbers. For some reason, the window flickers sometimes when window is updated. I believe this to be caused by the window updating after what was previously shown in the window was erased and before what will be drawn next is drawn. I have found several web pages and questions with answers about what appears to be the same issue, except the solutions do not work.
Some examples{
Do not use CS_HREDRAW|CS_VREDRAW. (No noticeable effect)
Return 1 for the window message 'WM_ERASEBKGND'. (I need to erase what was previously drawn. This stops the flicker by preventing it from erasing.)
Instead of erasing, draw a rectangle in the case of WM_PAINT. (This made it worse)
}
How do I actually prevent window flicker?
// compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
boolean Draw;
//Trigonometry tables in increments of 1/256 of a rotation and multiplied by 65536
const int Total=3,Sine[256]={0,1608,3216,4821,6424,8022,9616,11204,12785,14359,15924,17479,19024,20557,22078,23586,25080,26558,28020,29466,30893,32303,33692,35062,36410,37736,39040,40320,41576,42806,44011,45190,46341,47464,48559,49624,50660,51665,52639,53581,54491,55368,56212,57022,57798,58538,59244,59914,60547,61145,61705,62228,62714,63162,63572,63944,64277,64571,64827,65043,65220,65358,65457,65516,65536,65516,65457,65358,65220,65043,64827,64571,64277,63944,63572,63132,62714,62228,61705,61145,60547,59914,59244,58538,57798,57022,56212,55368,54491,53581,52639,51665,50660,49624,48559,47464,46341,45190,44011,42806,41576,40320,39040,37736,36410,35062,33692,32303,30893,29466,28020,26558,25080,23586,22078,20557,19024,17479,15924,14359,12785,11204,9616,8022,6424,4821,3216,1608,0,-1608,-3216,-4821,-6424,-8022,-9616,-11204,-12785,-14359,-15924,-17479,-19024,-20557,-22078,-23586,-25080,-26558,-28020,-29466,-30893,-32303,-33692,-35062,-36410,-37736,-39040,-40320,-41576,-42806,-44011,-45190,-46341,-47464,-48559,-49624,-50660,-51665,-52639,-53581,-54491,-55368,-56212,-57022,-57798,-58538,-59244,-59914,-60547,-61145,-61705,-62228,-62714,-63162,-63572,-63944,-64277,-64571,-64827,-65043,-65220,-65358,-65457,-65516,-65536,-65516,-65457,-65358,-65220,-65043,-64827,-64571,-64277,-63944,-63572,-63162,-62714,-62228,-61705,-61145,-60547,-59914,-59244,-58538,-57798,-57022,-56212,-55368,-54491,-53581,-52639,-51665,-50660,-49624,-48559,-47464,-46341,-45190,-44011,-42806,-41576,-40320,-39040,-37736,-36410,-35062,-33692,-32303,-30893,-29466,-28020,-26558,-25080,-23586,-22078,-20557,-19024,-17479,-15924,-14359,-12785,-11204,-9616,-8022,-6424,-4821,-3216,-1608},Cosine[256]={65536,65516,65457,65358,65220,65043,64827,64571,64277,63944,63572,63132,62714,62228,61705,61145,60547,59914,59244,58538,57798,57022,56212,55368,54491,53581,52639,51665,50660,49624,48559,47464,46341,45190,44011,42806,41576,40320,39040,37736,36410,35062,33692,32303,30893,29466,28020,26558,25080,23586,22078,20557,19024,17479,15924,14359,12785,11204,9616,8022,6424,4821,3216,1608,0,-1608,-3216,-4821,-6424,-8022,-9616,-11204,-12785,-14359,-15924,-17479,-19024,-20557,-22078,-23586,-25080,-26558,-28020,-29466,-30893,-32303,-33692,-35062,-36410,-37736,-39040,-40320,-41576,-42806,-44011,-45190,-46341,-47464,-48559,-49624,-50660,-51665,-52639,-53581,-54491,-55368,-56212,-57022,-57798,-58538,-59244,-59914,-60547,-61145,-61705,-62228,-62714,-63162,-63572,-63944,-64277,-64571,-64827,-65043,-65220,-65358,-65457,-65516,-65536,-65516,-65457,-65358,-65220,-65043,-64827,-64571,-64277,-63944,-63572,-63162,-62714,-62228,-61705,-61145,-60547,-59914,-59244,-58538,-57798,-57022,-56212,-55368,-54491,-53581,-52639,-51665,-50660,-49624,-48559,-47464,-46341,-45190,-44011,-42806,-41576,-40320,-39040,-37736,-36410,-35062,-33692,-32303,-30893,-29466,-28020,-26558,-25080,-23586,-22078,-20557,-19024,-17479,-15924,-14359,-12785,-11204,-9616,-8022,-6424,-4821,-3216,-1608,0,1608,3216,4821,6424,8022,9616,11204,12785,14359,15924,17479,19024,20557,22078,23586,25080,26558,28020,29466,30893,32303,33692,35062,36410,37736,39040,40320,41576,42806,44011,45190,46341,47464,48559,49624,50660,51665,52639,53581,54491,55368,56212,57022,57798,58538,59244,59914,60547,61145,61705,62228,62714,63162,63572,63944,64277,64571,64827,65043,65220,65358,65457,65516};
int HorizontalAxis,VerticalAxis,SemiHorizontalAxis,SemiVerticalAxis,Speed=1,Phi=64,Theta,VelX,VelY,VelZ,SinTheta,CosTheta=65536,SinPhi,CosPhi=-65536,RegX,RegY,RegZ,Quadrilaterals[3][6]={{0,1,2,3,1,0},{0,3,4,5,0,1},{6,7,8,9,1,2}};
LONG64 AxAv,X,Y,Z,XCoordinates[10]={-5,-5,5,5,5,-5,60,60,120,120},YCoordinates[10]={-5,5,5,-5,-5,-5,80,140,140,80},ZCoordinates[10]={10,10,10,10,30,30,100,100,200,200},q$,w$,e$,r$,t$,y$,u$,i$;
POINT Points[3][4]={{{0,0},{0,0},{0,0},{0,0}}};
RECT WindowRect;
const HPEN Pens[2]={CreatePen(PS_NULL,0,0),CreatePen(PS_SOLID,1,RGB(0,0,0))};
const HBRUSH Brushes[3]={CreateSolidBrush(RGB(0,0,0)),CreateSolidBrush(RGB(128,128,128)),CreateSolidBrush(RGB(255,255,255))};
HINSTANCE hInst;
HWND hWnd;
PAINTSTRUCT ps;
HDC hdc;
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){
switch(message){
case WM_KEYDOWN:
if(GetAsyncKeyState(16)){Speed=1+3*Speed/2;}
if(GetAsyncKeyState(17)){
Speed=2*Speed/3-1;
if(Speed<1){Speed=1;}
}if(GetAsyncKeyState(82)){
X=0;Y=0;Z=0;Theta=0;Phi=0;RegX=0;RegY=0;RegZ=0;
SinTheta=0;CosTheta=65536;SinPhi=0;CosPhi=65536;
}return 0;
case WM_SIZE:
GetWindowRect(hWnd,&WindowRect);
HorizontalAxis=WindowRect.right-WindowRect.left;
SemiHorizontalAxis=HorizontalAxis/2;
VerticalAxis=WindowRect.bottom-WindowRect.top-100;
SemiVerticalAxis=VerticalAxis/2;
AxAv=(HorizontalAxis+VerticalAxis)/2;
return 0;
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
if(GetAsyncKeyState(83)){
if(Phi>0){
Phi--;
SinPhi=Cosine[Phi];CosPhi=-Sine[Phi];
}
}if(GetAsyncKeyState(87)){
if(Phi<128){
Phi++;
SinPhi=Cosine[Phi];CosPhi=-Sine[Phi];
}
}if(GetAsyncKeyState(65)){
Theta--;
if(Theta<0){Theta=255;}
SinTheta=Sine[Theta];CosTheta=Cosine[Theta];
}if(GetAsyncKeyState(68)){
Theta++;
if(Theta>255){Theta=0;}
SinTheta=Sine[Theta];CosTheta=Cosine[Theta];
}if(GetAsyncKeyState(39)){VelZ=-SinTheta*Speed;VelX=-CosTheta*Speed;}
if(GetAsyncKeyState(38)){VelZ+=CosTheta*Speed;VelX-=SinTheta*Speed;}
if(GetAsyncKeyState(37)){VelZ+=SinTheta*Speed;VelX+=CosTheta*Speed;}
if(GetAsyncKeyState(40)){VelZ-=CosTheta*Speed;VelX+=SinTheta*Speed;}
if(GetAsyncKeyState(81)){VelY=65536*Speed;}
if(GetAsyncKeyState(69)){VelY=-65536*Speed;}
RegX+=VelX;RegY+=VelY;RegZ+=VelZ;
X+=RegX/65536;Y+=RegY/65536;Z+=RegZ/65536;
RegX%=65536;RegY%=65536;RegZ%=65536;
VelX=0;VelY=0;VelZ=0;
q$=0;
while(q$<Total){
Draw=false;
w$=Quadrilaterals[q$][0];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][0].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][0].y=SemiVerticalAxis+AxAv*u$/i$;
}w$=Quadrilaterals[q$][1];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][1].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][1].y=SemiVerticalAxis+AxAv*u$/i$;
}w$=Quadrilaterals[q$][2];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][2].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][2].y=SemiVerticalAxis+AxAv*u$/i$;
}w$=Quadrilaterals[q$][3];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][3].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][3].y=SemiVerticalAxis+AxAv*u$/i$;
}if(Draw){
SelectPen(hdc,Pens[Quadrilaterals[q$][4]]);
SelectBrush(hdc,Brushes[Quadrilaterals[q$][5]]);
Polygon(hdc,Points[q$],4);
}q$++;
}EndPaint(hWnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:return DefWindowProc(hWnd,message,wParam,lParam);
}
}
int CALLBACK WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nCmdShow){
GetWindowRect(GetDesktopWindow(),&WindowRect);
HorizontalAxis=WindowRect.right;
SemiHorizontalAxis=HorizontalAxis/2;
VerticalAxis=WindowRect.bottom-100;
SemiVerticalAxis=VerticalAxis/2;
AxAv=(HorizontalAxis+VerticalAxis)/2;
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,IDI_APPLICATION);
wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=NULL;
wcex.lpszClassName=_T("DesktopApp");
wcex.hIconSm=LoadIcon(wcex.hInstance,IDI_APPLICATION);
if(!RegisterClassEx(&wcex)){
MessageBox(NULL,_T("RegisterClassEx failed!"),_T("Something"),NULL);
return 1;
}hInst=hInstance;
hWnd=CreateWindow(_T("DesktopApp"),_T("Something Application"),WS_OVERLAPPEDWINDOW,0,0,HorizontalAxis,VerticalAxis,NULL,NULL,hInstance,NULL);
if(!hWnd){
MessageBox(NULL,_T("CreateWindow failed!"),_T("Something"),NULL);
return 1;
}ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
Sleep(10);
InvalidateRect(hWnd,NULL,true);
}return(int)msg.wParam;
}

This is the core of most, but not all, of the noticeable flicker:
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
Sleep(10);
InvalidateRect(hWnd,NULL,true);
}return(int)msg.wParam;
You are putting a Sleep statement and an InvalidateRect call not just between every WM_PAINT call, but behind EVERY windows message. That's going to cause all kinds of problems. Further, your InvalidateRect is passing true for the erase flag. Here's an improvement:
Create a timer either in WM_CREATE or right before you start pumping messages.
SetTimer(hWnd, 999, 33, NULL); // 999 is just a random timer id, "33" is the milliseconds to wait between WM_TIMER messages
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}return(int)msg.wParam;
And then handle the timer as follows in your WndProc.
case WM_TIMER:
{
InvalidateRect(hWnd, NULL, FALSE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:return DefWindowProc(hWnd, message, wParam, lParam);
}
Notice that I changed the redraw interval from 10 milliseconds to 33 milliseconds. I have a 4k monitor that can't go past 60 frames/second. A 10 millisecond interval is pushing that to go 100 frames/second. That's another element of flicker. So I reduced it to 30fps. We can try to push that back up after we get through some other fixes.
And since we've bought into InvalidateRect not clearing the whole screen, we can go ahead and add this to the WndProc as well so that all other redraw events won't erase it either.
case WM_ERASEBKGND:
{
return 1;
}
At this point with all the changes I've made so far, there's just a minimal amount of flicker left, especially when I resize your window down from full screen to a quarter of my 4k screen. Also, when I build your code for Release instead of Debug, it's even further reduced. That almost proves that all the math code between BeginPaint/Endpaint is taking too long and not drawing the frame within 1 frame tick.
One other minor optimization that I sometimes use, but can't definitively say if this will help is to not use the HDC provided by the BeginPaint call which might have a clipping region associated with it. It's sometimes faster to just get an unclipped HDC and redraw with that. You could try this mod to WM_PAINT. YMMV:
case WM_PAINT:
// validate that HWND
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
// fetch the unclipped DC so that subsequent drawing operations don't get boundary checked
hdc = GetDC(hWnd);
...
}if (Draw) {
SelectPen(hdc, Pens[Quadrilaterals[q$][4]]);
SelectBrush(hdc, Brushes[Quadrilaterals[q$][5]]);
Polygon(hdc, Points[q$], 4);
}q$++;
}
ReleaseDC(hWnd, hdc);
hdc = NULL;
return 0;
As I said above, most, but not all of the flickering is eliminated. Now to get rid of the rest, follow the instructions in the link provided by Alan Birtles. That is, in your WM_PAINT handler, create an offscreen memory DC and paint to that. Then blit from that offscreen DC to the real window DC. Your modified WM_PAINT should paint the entire space the memory DC as well including the background. When you do that, you can likely increase the framerate.

Related

Why when I paint, and the mouse is moving in the window, the painting is not done at the same time everywhere? (WinAPI)

After asking this question, I changed my code. It works, but when WM_PAINT paints the window and the cursor is moving in it, the painting is not done at the same time everywhere. Here you have a video to see it better. This is my WM_PAINT:
//TV is a struct with the dimensions of the window.
//BitmapBuffer is the bitmap containing the painting.
static int cont;
cont++;
HDC HDc;
PAINTSTRUCT ps;
HDc = BeginPaint(identifier, &ps);
Gdiplus::Graphics lienzo (HDc);
AlphaBlend(HDc, 0, 0, TV.width+4, TV.height+4, buffer, 0, 0, TV.width+4, TV.height+4, CopyInfo);
EndPaint(identifier, &ps);
Since the problem is when moving the mouse, maybe the WM_NCHITTEST message has something to do with it:
case WM_NCHITTEST:
POINTS point1 = MAKEPOINTS(lParam);
POINT point2;
point2.x = point1.x;
point2.y = point1.y;
ScreenToClient(hwnd, &point2);
if (PtInRegion(region, point2.x, point2.y))
{
if (inWindow == false) //inWindow is true when the cursor is in the window
{
inWindow = true;
TrackMouseEvent(&structure);
Repaint(); //this function repaint the buffer and after call invalidrect
}
return HTCLIENT;
}
else
{
if (inWindow == true)
{
inWindow = false;
Repaint();
}
return HTTRANSPARENT;
}
break;
Does anyone have an idea why this happens?
It's hard to see the problem, because your code doesn't define Repaint. However, you should be using InvalidateRect to tell Windows which area is being updated.
THAT SAID...
Windows is hard to program for updating images with out using a double buffering technique. This is when you draw to a memory (bitmap) then bitblt the bitmap to the screen.
You find this answer useful Reduce flicker with GDI+ and C++

What information does dwExtraInfo hold for the PMOUSEHOOKSTRUCT?

LRESULT CALLBACK LowLevelMouseProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
BOOL fpassmove = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_MOUSEMOVE: // how do i catch a dx instead of a cursor points?
PMOUSEHOOKSTRUCT me = (PMOUSEHOOKSTRUCT)lParam;
printf("x:%d\ny:%d\nextrainfo:%04X\n", me->pt.x,me->pt.y, me->dwExtraInfo );
break;
}
}
return(fpassmove ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelMouse);
return(0);
}
I am looking at all mouse moment from a global hook, and I'm trying to find the dx and dy of the mouse event, And I was hoping to find it in "dwExtraInfo". However, I have no idea how to make sense of the data inside "dwExtraInfo".
the windows documentation is not helpful in telling me what the data in dwExtraInfo means
dwExtraInfo
Type: ULONG_PTR
Additional information associated with the message.
Could not find any documentation on dwExtraInfo directly, but found something related: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo:
Return value
Type: LPARAM
The return value specifies the extra information. The meaning of the
extra information is device specific.
One example of such device specific extra information is Pen gestures: https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
Distinguishing Pen Input from Mouse and Touch
When your application receives a mouse message (such as
WM_LBUTTONDOWN), it may call the GetMessageExtraInfo function to
evaluate whether the message originated from a pen or a mouse device.
The value returned from GetMessageExtraInfo needs to be mask-checked
against 0xFFFFFF00, and then compared with 0xFF515700. The following
definitions may make this clearer:
#define MI_WP_SIGNATURE 0xFF515700
#define SIGNATURE_MASK 0xFFFFFF00
#define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE
If the comparison is true, then this mouse message was generated by a
Tablet PC pen or touch screen. In all other cases, you can assume that
this message was generated by a mouse device.
The lower 8 bits returned from GetMessageExtraInfo are variable. Of
those bits, 7 (the lower 7, masked by 0x7F) are used to represent the
cursor ID, zero for the mouse or a variable value for the pen ID.
Additionally, in Windows Vista, the eighth bit, masked by 0x80, is
used to differentiate touch input from pen input (0 = pen, 1 = touch).

InvalidateRect is not repainting the window

I got a polygon that is drawn whenever I press a button.
I wanted to repaint the polygon as I press the button again, but when I press it, it just paints another polygon without erasing the other one:
//header
#define CREATETRIANGLE 1
//WM_COMMAND
case 2:
PAINTPROCEDURE = CREATETRIANGLE;
InvalidateRect(hwnd, NULL, TRUE);
break;
//WM_PAINT
case WM_PAINT:
switch(PAINTPROCEDURE){
case 0:{
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd,&ps);
}
break;
case 1:
RedrawWindow(hwnd, &rect, NULL, RDW_NOCHILDREN); //I tried this function, but it did nothing
TriangleDC = BeginPaint(hwnd, &tps);
SelectPen(TriangleDC, CreatePen(PS_SOLID, 2, RGB(256,256,256)));
SelectBrush(TriangleDC, CreateSolidBrush(RGB(0,192,192)));
{
POINT vertices[] = {{baseX,baseY}, {(baseX-(triangle.sideB)),baseY}, {baseX,(baseY-triangle.sideC)}};
Polygon(TriangleDC, vertices, 3);
}
EndPaint(hwnd,&ps);
PAINTPROCEDURE = 0;
break;
I also tried to get the polygon out of its scope, but it did nothing as well.
it just paints another polygon without erasing the other one
When you call BeginPaint, the system will normally call WM_ERASEBKGND before returning. The WM_ERASEBKGND handler is then given a chance to "erase" the window. The default handler (from DefWndProc) will fill the area with the brush from the WNDCLASS for this window.
It sounds like the erasing isn't happening which can mean: (1) you've provided WM_ERASEBKGND handler that doesn't actually erase the screen, or (2) the hbrBackground in the WNDCLASS is set wrong or set to the null brush.
In either of those cases, what should happen is that the fErase field of the PAINTSTRUCT you got from BeginPaint will be set to something other than 0, which tells you that you [the WM_PAINT handler] still have to erase the window first.
Now sometimes people play games with their own custom WM_ERASEBKGND handler when trying to optimize painting (or in a miguided attempt to reduce flicker). That can result in the fErase flag being 0 even if you do need to erase first.
My advice is to let DefWndProc handle the WM_ERASEBKGND and to make sure you've got a proper value set for hbrBackground in the WNDCLASS. Once that works, you can experiment with other approaches.

Tabcontrol paints over main window childs

Here is how the program looks as it starts :
http://oi58.tinypic.com/2dwgs4h.jpg (can't upload images if I have less than 10 rep, sorry)
As soon as I hover with the cursor to change tab, every control which is not a child of the tabcontrol gets painted over in white as shown here :
http://oi61.tinypic.com/2yvuiwl.jpg
Here is how I created the TabControl in WM_CREATE:
RECT client_rect;
GetClientRect(hwnd, &client_rect);
TabControl = CreateWindowEx(WS_EX_COMPOSITED, WC_TABCONTROL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
10, 10, client_rect.right - client_rect.left - 20,
client_rect.bottom - client_rect.top - 20, hwnd, (HMENU)110, GetModuleHandle(NULL), NULL);
TCITEM tab_info;
memset(&tab_info, 0, sizeof(tab_info));
tab_info.mask = TCIF_TEXT;
tab_info.pszText = L"Encoder";
tab_info.cchTextMax = 5;
SendMessage(TabControl, TCM_INSERTITEM, 0, (LPARAM)&tab_info);
tab_info.pszText = L"Decoder";
SendMessage(TabControl, TCM_INSERTITEM, 1, (LPARAM)&tab_info);
tab_info.pszText = L"Info Tab ";
SendMessage(TabControl, TCM_INSERTITEM, 2, (LPARAM)&tab_info);
RECT tab_rectangle;
GetClientRect(TabControl, &tab_rectangle);
SendMessage(TabControl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tab_rectangle);
DefaultTabProc = (WNDPROC)SetWindowLongPtr(TabControl, GWL_WNDPROC, (LONG_PTR)TabProc);
Every other control is a child of the main window, except for the two buttons on the left which are defined as childs of the TabControl it self.
I've subclassed the TC to be able to paint that 50x50 px bitmap in bottom left and I'm handling the WM_PAINT of the subclassed wndproc this way :
case WM_PAINT:
{
if (!BitmapCall) //bool to decide whether I invalidated this rect to print the bitmap or not
CallWindowProc(DefaultTabProc, hwnd, uMsg, wParam, lParam);
if (EncodingTab) //we are in the Encoding tab, so print the bitmap
{
HDC hdc = GetDC(hwnd);
Graphics grap(hdc);
grap.DrawImage(&(*bitmap), 20, 248);
ReleaseDC(hwnd, hdc);
BitmapCall = false;
}
break;
}
Strangely, if I call Graphics grap(GetDC(hwnd)); the problem does not arise, and I'd take this route if it wasn't for the great memory leak i'm facing over few dozens of seconds after the application starts.
I tried to handle Tabcontrol's WM_ERASEBKGND and just return TRUE without luck. I could then make every control child of the TC but apparently groupboxes and radio buttons doesn't like the idea and gets painted all in black leaving me with even more troubles.
Painting the bitmap from the main frame window looks impossible since it gets overpainted by again said TC,
I may finally try to handle the order in which everything gets painted but I have no clue on where to start/how to do
Thanks in advance

How to check mouse is not moved from last 5 seconds?

I'm working on a task for my game program, in which I want to hide my mouse after 10 seconds from my screen. However I'm able to check the mouse move condition...
Here is my code..
using namespace std;
HHOOK g_hMouseHook;
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
PMSLLHOOKSTRUCT pmll = (PMSLLHOOKSTRUCT) lParam;
switch (wParam)
{
case WM_MOUSEMOVE:
printf("Mouse has been moved\n");
break;
}
}
return CallNextHookEx(g_hMouseHook, nCode, wParam, lParam);
}
int _tmain(int argc, _TCHAR* argv[])
{
MSG msg;
g_hMouseHook = SetWindowsHookEx( WH_MOUSE_LL, LowLevelMouseProc, GetModuleHandle(NULL), 0 );
if (!g_hMouseHook)
printf("err: %d\n", GetLastError());
while ( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(g_hMouseHook);
return (int) msg.wParam;
}
I'm doing it by using hook and it is displaying the mouse movement successfully.
Now I'm searching for an option with which I can also check that my mouse has not been moved.
*one thing I'm making it on console.
I've changed the mouse cursor or the hide by using LoadCursorfromFile and it's working properly.
Please share your opinions on to check when the mouse is not moving.
Call TrackMouseEvent to set up an idle time of 5000 milliseconds. You'll get a WM_HOVER message after 5 seconds. You could reset the timer on every keypress, but that's a bit inefficient. Instead, on every keypress you should update a lastKeyPressedTime variable. Now, if WM_HOVER arrives after 5 seconds, you check to see if the last keypress is 5 seconds ago. If it is, you have neither keyboard nor mouse input an can remove the mouse.
If you had keyboard input in the last 5 seconds while the mouse was idle, you should reset the TrackMouseEvent. If you're lazy, reset it to 5 seconds again. If you're being accurate, you have to get a bit more creative.
Perhaps GetLastInputInfo is what you need MSDN here.
For example, to get the elapsed milliseconds since the last mouse move or key press, you might have a function like this:
DWORD GetIdleTime()
{
LASTINPUTINFO pInput;
pInput.cbSize = sizeof(LASTINPUTINFO);
if (!GetLastInputInfo(&pInput))
{
// report error, etc.
}
// return idle time in millisecs
return pInput.dwTime;
}