While testing my program, I've discovered an annoying issue that I have not been able to fix. When another applications window is being dragged over the my window, the title bar and menu bar text will flicker. This happens with anything, including folders, but is most noticeable when the ‘active’ foreground window is something like Media Player. I suspect it is something to do with the way the double buffering is implemented or where I am doing my drawing. I have tried a number of different things to remedy it:
- using WS_CLIPCHILDREN and WS_EX_COMPOSITED in CreateWindowEx
- removing all code that blits or draws anything to the client area
- using runtime created menus instead of resource created menus and vice versa
- using PeekMessage instead of GetMessage
- using a region to only update the client area sans menu bar
- entirely removing the timer
- tried alternate double buffering code (all have the same issue, or other artifacts)
Below is the full code to my program. I would greatly appreciate if somebody knows if there is a way to fix this. Feel free to point out anything stupid :P
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <time.h>
#include "resource.h"
const char g_szClassName[] = "GDIWindowClass";
HDC HDCMem;
HBITMAP g_hbmBackm, g_hbmChar, g_hbmChar2, g_hbmChar3, g_hbmChar4, g_hbmChar5 = NULL;
HWND b_btnPrev = NULL;
HWND b_btnNext = NULL;
HFONT hSansFont = NULL;
HFONT hSerifFont = NULL;
HCURSOR hCursorArrow = NULL;
struct character* current_character;
struct character {
char name [36];
char source [36];
char about [300];
HBITMAP portrait;
};
struct character characters [13] =
{
{
"Name1", "Source1", "About1", (HBITMAP)&g_hbmChar
},
{
"Name2", "Source2", "About2", (HBITMAP)&g_hbmChar2
},
{
"Name3", "Source3", "About3", (HBITMAP)&g_hbmChar3
},
{
"Name4", "Source4", "About4", (HBITMAP)&g_hbmChar4
},
{
"Name5", "Source5", "About5", (HBITMAP)&g_hbmChar5
}
};
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
WNDCLASSEX wc;
HWND hWnd;
MSG Msg;
wc.cbSize = sizeof ( WNDCLASSEX );
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon ( hInstance, MAKEINTRESOURCE(IDI_ICON) );
wc.hCursor = hCursorArrow;
wc.hbrBackground = 0;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
wc.lpszClassName = g_szClassName;
wc.hIconSm = NULL;
RegisterClassEx ( &wc );
hWnd = CreateWindowEx ( 0, g_szClassName, "Slideshow", WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME, CW_USEDEFAULT, CW_USEDEFAULT, 545, 292, NULL, NULL, hInstance, NULL );
ShowWindow ( hWnd, SW_SHOW );
while ( GetMessage ( &Msg, NULL, 0, 0 ) > 0)
{
TranslateMessage( &Msg );
DispatchMessage ( &Msg );
}
return Msg.wParam;
}
BOOL CALLBACK AboutDlgProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
EndDialog(hWnd, IDOK);
break;
case IDCANCEL:
EndDialog(hWnd, IDCANCEL);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc, memDC, memDCBack;
PAINTSTRUCT ps;
static HBITMAP hBmp, hBmpBack;
static RECT rect;
static RECT textrect;
struct tm *timeinfo;
time_t tim = time(NULL);
timeinfo = localtime(&tim);
static char sTime[128];
switch(iMsg)
{
case WM_CREATE:
hCursorArrow = LoadCursor( NULL, IDC_ARROW );
hSansFont = CreateFont ( 8, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, 0, 0, DEFAULT_QUALITY, FF_DONTCARE, "MS Sans Serif" );
hSerifFont = CreateFont ( 21, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, 0, 0, DEFAULT_QUALITY, FF_DONTCARE, "MS Serif" );
characters[0].portrait = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_CHR1), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
characters[1].portrait = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_CHR2), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
characters[2].portrait = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_CHR3), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
characters[3].portrait = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_CHR4), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
characters[4].portrait = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_CHR5), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
b_btnPrev = CreateWindow ("button", "Previous", WS_VISIBLE | WS_CHILD, 193, 195, 70, 21, hwnd, (HMENU) IDB_BTN_PREV, NULL, NULL);
b_btnNext = CreateWindow ("button", "Next", WS_VISIBLE | WS_CHILD, 264, 195, 70, 21, hwnd, (HMENU) IDB_BTN_NEXT, NULL, NULL);
SendMessage ( b_btnPrev, WM_SETFONT, ( int ) hSansFont, TRUE );
SendMessage ( b_btnNext, WM_SETFONT, ( int ) hSansFont, TRUE );
SetRect(&textrect, 32, 88, 320, 320);
current_character = &characters[0];
GetClientRect(hwnd, &rect);
hBmpBack = LoadBitmap(((LPCREATESTRUCT)lParam)->hInstance, MAKEINTRESOURCE(IDB_BACK));
SetTimer(hwnd, 0, 10, NULL);
break;
case WM_TIMER:
localtime(&tim);
strftime(sTime, 80, " %I:%M %p", timeinfo);
hdc = GetDC(hwnd);
if(hBmp == NULL)
hBmp = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
memDC = CreateCompatibleDC(hdc);
memDCBack = CreateCompatibleDC(memDC);
SelectObject(memDC, hBmp);
SelectObject(memDCBack, hBmpBack);
BitBlt(memDC, 0, 0, rect.right, rect.bottom, NULL, 0, 0, WHITENESS);
BitBlt(memDC, 0, 0, 537, 246, memDCBack, 0, 0, SRCCOPY);
SelectObject(memDCBack, current_character->portrait);
BitBlt(memDC, 364, 26, 150, 190, memDCBack, 0, 0, SRCCOPY);
SelectObject(memDC, hSerifFont);
SetBkMode(memDC, TRANSPARENT);
SetTextColor(memDC, RGB(120, 120, 120));
TextOut(memDC, 32, 35, current_character->name, strlen(current_character->name));
TextOut(memDC, 32, 56, current_character->source, strlen(current_character->source));
TextOut(memDC, 96, 196, sTime, strlen(sTime));
SelectObject(memDC, hSansFont);
SetTextColor(memDC, RGB(0, 0, 0));
DrawText(memDC, current_character->about, -1, &textrect, DT_WORDBREAK);
DeleteDC(memDC);
DeleteDC(memDCBack);
ReleaseDC(hwnd, hdc);
InvalidateRgn(hwnd, NULL, FALSE);
break;
case WM_SETCURSOR:
if( (HWND)wParam == hwnd)
{
SetCursor(hCursorArrow);
return TRUE;
}
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
memDC = CreateCompatibleDC(hdc);
SelectObject(memDC, hBmp);
BitBlt(hdc, 0, 0, rect.right, rect.bottom, memDC, 0, 0, SRCCOPY);
DeleteDC(memDC);
EndPaint(hwnd, &ps);
break;
case WM_GETMINMAXINFO:
{
MINMAXINFO *minmax = (MINMAXINFO *)lParam;
minmax->ptMinTrackSize.x = 545;
minmax->ptMinTrackSize.y = 292;
minmax->ptMaxTrackSize.x = 545;
minmax->ptMaxTrackSize.y = 292;
}
break;
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_FILE_EXIT)
{
DestroyWindow(hwnd);
return 0;
}
if (LOWORD(wParam) == ID_HELP_ABOUT)
{
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);
return 0;
}
if (LOWORD(wParam) == IDB_BTN_NEXT)
{
if (current_character == &characters[6])
{
current_character = &characters[0];
}
else {
current_character+=1;
}
}
if (LOWORD(wParam) == IDB_BTN_PREV)
{
if (current_character == &characters[0])
{
current_character = &characters[6];
}
else {
current_character-=1;
}
}
}
break;
case WM_DESTROY:
for (int i = 0; i < 4; i++ ) {
DeleteObject(characters[i].portrait);
DeleteObject(characters[i].about);
DeleteObject(characters[i].source);
DeleteObject(characters[i].name);
};
DeleteObject(hSansFont);
DeleteObject(hSerifFont);
KillTimer(hwnd, 1);
PostQuitMessage ( 0 );
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}