 |
WM_PAINT. Однако, существует более привлекательная альтернатива,
которая состоит в том, чтобы установить точку останова по сообще-
нию, позволяющую сразу выйти на нужный участок программы, а затем
начать пошаговое выполнение, которое позволит точно выяснить при-
чину ошибки.
Установка точки останова по сообщению также отменит действие
выхода по Ctrl-Alt-SysRq, который делает небезопасным дальнейшее
пошаговое выполнение программы или выход из TDW. Так как сообще-
нием, на котором "застряла" программа, является WM_PAINT, устано-
вите для TDW прерывание по сообщению WM_PAINT и снова запустите
программу, следующим образом:
1. Снова войдите в окно Windows Messages (Сообщения
Windows), перейдите в правую верхнюю область, вызовите
локальное меню и выберите Add (Добавление).
2. Появится блок диалога Set Message Filter (Задание фильтра
сообщений) с уже выбранным значением Single Message (От-
дельное сообщение), а курсор в это время будет находиться
в текстовом поле ввода Single Message Name (Имя отдельно-
го сообщения). Введите WM_PAINT (только заглавными бук-
вами, иначе TDW не сможет найти соответствие), а в ка-
честве действия выберите Break (Прерывание).
3. Для запуска программы нажмите F9.
Программа немедленно прервется, и вы окажитесь на первой
строке WndProc. (Чтобы получить полный обзор кода, вы должны
очистить с экрана окно Windows Messages). Эта подпрограмма состо-
ит из оператора switch для сообщений, специальным образом обраба-
тываемых программой.
Подпрограмма WndProc:
long FAR PASCAL WndProc (HWND hWnd, unsigned Message,
WORD wParam, LONG lParam)
{
switch(Message)
{
case WM_COMMAND:
return DoWMCommand(wParam, hWnd);
case WM_LBUTTONDOWN:
DoLButtonDown(hWnd,lParam);
break;
case WM_LBUTTONUP:
DoLButtonUp(hWnd,lParam);
break;
TDeb 3.0 #3-3 = 52 =
case WM_MOUSEMOVE:
DoMouseMove(hWnd,lParam);
break;
case WM_PAINT:
DoPaint(hWnd);
break;
default:
return DefWindowProc(hWnd,Message,wParam,lParam);
}
return 0;
}
Пошаговое выполнение программы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Для пошагового выполнения программы нужно нажимать клавишу
F7. Маркер текущей строки дойдет до оператора case WM_PAINT, и
наконец до подпрограммы DoPaint.
Подпрограмма DoPaint:
void DoPaint(HWND hWnd)
{
int i,
saveROP;
HDC hdc,
hMemDC;
RECT theRect,
destRect;
HBITMAP the Bitmap;
PAINTSTRUCT ps;
if (CurrentPoint >= 0)
{
hdc = BeginPaint(hWnd,&ps);
/*
* Определить, какая прямоугольная область отмечена
* как недопустимая.
* Если ни один прямоугольник не помечен как
* недопустимый, то экран будет полностью перерисован.
*/
GetUpdateRect(hWnd,&theRect,0);
if (IsRectEmpty(&theRect))
GetClientRect(hWnd,&theRect);
/*
* Создание DC (контекста устройства) и области
* того же размера, что и обновляемый прямоугольник.
*/
TDeb 3.0 #3-3 = 53 =
hMemDC = CreateCompatibleDC(hdc);
theBitmap = CreateCompatibleBitmap(hdc,
theRect.right-theRect.left
theRect.bottom-theRect.top);
SelectObject(hMemDC,theBitmap);
/*
* Стирание memBitmap
*/
BitBlt(hMemDC, 0, 0,
theRect.right-theRect.left
theRect.bottom-theRect.top,
hdc, 0, 0, SCRCOPY);
/*
* Рисование только тех фигур, которые находятся
* внутри обновляемого прямоугольника.
*/
for (i = 0; i <= CurrentPoint; ++i)
{
IntersectRect(&destRect, &thisShape[i].Points,
&theRect);
if (!IsRectEmpty(&destRect))
DrawShape(hMemDC,
thisShape[i].Points.left-theRect.left,
thisShape[i].Points.top-theRect.top,
thisShape[i].Points.right-theRect.left,
thisShape[i].Points.bottom-theRect.top,
thisShape[i].theShape,thisShape[i].PenWidth,
thisShape[i].PenColor,thisShape[i].slope);
/*
* Отметим, что при рисовании фигуры программа переместила
* ее точку начала координат т.о., что она оказалась в
* верхнем левом углу обновляемого прямоугольника.
* Это точка (0,0) области, в которую будет выполнено
* отображение (theRect.left,theRect.right).
*/
}
/*
* И наконец, копирование области в область обновляемого
* прямоугольника.
*/
BitBlt(hdc, theRect.left, theRect.top,
theRect.right-theRect.left,
theRect.bottom-theRect.top,
hMemDC, 0, 0, SRCCOPY);
DeleteDC(hMemDC);
TDeb 3.0 #3-3 = 54 =
DeleteObject(theBitmap);
EndPaint(hWnd,&ps);
}
}
По мере продолжения пошагового выполнения вы увидите, что
единственная строка кода, выполняемая внутри DoPaint, это:
if (CurrentPoint >= 0)
Затем управление возвращается в цикл сообщений, в котором
программа принимает следующее сообщение, WM_PAINT, и затем снова
уходит на цикл с WndProc и DoPaint. Подпрограмма DoPaint, безус-
ловно, что-то делает не так, и нужно сначала выяснить, что же она
должна делать на самом деле?
TDeb 3.0 #3-3 = 55 =
Анализ DoPaint
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Назначение данной подпрограммы состоит либо в рисовании все-
го экрана при первом вызове подпрограммы, либо в перерисовке об-
ласти экрана, текущего прямоугольника, если на экране было
что-либо нарисовано. Чтобы определить, было ли что-нибудь нарисо-
вано, DoPaint проверяет значение переменной Currentpoint, перво-
начально устанавливаемой в -1. (CurrentPoint указывает число на-
рисованных объектов). Если CurrentPoint имеет значение -1, то
есть значение, которое было установлено при запуске и рисовании
исходного экрана, то брать и перерисовывать содержимое текущего
прямоугольника нет необходимости, поэтому все коды внутри опера-
тора if опускается, и происходит возврат, а Windows перерисовыва-
ет все окно.
Если вы будете проверять значение CurrentPoint в окне
|