Книга: Графика для Windows средствами DirectDraw

Отладка

Отладка

Говорят, некоторым программистам нравится отлаживать свои программы — я не отношусь к их числу. Приятно узнать, почему ваша программа постоянно «зависает» или почему спрайт неправильно выводится на экран — но я охотно поменял бы это чувство удовлетворения на те напрасно потраченные часы и дни, когда я скрежетал зубами, заново компилировал свои программы и в сотый раз перезагружал компьютер.

Конечно, наша рабочая среда не идеальна, а инструменты еще не прошли всего пути развития. Всю программную отрасль постоянно лихорадит от багов. Они приводят к задержкам, сворачиванию и отмене крупных и мелких проектов. На искоренение особо зловредных багов истрачены многие миллионы долларов.

Но, работая над проектом, содержащим множество багов, вы теряете не только деньги — вы теряете чувство уверенности. Программирование — дело непростое, и не стоит усложнять его попытками внести новые возможности в еще не отлаженную программу. Мы, программисты, видели достаточно багов и привыкли к ним, но такое положение дел никак нельзя считать нормальным.

Иногда ошибки возникают по вине Windows, иногда — по вине DirectX или какой-нибудь библиотеки классов, но подавляющее большинство багов лежит на совести прикладных программистов. Если вы нашли ошибку в программе, лучше бросить все дела и заняться ее искоренением. Не стоит усложнять ситуацию и продолжать работу, зная, что в вашей программе прячутся баги.

Об ошибках и способах отладки написаны многие тома. Особенно ценной я считаю книгу «Writing Solid Code» Стива Магуайра (Steve Maguire) (Microsoft Press, ISBN 1-55615-551-4). Если вы не читали ее ранее, обязательно прочтите. В этом приложении мы ограничимся проблемами и способами отладки, которые относятся к полноэкранным приложениям DirectDraw.

Проблемы

Отладить полноэкранное приложение намного сложнее, чем любое другое, и для этого есть несколько причин. Самая очевидная из них — раз приложение занимает весь экран, вы не сможете изменить точки прерывания, просмотреть код программы или значения переменных. Дело усложняется переключением страниц. Если программа должна вывести проверочное сообщение или отладочное окно, нельзя гарантировать, что оно действительно появится на экране, потому что Windows может вывести информацию во вторичном буфере. И даже если вам повезет и вы сможете увидеть это окно (при использовании буферизации ваши шансы — 50 на 50), вероятно, его все равно не удастся толком разглядеть из-за различий между текущей и системной палитрой.

Следовательно, многие традиционные механизмы и методики отладки не работают для DirectDraw. Интегрированный отладчик Visual C++ практически бесполезен, а пользоваться стандартными отладочными макросами типа ASSERT() или VERIFY() оказывается рискованно.

Windows NT и Windows 95

Первый шаг в великой битве с багами — переход на Windows NT (если вы еще не успели этого сделать). Разумеется, вам не придется отказываться от поддержки Windows 95, но для разработки NT подходит лучше, а приложения DirectX переносятся из NT в 95 без перекомпиляции. Просто Windows NT работает более устойчиво, чем Windows 95. NT редко (очень редко) требует перезагрузки, тогда как в 95 это вполне обычное явление.

Оборотная сторона заключается в том, что по возможностям DirectX NT часто отстает от 95. Поскольку в Windows NT нельзя установить стандартную runtime-часть DirectX, на поддержку новых возможностей у Microsoft уходит больше времени. Следовательно, если вам необходимы новейшие возможности DirectX, то для разработки неизбежно придется использовать Windows 95. Для DirectDraw это не вызывает особых проблем, потому что в последних версиях эта библиотека практически не изменялась. А вот другие DirectX API, напротив, заметно изменились в DirectX 5 (особенно это относится к DirectInput и DirectPlay).

Профессиональные разработчики для DirectX отдают явное предпочтение NT. Более того, некоторые будущие бета-версии DirectX могут предназначаться только для NT.

Отладочные макросы

Visual C++ (как и многие другие среды разработки) содержит макросы, предназначенные специально для отладки. Например, макросы TRACE(), ASSERT() и VERIFY() приносят огромную пользу в процессе разработки. Они предназначены для разных целей, но у всех трех макросов есть нечто общее — они не отягощают итоговый выполняемый файл. При построении отладочных версий вашей программы макросы ведут себя так, как им положено. Однако в «окончательной» версии они удаляются из программы (вместе с теми возможностями, которые ими обеспечивались).

Макрос TRACE() посылает диагностические сообщения в окно отладчика. Правильно составленные сообщения образуют протокол событий, который можно просмотреть после выполнения программы (а средства удаленной отладки, о которой мы вскоре поговорим, позволяют сделать это даже во время работы программы). Макросы TRACE(), содержащие коды возврата и описания ошибок, помогают отыскать источники багов в ваших программах. Макрос TRACE() в отличие от двух других нормально работает в полноэкранных приложениях DirectDraw, так что вы можете свободно пользоваться им (этот макрос регулярно встречается в программах на CD-ROM).

Макросы ASSERT() и VERIFY() очень похожи друг на друга, что часто приводит к недоразумениям. На самом деле между ними существует очень важное различие. В отладочных версиях макросы ASSERT() и VERIFY() работают одинаково. Оба макроса вычисляют выражение, переданное им в качестве аргумента, и прекращают работу программы с выводом сообщения в том случае, если это выражение оказывается равным нулю. Отличие заключается в том, что в окончательной версии макрос ASSERT() вместе с вычисляемым выражением полностью удаляется из кода. С другой стороны, выражение макроса VERIFY() остается в программе. Макрос ASSERT() предназначен для проверки состояния переменных, а VERIFY() — для проверки функций. Выражение макроса ASSERT() относится только к состоянию переменных и не является обязательной частью программы, поэтому его можно удалить из окончательной версии.

Использование макросов 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.

Удаленная отладка

Процесс отладки упрощается, если вам повезло и в вашем распоряжении оказались два компьютера, объединенных в локальную сеть. В этом случае возможна удаленная отладка, при которой на одном компьютере работает отлаживаемая программа, а на другом — отладчик Visual C++. При удаленной отладке исчезают все проблемы, связанные с переключением страниц, палитрами и отображением отладчика. Отладчик всегда присутствует на экране и с ним можно работать, потому что отладчик и приложение работают на разных компьютерах. Даже если ваша программа «сломается», ее состояние можно будет просмотреть в отладчике. Поскольку удаленная отладка обладает такими преимуществами (и при этом так плохо документирована), мы поговорим о том, как происходит ее настройка. Если эта тема вас не интересует, можете пропустить этот раздел.

Для выполнения удаленной отладки вам понадобятся два компьютера, объединенных в локальную сеть. Конкретные параметры сети (количество узлов, тип кабеля, сетевые адаптеры и т. д.) не имеют значения; главное — чтобы на обоих компьютерах был установлен сетевой протокол TCP/IP. Кроме того, необходимо установить на обоих компьютерах Visual C++.

Затем вы должны выбрать, на каком компьютере будет работать отладчик Visual C++, а на каком — приложение. Мы будем называть компьютер, на котором работает Visual C++, хостовым компьютером (или хостом), а компьютер с отлаживаемым приложением — удаленным компьютером. Обычно хостом назначают более мощный из двух компьютеров.

Вам необходимо узнать адреса TCP/IP для обоих компьютеров. Проще всего получить этот адрес с помощью утилиты Winipcfg (WINIPCFG.EXE). Для Winipcfg не существует ярлыка (shortcut) или команды меню Start, поэтому придется либо создать ярлык или команду (утилита находится в каталоге Windows), либо запустить Winipcfg из окна DOS или диалогового окна Run меню Start. Окно утилиты Winipcfg изображено на рис. А.1. В поле IP Address приведено значение адреса TCP/IP . В нашем примере удаленный компьютер имеет адрес 128.128.128.1 (а хостовый компьютер будет иметь адрес 128.128.128.2).


Рис. А.1. Утилита Winipcfg

Также вам понадобится сетевое имя удаленного компьютера. Сетевое имя представляет собой неформальную строку, которая облегчает идентификацию сетевых компьютеров (при этом вам не придется запоминать адреса TCP/IP для всех компьютеров сети). Чтобы узнать сетевое имя компьютера, можно щелкнуть правой кнопкой мыши на значке Network Neighborhood (он находится на рабочем столе) и выбрать из контекстного меню команду Properties; откроется диалоговое окно Network. Перейдите на вкладку Identification. На рис. А.2 показано, как выглядит эта вкладка. В данном примере имя удаленного компьютера — remotemachine. Вероятно, вам не стоит менять сетевое имя, если только вы не являетесь сетевым администратором — просто воспользуйтесь именем, которое было назначено компьютеру при исходной настройке.

Затем вам понадобится каталог на удаленном компьютере, где будет храниться и работать ваше приложение. Вы можете присвоить ему любое имя и разместить в любом месте жесткого диска, но на практике оказывается удобнее разместить этот каталог поближе к корневому. Вам не придется копировать выполняемый файл приложения (это будет сделано автоматически), однако следует перенести все файлы данных, необходимые для его работы. Собственно, выполняемый файл можно перенести хотя бы с целью тестирования. Чтобы отладка прошла нормально, запущенное приложение должно найти все свои файлы данных (не считая случаев, когда вы отлаживаете поведение программы при отсутствующих файлах данных).


Рис. А.2. Диалоговое окно Network Identification

После того как вы создадите каталог для приложения и убедитесь в том, что оно может выполняться на удаленном компьютере, запустите отладочный монитор Visual C++ (MSVCMON.EXE). Для этой программы, как и для утилиты Winipcfg, не существует ярлыка, поэтому вам придется создать его самостоятельно. Отладочный монитор находится в каталоге bin Visual C++. Если вы собираетесь плотно заняться удаленной отладкой, вероятно, ярлык отладочного монитора следует поместить в удобное место. Окно отладочного монитора Visual C++ изображено на рис. А.3.

Теперь нужно указать адрес хостового компьютера. Убедитесь, что в отладочном мониторе выбрано соединение TCP/IP, и нажмите кнопку Settings — откроется диалоговое окно Win32 Network (TCP/IP) Settings. Введите адрес хоста в первом поле. На рис. А.4 показано, как выглядит диалоговое окно с введенным адресом.

Вводить пароль необязательно — я рекомендую оставить это поле пустым. После ввода адреса хоста нажмите кнопку OK. Вы возвратитесь к диалоговому окну Debug Monitor. Нажмите кнопку Connect. Появится маленькое окно, которое показывает, что отладочный монитор готов начать сеанс отладки. Теперь удаленный компьютер настроен для проведения отладки.


Рис. А.3. Диалоговое окно Visual C++ Debug Monitor


Рис. А.4. Диалоговое окно Network Settings

Теперь займемся настройкой хоста. Запустите Visual C++ и загрузите проект, который вы собираетесь отлаживать. В нашем примере используется проект с именем Sample. Выполните команду Project|Settings и перейдите на вкладку General. На ней задается каталог, в котором генерируется итоговый выполняемый файл. Для упрощения отладки мы будем генерировать его прямо на удаленном компьютере — это избавит нас от необходимости заново копировать выполняемый файл на удаленный компьютер после очередной компиляции. В поле Output files введите имя каталога, созданного ранее на удаленном компьютере. Имя начинается с условного обозначения сетевого файла (). На рис. А.5 показано, как выглядит поле Output files с указанным каталогом.

Задаваемая строка начинается с имени удаленного компьютера (remotemachine), за которым следует имя диска (в нашем примере каталог удаленной отладки находится на диске C) и имя каталога. Перейдите на вкладку Debug; здесь необходимо изменить все три поля. Вы должны задать местонахождение целевого выполняемого файла и рабочий каталог. На рис. А.6 показано, как заполняются поля вкладки Debug в нашем примере. Как и на рис. А.5, путь к выполняемому файлу включает имя удаленного компьютера.

Перед тем как приступать к удаленной отладке, остается сделать лишь один шаг. Выполните команду Debugger Remote Connection из меню Build. Эта команда открывает окно (похожее на окно отладочного монитора), предназначенное для активизации и настройки сеанса удаленной отладки. По умолчанию в списке Connection выбирается строка Local. Чтобы перейти к удаленной отладке, выберите строку Network (TCP/IP), как показано на рис. А.7.


Рис. А.5. Поле Output files подготовлено для генерации выполняемого файла на удаленном компьютере


Рис. А.6. Изменения на вкладке Debug


Рис. А.7. Окно Remote Connection

Нажмите кнопку Settings — появится окно, изображенное на рис. А.4. Задайте в нем адрес TCP/IP удаленного компьютера. Поле Debug monitor password оставьте пустым, если только вы не задали пароль при настройке отладочного монитора на удаленном компьютере.

Теперь можно запускать отладчик. К сожалению, настройка еще не закончена, потому что отладчик потребует задать местонахождение всех DLL, используемых удаленным приложением. К счастью, это необходимо проделать лишь один раз.

Запустите отладчик. Если все параметры были настроены правильно, окно Debug Monitor на удаленном компьютере исчезнет — это говорит о том, что соединение установлено.

Удаленный компьютер попытается запустить программу, и вам будет предложено (на хостовом компьютере) указать местонахождение необходимых DLL. Для каждой DLL открывается окно Find Local Module. Вы должны ввести имя файла, включая сетевое имя компьютера. Окно Find Local Module изображено на рис. А.8 (в нем предлагается задать местонахождение файла WINMM.DLL). Часть введенной строки не поместилась на рисунке, но вы должны помнить о том, что кроме пути необходимо указать имя файла.


Рис. А.8. Окно Find Local Module

После того как вы укажете местонахождение всех DLL (как правило, они располагаются в каталоге windowssystem), программа запускается на удаленном компьютере, однако ее отладочный вывод направляется в окно отладчика на хосте. Теперь вы можете отлаживать свою программу. Мы настроили Visual C++ так, что при каждой компиляции новый выполняемый файл будет автоматически копироваться на удаленный компьютер. Удаленная отладка почти ничем не отличается от обычной, разве что программа выполняется не на хосте, а на другом компьютере.

Напоследок я скажу еще несколько слов об удаленной отладке. Во-первых, как ее отключить? Хороший вопрос. Выполните команду Build|Debugger Remote Connection в Visual C++ (на хосте), затем выберите строку Local в списке Connection и нажмите кнопку OK.

Удаленная отладка обладает многими достоинствами, но она не идеальна. Прежде всего, точки прерывания в ней работают ненадежно, а то и вовсе не работают. Другая проблема заключается в том, что после настройки удаленной отладки и выбора местонахождения DLL, необходимых для вашей программы, Visual C++ будет настаивать на загрузке DLL даже после возврата в режим локальной отладки. Следовательно, в конце раздела, посвященного удаленной отладке, мне следует рассказать о том, как вернуться к нормальной загрузке DLL.

Выполните команду Project|Settings и перейдите на вкладку Debug. Выберите из списка Category строку Additional DLL. Открывается список DLL, которые Visual C++ пытается загрузить при отладке вашей программы (независимо от того, включена удаленная отладка или нет). Чтобы отказаться от переназначения DLL (для нормальной отладки вам не потребуется ни один из элементов этого списка), выделите соответствующую строку и снимите флажок в левом верхнем углу. Список Additional DLLs с некоторыми DLL, необходимыми для типичных приложений MFC, изображен на рис. А.9.


Рис. А.9. Окно Additional DLLs

Отладочные сообщения DirectX

Вероятно, вы уже заметили, что при запуске приложений DirectX в окне вывода отладчика Visual C++ появляются диагностические сообщения. По умолчанию отладочные версии компонентов DirectX сообщают таким образом о важных внутренних событиях — например, об ошибках. Типичное окно вывода для приложения DirectDraw изображено на рис. А.10.

СОВЕТ

Прислушивайтесь к крикам DirectX

При установке runtime-части DirectX на рабочий компьютер возникает искушение установить окончательные версии DLL вместо отладочных (во время инсталляции вам предлагается выбрать нужный вариант). Не поддавайтесь соблазну и не устанавливайте окончательные версии! Да, они действительно работают чуть быстрее, и именно с ними будут работать пользователи вашего приложения, но при этом вы лишитесь отладочного вывода. Если во время работы над программой возникнут проблемы, вы так и не узнаете, что же DirectX пытается вам сказать.


Рис. А.10. Типичное окно вывода в отладчике

Возможно, вы не знаете, что детальность этих сообщений тоже можно изменять. В каждой из библиотек DirectDraw, Direct3D и DirectSound можно выбрать пять разных уровней отладочных сообщений. Чтобы настроить уровень отладочных сообщений, выберите значок DirectX в Control Panel и перейдите на вкладку нужного компонента DirectX. Диалоговое окно DirectX Properties с выбранной вкладкой DirectDraw изображено на рис. А.11.


Рис. А.11. Окно DirectX Properties (запускается из Control Panel)

Для библиотеки DirectDraw нажмите кнопку Advanced Settings — откроется окно DirectDraw Advanced Settings. Нужный уровень отладочных сообщений устанавливается с помощью слайдера Debug Level. Окно DirectDraw Advanced Settings изображено на рис. А.12.


Рис. А.12. Окно DirectDraw Advanced Settings

При максимальном уровне отладки каждое приложение DirectDraw, запущенное в отладчике, выдает весьма обширный и подробный протокол. Вывод протокола снижает быстродействие программы, так что максимальный уровень не стоит держать включенным постоянно. С другой стороны, он сильно помогает в затяжной борьбе с DirectDraw. Чтобы показать, насколько подробная информация выдается при максимальном уровне отладки, я приведу отладочный протокол для небольшого полноэкранного приложения DirectDraw. Обратите внимание на то, что листинг раскрывает некоторые внутренние тонкости работы DirectDraw. Подробный отладочный протокол приведен в листинге А.1.

Листинг А.1. Подробный отладочный протокол DirectDraw

DDraw:====> ENTER: DLLMAIN(baaa12c0): Process Attach: fff00c89, tid=fff04bf1
DDraw:Thunk connects
DDraw:Signalling DDHELP that a new process has connected
DDraw:====> EXIT: DLLMAIN(baaa12c0): Process Attach: fff00c89
DDraw:createDC(R3D)
DDraw:Enumerating GUID aba52f41-f744-11cf-b4-52-00-00-1d-1b-41-26
DDraw: Driver Name = R3D
DDraw: Description = Righteous 3D DirectX II Driver
DDraw:DeleteDC 0x179e
DDraw:createDC(mm3dfx)
DDraw:Enumerating GUID 3a0cfd01-9320-11cf-ac-a1-00-a0-24-13-c2-e2
DDraw: Driver Name = mm3dfx
DDraw: Description = 3Dfx Interactive DirectX Driver
DDraw:DeleteDC 0x179e
DDraw:Only one Display device in the current system.
DDraw:DirectDrawCreate entered
DDraw: GUID *:00000000, LPLPDD:0064f870, pUnkOuter:00000000
DDraw:Registry already scanned, not doing it again
DDraw:full name = C:SAMPLEDEBUGSAMPLE.EXE
DDraw:name = SAMPLE.EXE
DDraw:DirectDrawCreate: pid = fff00c89
DDraw:Reading Registry
DDraw: ModeXOnly: 0
DDraw: EmulationOnly: 0
DDraw: ShowFrameRate: 0
DDraw: EnablePrintScreen: 0
DDraw: DisableMMX: 0
DDraw: DisableWiderSurfaces:0
DDraw: DisableNoSysLock:0
DDraw: ForceNoSysLock:0
DDraw:Signalling DDHELP to create a new DC
DDraw:createDC(display)
DDraw:DIRECTDRAW driver is wrong version, got 0x5250, expected 0x0100
DDraw:getDisplayMode:
DDraw: bpp=8, refresh=0
DDraw: dwHeight=600, dwWidth=800
DDraw: lStride=0
DDraw:Driver says nummodes=9
DDraw:Enum Display Settings says nummodes=9
DDraw:dwModeIndex = 1
DDraw:Masks for current mode are: 00000000 00000000 00000000
DDraw:DirectDrawObjectCreate: oldpdd == 00000000, reset=0
DDraw:DIRECTDRAW object passed in = 00000000
DDraw:oldpdd == 00000000, reset=0
DDraw:Driver Object: 2256 base bytes
DDraw:dwReserved3 of DDrawGbl is set to 0x0
DDraw:oldpdd == NULL || reset
DDraw:Driver can't blt
DDraw:pddd->lp16DD = 40cf0000
DDraw:Adding ModeX mode 320x200x8 (standard VGA flag is 0)
DDraw:Adding ModeX mode 320x240x8 (standard VGA flag is 0)
DDraw:Adding ModeX mode 320x200x8 (standard VGA flag is 1)
DDraw:All video memory heaps have been disabled. OS has no AGP support
DDraw:Current and Original Mode = 1
DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 1
DDraw:DDHALInfo contains D3D pointers: 00000000 00000000
DDraw:createDC(display)
DDraw:NOT Setting DDCAPS_BANKSWITCHED
DDraw:DeleteDC 0x179e
DDraw:Taking the Win16 lock may not be necessary for VRAM locks
DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0x175e
DDraw:DeleteDC 0x179e
DDraw:Primary's rect is 0, 0, 800, 600
DDraw:HELInit for DISPLAY Driver: Reference Count = 1
DDraw:createDC(display)
DDraw:DeleteDC 0x179e
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0x175e
DDraw:DeleteDC 0x179e
DDraw:***New local allocated 82dc1b1c for global pdrv 82dc11f8
DDraw:New driver object created, interface ptr = 82dc1b84
DDraw: DirectDrawCreate succeeds, and returns ddraw pointer 82dc1b84
DDraw:New driver interface created, 82dc1bb0
DDraw:DD_AddRef, pid=fff00c89, obj=82dc1bb0
DDraw:DD_AddRef, Reference Count: Global = 2 Local = 2 Int = 1
DDraw:DD_Release, pid=fff00c89, obj=82dc1b84
DDraw:DD_Release, Ref Count: Global = 1 Local = 1 Interface = 0
DDraw:*********** ALLOWING MODE X AND VGA MODES
DDraw:DD_GetDeviceRect: display [0 0 800 600]
DDraw:Subclassing window 00000aac
DDraw:StartExclusiveMode
DDraw:******** invalidating all surfaces
DDraw:Enumerating mode 0. 640x480
DDraw:Enumerating mode 1. 800x600
DDraw:Enumerating mode 2. 1024x768
DDraw:Enumerating mode 3. 1280x1024
DDraw:Enumerating mode 4. 640x480
DDraw:Enumerating mode 5. 800x600
DDraw:Enumerating mode 6. 1024x768
DDraw:Enumerating mode 7. 640x480
DDraw:Enumerating mode 8. 800x600
DDraw:Enumerating mode 9. 320x200
DDraw:Enumerating mode 10. 320x240
DDraw:Enumerating mode 11. 320x200
DDraw:Looking for 640x480x8
DDraw:Found 640x480x8x (flags = 1)
DDraw:Found 800x600x8x (flags = 1)
DDraw:Found 1024x768x8x (flags = 1)
DDraw:Found 1280x1024x8x (flags = 1)
DDraw:Found 640x480x16x (flags = 0)
DDraw:Found 800x600x16x (flags = 0)
DDraw:Found 1024x768x16x (flags = 0)
DDraw:Found 640x480x32x (flags = 0)
DDraw:Found 800x600x32x (flags = 0)
DDraw:Found 320x200x8x (flags = 3)
DDraw:Found 320x240x8x (flags = 3)
DDraw:Found 320x200x8x (flags = 11)
DDraw:Calling HEL SetMode
DDraw:width = 640
DDraw:height = 480
DDraw:bpp = 8
DDraw:WM_DISPLAYCHANGE: 640x480x8
DDraw:DD_GetDeviceRect: display [0 0 640 480]
DDraw:WM_SIZE hWnd=AAC wp=0000, lp=01E00280
DDraw:WM_SIZE: Window restored, NOT sending WM_ACTIVATEAPP
DDraw:createDC(display)
DDraw:DeleteDC 0x1712
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0x179e
DDraw:DeleteDC 0x1712
DDraw:createDC(display)
DDraw:getDisplayMode:
DDraw: bpp=8, refresh=0
DDraw: dwHeight=480, dwWidth=640
DDraw: lStride=0
DDraw:Driver says nummodes=9
DDraw:Enum Display Settings says nummodes=9
DDraw:dwModeIndex = 0
DDraw:Masks for current mode are: 00000000 00000000 00000000
DDraw:DirectDrawObjectCreate: oldpdd == 82dc11f8, reset=1
DDraw:DIRECTDRAW object passed in = 82dc11f8
DDraw:oldpdd == 82dc11f8, reset=1
DDraw:Driver Object: 2256 base bytes
DDraw:dwReserved3 of DDrawGbl is set to 0x0
DDraw:oldpdd == NULL || reset
DDraw:Driver can't blt
DDraw:******** invalidating all surfaces
DDraw:All video memory heaps have been disabled. OS has no AGP support
DDraw:Current and Original Mode = 0
DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 0
DDraw:DDHALInfo contains D3D pointers: 00000000 00000000
DDraw:createDC(display)
DDraw:NOT Setting DDCAPS_BANKSWITCHED
DDraw:DeleteDC 0x179e
DDraw:Taking the Win16 lock may not be necessary for VRAM locks
DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0x1776
DDraw:DeleteDC 0x179e
DDraw:Primary's rect is 0, 0, 640, 480
DDraw:DeleteDC 0x1712
DDraw:Looking for 640x480x16
DDraw:Found 640x480x8x (flags = 1)
DDraw:Found 800x600x8x (flags = 1)
DDraw:Found 1024x768x8x (flags = 1)
DDraw:Found 1280x1024x8x (flags = 1)
DDraw:Found 640x480x16x (flags = 0)
DDraw:Found 800x600x16x (flags = 0)
DDraw:Found 1024x768x16x (flags = 0)
DDraw:Found 640x480x32x (flags = 0)
DDraw:Found 800x600x32x (flags = 0)
DDraw:Found 320x200x8x (flags = 3)
DDraw:Found 320x240x8x (flags = 3)
DDraw:Found 320x200x8x (flags = 11)
DDraw:Calling HEL SetMode
DDraw:width = 640
DDraw:height = 480
DDraw:bpp = 16
DDraw:Window 00000ac4 is on top of us!!
DDraw:Window 00000ac4 is on top of us!!
DDraw:Window 00000ac4 is on top of us!!
DDraw:WM_DISPLAYCHANGE: 640x480x16
DDraw:DD_GetDeviceRect: display [0 0 640 480]
DDraw:createDC(display)
DDraw:DeleteDC 0x172a
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0xc96
DDraw:DeleteDC 0x172a
DDraw:createDC(display)
DDraw:getDisplayMode:
DDraw: bpp=16, refresh=0
DDraw: dwHeight=480, dwWidth=640
DDraw: lStride=0
DDraw:Driver says nummodes=9
DDraw:Enum Display Settings says nummodes=9
DDraw:dwModeIndex = 4
DDraw:Masks for current mode are: 00007c00 000003e0 0000001f
DDraw:DirectDrawObjectCreate: oldpdd == 82dc11f8, reset=1
DDraw:DIRECTDRAW object passed in = 82dc11f8
DDraw:oldpdd == 82dc11f8, reset=1
DDraw:Driver Object: 2256 base bytes
DDraw:dwReserved3 of DDrawGbl is set to 0x0
DDraw:oldpdd == NULL || reset
DDraw:Driver can't blt
DDraw:******** invalidating all surfaces
DDraw:All video memory heaps have been disabled. OS has no AGP support
DDraw:Current and Original Mode = 4
DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 4
DDraw:DDHALInfo contains D3D pointers: 00000000 00000000
DDraw:createDC(display)
DDraw:NOT Setting DDCAPS_BANKSWITCHED
DDraw:DeleteDC 0xc96
DDraw:Taking the Win16 lock may not be necessary for VRAM locks
DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0x179e
DDraw:DeleteDC 0xc96
DDraw:Primary's rect is 0, 0, 640, 480
DDraw:DeleteDC 0x172a
DDraw:82dc1bb0->CreateSurface
DDraw: DDSURFACEDESC->dwBackBufferCount = 1
DDraw: DDSURFACEDESC->lpSurface = 00000000
DDraw: DDSCAPS_COMPLEX
DDraw: DDSCAPS_FLIP
DDraw: DDSCAPS_PRIMARYSURFACE
DDraw:******** invalidating all primary surfaces
DDraw:#### Using GDI screen bpp = 16
DDraw:*** allocating primary surface
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0x179e
DDraw:DeleteDC 0xc96
DDraw:#### Using GDI screen bpp = 16
DDraw:*** allocating a backbuffer
DDraw:HEL:About to allocate 614400 bytes for the surface
DDraw:DD_Surface_AddRef, Reference Count: Global = 1 Local = 1 Int = 1
DDraw:DD_Surface_AddRef, Reference Count: Global = 1 Local = 1 Int = 1
DDraw: CreateSurface returns 00000000 (0)
DDraw:DD_Surface_AddRef, Reference Count: Global = 2 Local = 2 Int = 2
DDraw:82dc1bb0->CreateSurface
DDraw: DDSURFACEDESC->dwHeight = 240
DDraw: DDSURFACEDESC->dwWidth = 320
DDraw: DDSURFACEDESC->lpSurface = 00000000
DDraw: DDSCAPS_OFFSCREENPLAIN
DDraw: DDSCAPS_VIDEOMEMORY
DDraw:No hardware support
DDraw: CreateSurface returns 88760233 (563)
DDraw:82dc1bb0->CreateSurface
DDraw: DDSURFACEDESC->dwHeight = 240
DDraw: DDSURFACEDESC->dwWidth = 320
DDraw: DDSURFACEDESC->lpSurface = 00000000
DDraw: DDSCAPS_OFFSCREENPLAIN
DDraw: DDSCAPS_SYSTEMMEMORY
DDraw:Forcing pixel format for explicit system memory surface
DDraw:#### Got surface pixel format bpp = 16
DDraw:*** allocating a surface 320x240x16
DDraw:HEL: About to allocate 153600 bytes for the surface of 640x240 with alignemnt 8
DDraw:DD_Surface_AddRef, Reference Count: Global = 1 Local = 1 Int = 1
DDraw: CreateSurface returns 00000000 (0)
DDraw:82dc1f74->Lock
DDraw: DDSURFACEDESC->dwHeight = 240
DDraw: DDSURFACEDESC->dwWidth = 320
DDraw: DDSURFACEDESC->lPitch = 640
DDraw: DDSURFACEDESC->lpSurface = 004b7118
DDraw:Flags:
DDraw: DDPF_RGB
DDraw: BitCount:16
DDraw: Bitmasks: R/Y:00007c00, G/U:000003e0, B/V:0000001f, Alpha/Z:00000000
DDraw: DDSCAPS_OFFSCREENPLAIN
DDraw: DDSCAPS_SYSTEMMEMORY
DDraw:WM_SIZE hWnd=AAC wp=0000, lp=01E00280
DDraw:WM_SIZE: Window restored, sending WM_ACTIVATEAPP
DDraw:WM_ACTIVATEAPP: BEGIN Activating app pid=fff00c89, tid=fff04bf1
DDraw:*** Already activated
DDraw:WM_ACTIVATEAPP: DONE Activating app pid=fff00c89, tid=fff04bf1
DDraw:Bringing window to top
DDraw:WM_ACTIVATEAPP: BEGIN Deactivating app pid=fff00c89, tid=fff04bf1
DDraw:*** Active state changing
DDraw:******** invalidating all surfaces
DDraw:INACTIVE: fff00c89: Restoring original mode (1)
DDraw:In RestoreDisplayMode
DDraw:Turning off DCI in mySetMode
DDraw:WM_DISPLAYCHANGE: 800x600x8
DDraw:DD_GetDeviceRect: display [0 0 800 600]
DDraw:WM_SIZE hWnd=AAC wp=0000, lp=02580320
DDraw:WM_SIZE: Window restored, NOT sending WM_ACTIVATEAPP
DDraw:WM_ACTIVATEAPP: BEGIN Deactivating app pid=fff00c89, tid=fff04bf1
DDraw:*** Already deactivated
DDraw:WM_ACTIVATEAPP: DONE Deactivating app pid=fff00c89, tid=fff04bf1
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0x159a
DDraw:DeleteDC 0xa4a
DDraw:RestoreDisplayMode: Process fff00c89 Mode = 4
DDraw:createDC(display)
DDraw:getDisplayMode:
DDraw: bpp=8, refresh=0
DDraw: dwHeight=600, dwWidth=800
DDraw: lStride=0
DDraw:Driver says nummodes=9
DDraw:Enum Display Settings says nummodes=9
DDraw:dwModeIndex = 1
DDraw:Masks for current mode are: 00000000 00000000 00000000
DDraw:DirectDrawObjectCreate: oldpdd == 82dc11f8, reset=1
DDraw:DIRECTDRAW object passed in = 82dc11f8
DDraw:oldpdd == 82dc11f8, reset=1
DDraw:Driver Object: 2256 base bytes
DDraw:dwReserved3 of DDrawGbl is set to 0x0
DDraw:oldpdd == NULL || reset
DDraw:Driver can't blt
DDraw:******** invalidating all surfaces
DDraw:All video memory heaps have been disabled. OS has no AGP support
DDraw:Current and Original Mode = 1
DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 1
DDraw:DDHALInfo contains D3D pointers: 00000000 00000000
DDraw:createDC(display)
DDraw:NOT Setting DDCAPS_BANKSWITCHED
DDraw:DeleteDC 0x170a
DDraw:Taking the Win16 lock may not be necessary for VRAM locks
DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8
DDraw:createDC(display)
DDraw:createDC(display)
DDraw:DeleteDC 0xaa2
DDraw:DeleteDC 0x170a
DDraw:Primary's rect is 0, 0, 800, 600
DDraw:DeleteDC 0x13ba
DDraw:Redrawing all windows
DDraw:DoneExclusiveMode
DDraw:Enabling error mode, hotkeys
DDraw:Mode was never changed by this app
DDraw:WM_ACTIVATEAPP: DONE Deactivating app pid=fff00c89, tid=fff04bf1
DDraw:DD_Surface_Release, Reference Count: Global = 0 Local = 0 Int = 0
DDraw:Deleting attachment from 82dc1e98 to 82dc1b84 (implicit = 1)
DDraw:DeleteOneAttachment: 82dc1b84,82dc1e98
DDraw:DD_Surface_AddRef, Reference Count: Global = 3 Local = 3 Int = 3
DDraw:Leaving AddRef early to prevent recursion
DDraw:DeleteOneLink: 82dc1e98,82dc1b84
DDraw:DeleteOneLink: 82dc1b84,82dc1e98
DDraw:DD_Surface_Release, Reference Count: Global = 2 Local = 2 Int = 2
DDraw:Leaving Release early to prevent recursion
DDraw:DD_Surface_Release, Reference Count: Global = 1 Local = 1 Int = 1
DDraw:DD_Surface_Release, Reference Count: Global = 0 Local = 0 Int = 0
DDraw:Freeing pointer 0042110c
DDraw:DD_Release, pid=fff00c89, obj=82dc1bb0
DDraw:DD_Release, Ref Count: Global = 0 Local = 0 Interface = 0
DDraw:Unsubclassing window 00000aac
DDraw:ProcessSurfaceCleanup
DDraw:Process fff00c89 had 1 accesses to surface 82dc1f74
DDraw:DD_Surface_Release, Reference Count: Global = 0 Local = 0 Int = 0
DDraw:Freeing pointer 004b7118
DDraw:Leaving ProcessSurfaceCleanup
DDraw:ProcessPaletteCleanup, ppal=00000000
DDraw:ProcessClipperCleanup
DDraw:Cleaning up clippers owned by driver object 0x82dc11f8
DDraw:Not cleaning up clippers not owned by a driver object
DDraw:ProcessVideoPortCleanup
DDraw:Leaving ProcessVideoPortCleanup
DDraw:Mode was never changed by this app
DDraw:FREEING DRIVER OBJECT
DDraw:Calling HEL DestroyDriver
DDraw:HEL DestroyDriver: dwHELRefCnt=0
DDraw:3 surfaces allocated - 768000 bytes total
DDraw:*********** DDHEL TIMING INFO ************
DDraw:myFlip: 30 calls, 1.365 sec (0.045)
DDraw:myLock: 1 calls, 0.000 sec (0.000)
DDraw:myUnlock: 1 calls, 0.000 sec (0.000)
DDraw:******************************************
DDraw:Frequency(cycles/second)(0) 1193180
DDraw:Blt16_SrcCopy(32): SUM = 264860
DDraw:Blt16_SrcCopy(32): COUNT = 30
DDraw:Blt16_SrcCopy(32): AVG = 8828
DDraw:Blt16_SrcCopy(32): MIN = 8572
DDraw:Blt16_SrcCopy(32): MAX = 9964
DDraw:Blt16_SrcCopy(32): Dst MB/sec = 17
DDraw:Blt16_ColorFill(47): SUM = 716435
DDraw:Blt16_ColorFill(47): COUNT = 32
DDraw:Blt16_ColorFill(47): AVG = 22388
DDraw:Blt16_ColorFill(47): MIN = 15855
DDraw:Blt16_ColorFill(47): MAX = 55858
DDraw:Blt16_ColorFill(47): Dst MB/sec = 27
DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): SUM = 263495
DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): COUNT = 30
DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): AVG = 8783
DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): MIN = 8528
DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): MAX = 9917
DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): Dst MB/sec = 17
DDraw:Driver is now FREE
DDraw:====> ENTER: DLLMAIN(baaa12c0): Process Detach fff00c89, tid=fff04bf1
DDraw:MemState
DDraw:Memory still allocated! Alloc count = 11
DDraw:Current Process (pid) = fff00c89
DDraw:82dc100c: dwSize=00000008, lpAddr=baaa1bbc (pid=fff1b349)
DDraw:82dc1054: dwSize=0000001d, lpAddr=baae5093 (pid=fff18e61)
DDraw:82dc1090: dwSize=00000019, lpAddr=baae5093 (pid=fff18e61)
DDraw:82dc10c8: dwSize=00000019, lpAddr=baae5093 (pid=fff18e61)
DDraw:82dc1100: dwSize=0000001d, lpAddr=baae5093 (pid=fff18e61)
DDraw:82dc113c: dwSize=00000018, lpAddr=baae5093 (pid=fff18e61)
DDraw:82dc1170: dwSize=00000019, lpAddr=baae5093 (pid=fff18e61)
DDraw:82dc11a8: dwSize=0000001c, lpAddr=baae52c8 (pid=fff18e61)
DDraw:82dc1030: dwSize=00000008, lpAddr=baaa1bbc (pid=fff04a0d)
DDraw:82dc1fc0: dwSize=00000008, lpAddr=baaa1bbc (pid=fff04a0d)
DDraw:82dc1c3c: dwSize=00000008, lpAddr=baaa1bbc (pid=fff00c89)
DDraw:Total Memory Unfreed From Current Process = 8 bytes
DDraw:====> EXIT: DLLMAIN(baaa12c0): Process Detach fff00c89

Оглавление книги


Генерация: 0.030. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз