Reputation: 2275
I am making a simple game in Win32. Currently, I have most of my drawing object declared globally in the main file so that I never have to delete them or reload bitmaps. So basically all of my bitmaps are loaded in WM_CREATE, and then nothing ever needs to be deleted - I was told by someone that I could just rely on the system to clean up my resources on project termination. In WM_PAINT (which is called around 10 times a second), I have a lot of BitBlt() calls, as well as quite a few SelectObject() calls. After running for about 10 - 15 minutes, SelectObject(). What would cause SelectObject() to fail, and am I using GDI object incorrectly?
EXAMPLE:
// Top of the file
HDC hdc;
HDC hdcmem;
HDC hbcmem;
HBITMAP colorsprites, blackwhitesprites, nums;
HBITMAP hdcold, hdcbmold, hdcbm;
// Some functions to get the window ready
// More variables used for drawing:
HBITMAP bg, side, mainCont, tmpbm, tmpold, bm_left, bm_right, sidebg, win_bm;
PAINTSTRUCT ps;
RECT rc;
HDC tmphdc;
HDC tmp;
HFONT font;
HBRUSH hbr;
HPEN pen;
BITMAP structBitmapHeader;
HGDIOBJ hBitmap;
HCURSOR crosshairs = LoadCursorW(hInst, IDC_CROSS);
HCURSOR normal = LoadCursorW(hInst, IDC_ARROW);
POINT cursor;
bool addPass = false, ignorePass;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
hdc = GetDC(hWnd);
hdcmem = CreateCompatibleDC(hdc);
GetClientRect(hWnd, &rc);
hdcbm = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
hbcmem = CreateCompatibleDC(hdcmem);
hdcbmold = (HBITMAP)SelectObject(hdcmem, hdcbm);
// Load bitmaps
bg = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BACKGROUND));
mainCont = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_GAME_CONT));
side = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SIDEINFO));
colorsprites = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_COLOR_SPRITES));
blackwhitesprites = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BLACKWHITE_SPRITES));
sidebg = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SIDEBG));
nums = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_NUMBERS));
bm_left = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_LEFT));
bm_right = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_RIGHT));
win_bm = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_VICTORY));
if(bg == NULL || mainCont == NULL || side == NULL || colorsprites == NULL
|| blackwhitesprites == NULL || sidebg == NULL || nums == NULL || bm_left == NULL
|| bm_right == NULL)
ThrowError("A bitmap failed to load.");
break;
case WM_PAINT:
BeginPaint(hWnd, &ps);
// SelectObject() and BitBlt() are called a lot in here
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
// System will clean up all GDI stuff - no need to delete anything
PostQuitMessage(0);
break;
}
}
Upvotes: 1
Views: 1699
Reputation: 10425
You can make life a lot easier by calling SaveDC right after BeginPaint and RestoreDC just before EndPaint. This will restore the DC to its original state before it is freed.
http://msdn.microsoft.com/en-us/library/windows/desktop/dd162945(v=vs.85).aspx
Upvotes: 2
Reputation: 308530
Make sure that when you destroy a DC, you've selected the original bitmap back into it. You should never destroy a DC while your bitmap is still selected.
Upvotes: 3