Господа! помогите пожалуйста разобраться с непонятным недокументированным багом в моей маленькой программе в следствии которого в программе появляются лишние GDI-объекты а конкретно DC (контексты устройства) и программа начинает "кушать" память. Это регистрируется диспетчером задач виндовс(столбцы память, объекты GDI). Контексты устройства создаются при вызове функции BeginPaint() и удаляются при вызове EndPaint() НО!!! так происходит только тогда когда в блоке рисования не используется функция DrawText() (или она закомментирована или не вызывается в соответствии с кодом программы) Соответственно когда она хотя бы единожды была вызвана функция EndPaint() уже не удаляет созданный ранее объект GDI и они начинают накапливаться.. И вообще странно что функции BeginPaint() создаёт какие-то объекты. Ведь как известно она лишь получается хендл контекста устройства у системы, а он ОБЩИЙ..
Код:
#include <windows.h>
#include <tchar.h>
#include "судоку.h"
LRESULT APIENTRY WndProc(HWND, UINT, WPARAM, LPARAM);
struct rter
{
RECT rt;
RECT ref;
bool er;
};
rter area[9][9];
cell tab;
info str;
TCHAR out[150];
#define x0 5 //отступ слева
#define y0 5 //отступ сверху
const TCHAR mb[][19]={"Судоку","Цифра недопустима","Решение не найдено"};
int CALLBACK _tWinMain(HINSTANCE This, // Дескриптор текущего приложения
HINSTANCE Prev, // В современных системах всегда 0
LPTSTR cmd, // Командная строка
int mode) // Режим отображения окна
{
HWND hWnd; // Дескриптор главного окна программы
MSG msg; // Структура для хранения сообщения
WNDCLASS wc; // Класс окна
// Определение класса окна
wc.hInstance = This;
wc.lpszClassName = "WINDOW"; // Имя класса окна
wc.lpfnWndProc = WndProc; // Функция окна
wc.style; // Стиль окна
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Стандартная иконка
wc.hCursor = LoadCursor(NULL,IDC_ARROW); // Стандартный курсор
wc.lpszMenuName = NULL; // Нет меню
wc.cbClsExtra = 0; // Нет дополнительных данных класса
wc.cbWndExtra = 0; // Нет дополнительных данных окна
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH );// Заполнение окна светло-серым цветом
RegisterClass(&wc); // Регистрация класса окна
// Создание окна
hWnd = CreateWindow("WINDOW", // Имя класса окна
mb[0], // Заголовок окна
WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, // Стиль окна
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y Размеры окна
331, // Width
400, // Height
NULL, // Дескриптор родительского окна
NULL, // Нет меню
This, // Дескриптор приложения
NULL); // Дополнительной информации нет
CreateWindow("BUTTON","Очистить всё",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 80, 330, 110, 35, hWnd,(HMENU)0, This ,NULL) ;
CreateWindow("BUTTON","Решить",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 210, 330, 110, 35, hWnd,(HMENU)101, This ,NULL) ;
ShowWindow(hWnd, mode); //Показать окно
while(GetMessage(&msg, NULL, 0, 0))// Цикл обработки сообщений
{
TranslateMessage(&msg);// Функция трансляции кодов нажатой клавиши
DispatchMessage(&msg); // Посылает сообщение функции WndProc()
}
return msg.wParam;
}
// Оконная функция вызывается операционной системой
// и получает сообщения из очереди для данного приложения
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
static int Y=0,X=0;
static HFONT hF;
static HPEN hP2,hP3;
static LOGBRUSH lb;
static HBRUSH hB;
static HCURSOR hC;
int c;
TCHAR F;
int yd,xd;
bool res;
switch(message)
{
case WM_CREATE:
hF=CreateFont(36, // высота шрифта
0, // ширина символов
0, // угол наклона букв
0, // угол наклона строки
FW_NORMAL, // толщина букв («жирность»)
0, // курсив
0, // подчеркивание
0, // перечеркивание
DEFAULT_CHARSET, // набор символов
OUT_DEFAULT_PRECIS, // точность вывода
CLIP_DEFAULT_PRECIS, // точность отсечения
DEFAULT_QUALITY, // качество вывода
DEFAULT_PITCH, // шаг между буквами
"Calibri" // имя шрифта
);
lb.lbColor=RGB(0,0,255);
hP2=CreatePen(PS_SOLID,2,RGB(0,0,0)); //толстые линии
hP3=ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_SQUARE,4,&lb,0,NULL); //линии курсора
hB= CreateSolidBrush(RGB(255,119,119));
hC=LoadCursor(NULL,IDC_WAIT);
for(int yc=0,yd=0;yc<9;yc++,yd+=35)
for(int xc=0,xd=0;xc<9;xc++,xd+=35)
{
tab.fig[yc][xc]=0;
area[yc][xc].rt.left=xd;
area[yc][xc].rt.right=xd+35;
area[yc][xc].rt.top=yd;
area[yc][xc].rt.bottom=yd+35;
area[yc][xc].ref.left=xd+x0-2;
area[yc][xc].ref.right=xd+x0+37;
area[yc][xc].ref.top=yd+y0-2;
area[yc][xc].ref.bottom=yd+y0+37;
area[yc][xc].er=true;
}
break;
case WM_LBUTTONDOWN:
if((LOWORD(lParam)-x0)/35U<9 &&(HIWORD(lParam)-y0)/35U<9)
if(area[Y][X].er)
{
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
X = (LOWORD(lParam)-x0)/35;
Y = (HIWORD(lParam)-y0)/35;
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
}
else
MessageBox(hWnd,mb[1],mb[0],MB_OK|MB_ICONWARNING);
break;
case WM_COMMAND:
switch(wParam)
{
case 0:
for(int y=0;y<9;y++)
for(int x=0;x<9;x++)
{
tab.fig[y][x]=0;
area[y][x].er=true;
}
break;
case 101:
if(area[Y][X].er)
{
hC=SetCursor(hC);
res=process(&tab,&str);
hC=SetCursor(hC);
if(!res)
MessageBox(hWnd,mb[2],mb[0],MB_OK| MB_ICONASTERISK );
}
else
MessageBox(hWnd,mb[1],mb[0],MB_OK|MB_ICONWARNING);
break;
}
InvalidateRect(hWnd,NULL,TRUE);
SetFocus(hWnd);
break;
case WM_SETFOCUS:
break;
case WM_KEYDOWN:
switch(wParam)
{
case VK_UP:
if(Y>0)
if(area[Y][X].er)
{
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
Y--;
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
}
else
MessageBox(hWnd,mb[1],mb[0],MB_OK|MB_ICONWARNING);
break;
case VK_DOWN:
if(Y<8)
if(area[Y][X].er)
{
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
Y++;
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
}
else
MessageBox(hWnd,mb[1],mb[0],MB_OK|MB_ICONWARNING);
break;
case VK_LEFT:
if(X>0)
if(area[Y][X].er)
{
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
X--;
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
}
else
MessageBox(hWnd,mb[1],mb[0],MB_OK|MB_ICONWARNING);
break;
case VK_RIGHT:
if(X<8)
if(area[Y][X].er)
{
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
X++;
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
}
else
MessageBox(hWnd,mb[1],mb[0],MB_OK|MB_ICONWARNING);
break;
case VK_DELETE:
for(int y=0;y<9;y++)
for(int x=0;x<9;x++)
{
tab.fig[y][x]=0;
area[y][x].er=true;
}
InvalidateRect(hWnd,NULL,TRUE);
break;
case VK_RETURN:
if(area[Y][X].er)
{
hC=SetCursor(hC);
res=process(&tab,&str);
hC=SetCursor(hC);
if(res)
InvalidateRect(hWnd,NULL,TRUE);
else
MessageBox(hWnd,mb[2],mb[0],MB_OK| MB_ICONASTERISK );
}
else
MessageBox(hWnd,mb[1],mb[0],MB_OK|MB_ICONWARNING);
break;
case VK_F1:
wsprintf(out,"Всего итераций:\t\t%d\nЗаходов в case1:\t\t%d\nЗаходов в case2:\t\t%d\nЗаходов в case0:\t\t%d\nМакс длина очереди:\t%d",str.iter,str.c1,str.c2,str.c0,str.maxq);
MessageBox(hWnd,out,"Техническая информация",MB_OK| MB_ICONASTERISK );
}
break;
case WM_CHAR:
if(wParam-48<10 && wParam-48!=tab.fig[Y][X])
{
tab.fig[Y][X]=c=wParam-48;
area[Y][X].er=true;
InvalidateRect(hWnd,&area[Y][X].ref,TRUE);
if(c==0) c=-1;
for(yd=Y;yd>2;yd-=3);
for(xd=X;xd>2;xd-=3);
for(int xu=0;xu<9;xu++)
if(xu!=X)
if(tab.fig[Y][xu]==c)
{
area[Y][xu].er=false;
area[Y][X].er=false;
InvalidateRect(hWnd,&area[Y][xu].ref,TRUE);
}
else
{
if(area[Y][xu].er==false)
InvalidateRect(hWnd,&area[Y][xu].ref,TRUE);
area[Y][xu].er=true;
}
for(int yu=0;yu<9;yu++)
if(yu!=Y)
if(tab.fig[yu][X]==c)
{
area[yu][X].er=false;
area[Y][X].er=false;
InvalidateRect(hWnd,&area[yu][X].ref,TRUE);
}
else
{
if(area[yu][X].er==false)
InvalidateRect(hWnd,&area[yu][X].ref,TRUE);
area[yu][X].er=true;
}
for(int yu=Y-yd;yu<Y-yd+3;yu++)
for(int xu=X-xd;xu<X-xd+3;xu++)
if(yu!=Y && xu!=X)
if(tab.fig[yu][xu]==c)
{
area[yu][xu].er=false;
area[Y][X].er=false;
InvalidateRect(hWnd,&area[yu][xu].ref,TRUE);
}
else
{
if(area[yu][xu].er==false)
InvalidateRect(hWnd,&area[yu][xu].ref,TRUE);
area[yu][xu].er=true;
}
}
break;
case WM_PAINT:
hDC=BeginPaint(hWnd,&ps);
SetViewportOrgEx(hDC, x0,y0 , NULL);
SelectObject(hDC,hF);
SetBkMode(hDC,TRANSPARENT);
for(int y=0;y<9;y++)
for(int x=0;x<9;x++)
if(tab.fig[y][x]!=0 )
{
if(area[y][x].er==false)
FillRect(hDC,&area[y][x].rt,hB);
wsprintf(&F,"%d",tab.fig[y][x]);
DrawText(hDC,&F, 1, &area[y][x].rt,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
for(int a=35;a<281;a+=35)
{
MoveToEx(hDC,a,0,NULL);
LineTo(hDC,a,315);
MoveToEx(hDC,0,a,NULL);
LineTo(hDC,315,a);
}
SelectObject(hDC,hP2);
for(int a=0;a<316;a+=105)
{
MoveToEx(hDC,a,-1,NULL);
LineTo(hDC,a,315);
MoveToEx(hDC,0,a,NULL);
LineTo(hDC,315,a);
}
SetViewportOrgEx(hDC, area[Y][X].rt.left+x0,area[Y][X].rt.top+y0 , NULL);
SelectObject(hDC,hP3);
MoveToEx(hDC,0,9,NULL);
LineTo(hDC,0,0);
LineTo(hDC,9,0);
MoveToEx(hDC,26,0,NULL);
LineTo(hDC,35,0);
LineTo(hDC,35,9);
MoveToEx(hDC,35,26,NULL);
LineTo(hDC,35,35);
LineTo(hDC,26,35);
MoveToEx(hDC,9,35,NULL);
LineTo(hDC,0,35);
LineTo(hDC,0,26);
EndPaint(hWnd,&ps);
break;
case WM_CLOSE :
DeleteObject(hP2);
DeleteObject(hP3);
DeleteObject(hF);
DeleteObject(hB);
PostQuitMessage(0);
break; // Завершение программы
// Обработка сообщения по умолчанию
default : return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}