Использование макросов ASSERT()и VERIFY()в полноэкранных приложениях DirectDraw осложняется тем, что при неудачной проверке выводится диалоговое окно. Несовместимость палитры может привести к искажению окна, а из-за переключения страниц окно может и вовсе не появиться на экране.
При таких затруднениях у вас есть два варианта: отказаться от ASSERT()и VERIFY()или предоставить нестандартные версии, работающие в DirectDraw. Второй вариант предпочтительнее, и, как выясняется, он реализуется достаточно просто.
Если покопаться в заголовочных файлах MFC, вы увидите, что в отладочном режиме макрос ASSERT()определяется так:
#define ASSERT(f) \
do \
{ \
if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) \
AfxDebugBreak(); \
} while (0) \
Выглядит довольно странно. Но вместо того, чтобы пытаться расшифровать логику его работы, мы согласимся с тем, что макрос работает, и попытаемся изменить его так, чтобы он правильно работал в приложениях DirectDraw. Однако перед этим следует заметить, что вывод диалогового окна и завершение приложения выполняются с помощью вызова AfxAssertFailedLine(). Следовательно, любой код, добавленный в этот условный оператор (что на первый взгляд кажется логичным), выполняться не будет.
Теперь давайте подумаем, что нужно сделать для нормального отображения диалогового окна. Можно вызвать функцию DirectDraw FlipToGDISurface()и обеспечить вывод диалогового окна на первичной поверхности, но проблема с палитрой при этом остается, к тому же окно может быть выведено в неверном видеорежиме. Вместо этого мы воспользуемся функцией RestoreDisplayMode() — это гарантирует вывод диалогового окна, активизацию стандартной палитры Windows и возврат к исходному видеорежиму Windows. Видоизмененный код выглядит так:
#define ASSERT(f) \
do \
{ \
if (!(f)) \
{ \
if (GetDDWin()) \
{ \
GetDDWin()->GetDDraw()->RestoreDisplayMode(); \
GetDDWin()->GetDDraw()->Release(); \
} \
AfxAssertFailedLine(THIS_FILE, __LINE__); \
AfxDebugBreak(); \
} \
} while (0) \
Для работы с объектом DirectDraw применяются функции GetDDWin()и GetDDraw()(которые соответственно возвращают указатели на объект DirectDrawWinи интерфейс DirectDraw). Помимо вызова функции RestoreDisplayMode()мы для приличия освобождаем объект DirectDraw. Также обратите внимание на перестановку, в результате которой наш код будет выполняться перед вызовом функции AfxAssertFailedLine().
Перейдем к макросу VERIFY(). Возвращаясь к заголовочным файлам MFC, мы находим, что в отладочной версии VERIFY()реализуется с помощью макроса ASSERT():
#define VERIFY(f) ASSERT(f)
Вспомните — в отладочной версии ASSERT()и VERIFY()ведут себя одинаково. Раз ASSERT()и VERIFY()реализуются одним макросом, VERIFY()можно оставить без изменений. Сказанное относится и к окончательным версиям макросов ASSERT()и VERIFY(), потому что нам не потребуется изменять их поведение. При компиляции окончательной версии ASSERT()и VERIFY()определяются так:
#define ASSERT(f) ((void)0)
#define VERIFY(f) ((void)(f))
Как было сказано выше, выражение, передаваемое макросу ASSERT(), удаляется из окончательной версии (в действительности оно заменяется выражением ((void)0), которое игнорируется компилятором). Выражения, передаваемые VERIFY(), остаются в коде программы, однако их значение больше не проверяется.
Нам остается лишь переопределить стандартный вариант ASSERT()из MFC своим нестандартным вариантом. Для этого необходимо сначала отменить определение макроса из MFC. Кроме того, нужно позаботиться о том, чтобы подстановка осуществлялась только в отладочной версии. Окончательный код выглядит так:
#ifdef _DEBUG#undef ASSERT#define ASSERT(f) \
do \
{ \
if (!(f)) \
{ \
if (GetDDWin()) \
{ \
GetDDWin()->GetDDraw()->RestoreDisplayMode(); \
GetDDWin()->GetDDraw()->Release(); \
} \
AfxAssertFailedLine(THIS_FILE, __LINE__); \
AfxDebugBreak(); \
} \
} while (0) \
#endif _DEBUG
Модифицированный макрос находится на CD-ROM и готов к работе, поэтому если вы захотите внести изменения в какую-нибудь программу, то можете свободно пользоваться макросами TRACE(), ASSERT()и VERIFY(). Кроме того, этот код автоматически генерируется и включается в проекты, создаваемые DirectDraw AppWizard.
Читать дальше