Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004

.pdf
Скачиваний:
327
Добавлен:
13.08.2013
Размер:
3.3 Mб
Скачать

ГЛАВА 16 Автоматизированное тестирование

573

 

 

Сценарии Tester

Принцип работы сценариев прост: вы создаете несколько объектов Tester, запус! каете приложение или находите его основное окно, воспроизводите ему несколько нажатий клавиш, проверяете результаты и завершаете сценарий. В листинге 16!1 представлен пример сценария VBScript, который запускает NOTEPAD.EXE, вводит несколько строк текста и закрывает Блокнот (все примеры сценариев, приведен! ные в этой главе, вы можете найти на CD).

Листинг 16-1. Сценарий MINIMAL.VBS поясняет работу с часто используемыми объектами Tester

'Минимальный пример сценария Tester на VBScript. Он просто запускает

'Notepad, вводит несколько строк текста и закрывает Notepad.

'Получение системного объекта и объекта ввода.

Dim tSystem

Dim tInput

Dim tWin

Set tSystem = WScript.CreateObject ( "Tester.TSystem" )

Set tInput = WScript.CreateObject ( "Tester.TInput" )

'Запуск Notepad. tSystem.Execute "NOTEPAD.EXE"

'Подождать 3 секунды. tSystem.Sleep 3.0

'Попытка найти основное окно Notepad.

Set tWin = tSystem.FindTopTWindowByTitle ( "Untitled Notepad" )

If ( tWin Is Nothing ) Then

MsgBox "Unable to find Notepad!"

WScript.Quit

End If

'Гарантия того, что Notepad работает в активном режиме. tWin.SetForegroundTWindow

'Ввод чего нибудь.

tInput.PlayInput "Be all you can be!~~~" ' Еще раз.

tInput.PlayInput "Put on your boots and parachutes....~~~"

' И еще.

tInput.PlayInput "Silver wings upon their chests.....~~~"

' Подождать 3 секунды. tSystem.Sleep 3.0

' Закрыть Notepad. tInput.PlayInput "%FX" tSystem.Sleep 2.0 tInput.PlayInput "{TAB}~"

' Сценарий выполнен!

574ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

Влистинге 16!1 вы можете увидеть три объекта, чаще всего используемых Tester. Объект TSystem позволяет находить окна верхнего уровня, запускать приложения и приостанавливать тестирование. Объект TWindow, возвращаемый в листинге 16!1 методом FindTopTWindowByTitle, — главная рабочая лошадка и является оболочкой для HWND, включающей все виды свойств окна, которые вам могут понадобиться. Кроме того, TWindow умеет находить все дочерние окна, относящиеся к конкрет! ному родительскому окну. Последний объект в листинге 16!1 — объект TInput, поддерживающий единственный метод PlayInput для воспроизведения нажатий клавиш окну с фокусом.

Влистинге 16!2 представлен тест на языке VBScript, поясняющий работу с объектом TNotify. Одна из самых сложных проблем при разработке сценариев автоматизации тестирования связана с появлением неожиданного окна, такого как информационное окно ASSERT. Объект TNotify позволяет предоставить обработчик таких непредвиденных событий. Несложный сценарий, показанный в листинге 16!2, просто следит за любыми окнами, содержащими в заголовке слово «Notepad». Скорее всего класс TNotify вам понадобится нечасто, но порой он по!настоящему нужен.

Листинг 16-2. Сценарий HANDLERS.VBS демонстрирует использование объекта TNotify

'Тест VBScript, иллюстрирующий обработку оконных уведомлений

'Константы, передаваемые в метод TNotify.AddNotification.

Const antDestroyWindow

= 1

Const antCreateWindow

= 2

Const antCreateAndDestroy

= 3

Const ansExactMatch

= 0

Const ansBeginMatch

= 1

Const ansAnyLocMatch

= 2

' Получение системного объекта и объекта ввода.

Dim tSystem

Dim tInput

Set tSystem = WScript.CreateObject ( "Tester.TSystem" )

Set tInput = WScript.CreateObject ( "Tester.TInput" )

' Переменная для объекта TNotify.

Dim

Notifier

 

' Создание объекта TNotify.

 

Set

Notifier = _

 

 

WScript.CreateObject ( "Tester.TNotify"

, _

 

"NotepadNotification"

)

'Добавление интересующих меня уведомлений. В данном случае мне

'нужны уведомления об уничтожении и создании окна. Все возможные

'комбинации уведомлений вы найдете в исходном коде TNotify.

ГЛАВА 16 Автоматизированное тестирование

575

 

 

Notifier.AddNotification antCreateAndDestroy , _

ansAnyLocMatch

, _

"Notepad"

'Запуск Notepad. tSystem.Execute "NOTEPAD.EXE"

'Пауза на 1 секунду. tSystem.Sleep 1.0

'Поскольку модель разделенных потоков небезопасна с точки зрения

'потоков, я использую в схеме уведомлений таймер. Однако сообщение

'может быть заблокировано, поскольку вся обработка ограничивается

'одним потоком. Эта функция позволяет вручную проверить уведомления

'о создании и уничтожении окна.

Notifier.CheckNotification

'Информационное окно процедуры NotepadNotification_CreateWindow

'вызывает блокировку, поэтому код завершения Notepad не будет

'выполнен, пока оно не будет закрыто.

tInput.PlayInput "%FX" tSystem.Sleep 1.0

'Еще одна проверка уведомлений. Notifier.CheckNotification

'Я даю TNotify шанс на перехват сообщения об уничтожении окна. tSystem.Sleep 1.0

'Отключение уведомлений. Если при работе с WSH этого

'не сделать, объект не будет уничтожен, и уведомления

'в таблице уведомлений останутся в активном состоянии. WScript.DisconnectObject Notifier

Set Notifier = Nothing

WScript.Quit

Sub NotepadNotificationCreateWindow ( tWin )

MsgBox ( "Notepad was created!!" )

End Sub

Sub NotepadNotificationDestroyWindow ( )

MsgBox ( "Notepad has gone away...." )

End Sub

Время от времени нужно вызывать метод CheckNotification объекта TNotify (при! чины этого я объясню в разделе «Реализация Tester»). Периодический вызов ме! тода CheckNotification гарантирует поступление уведомлений, даже если в выбранном

576 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

вами языке нет цикла сообщений. Листинг 16!2 иллюстрирует использование информационных окон (message box) в процедурах уведомлений, однако вам, вероятно, не захочется включать в реальные сценарии вызовы информационных окон, потому что они могут вызвать проблемы, неожиданно изменяя окно с фо! кусом.

Помните также, что я позволяю задать только ограниченное число уведомле! ний — пять, поэтому вам не следует использовать TNotify для общих задач сцена! риев, таких как ожидание появления окна сохранения файла. TNotify следует при! менять только для обработки неожиданных окон. Вы можете определить свои обработчики уведомлений и параметры поиска текста в заголовке окна так, что будете получать уведомления для окон, в которых вы не заинтересованы. Скорее всего вы будете получать нежелательные уведомления при использовании общих строк, таких как «Notepad», и указании, что строка может находиться в любом месте заголовка окна. Для избежания нежелательных уведомлений методу AddNotification объекта TNotify надо передавать как можно более специфичную информацию. Кроме того, в процедурах обработки события CreateWindow следует изучать полу! чаемый объект TWindow, чтобы можно было проверить, то ли это окно, которое вам нужно. В процедурах события DestroyWindow, обрабатывающих общие уведомления, следует выполнять поиск открытых окон, чтобы гарантировать, что интересую! щее вас окно больше не существует.

На CD есть и другие примеры, которые помогут вам лучше разобраться в ра! боте с Tester. NPAD_TEST.VBS — это более полный тест VBScript, включающий не! которые повторно используемые блоки. PAINTBRUSH.JS иллюстрирует воспроиз! ведение манипуляций с мышью, не зависящее от разрешения экрана. Его выпол! нение требует некоторого времени, однако результат того стоит. TesterTester — это основной блочный тест для COM!объекта Tester. Эта программа написана на C# и расположена в каталоге Tester\Tester\Tests\TesterTester. Изучив ее, вы получите представление о том, как использовать Tester вместе с .NET. Кроме того, пример TesterTester демонстрирует работу с объектом TWindows — коллекцией объектов

TWindow.

Хотя я предпочитаю писать свои блочные тесты на языках JScript и VBScript, я понимаю, что иногда это довольно трудно. Языки сценариев не позволяют конт! ролировать тип переменных и не включают редактор IntelliSense, такой как ре! дактор C# в Visual Studio .NET, поэтому вам придется вернуться к старому стилю отладки — «запустить и ошибиться». Языки сценариев нравятся мне в первую очередь тем, что они не требуют компиляции тестов. Если вы работаете с гибкой средой сборки программы, в которой легко создавать другие двоичные файлы в дополнение к главному приложению, вы можете применять .NET, создавая тесты вместе со сборкой своего приложения. Конечно, Tester не ограничивает вас про! стейшими языками тестирования. Если вам удобней писать тесты на C или Microsoft Macro Assembler (MASM) — пожалуйста.

Использовать объекты Tester довольно просто, однако реальная работа состо! ит в планировании тестов. Ваши тесты должны быть максимально конкретными и простыми. Когда я только приступал к автоматизации своих блочных тестов в начале карьеры, я пытался включить в них побольше функций. Теперь каждый мой сценарий тестирует только одну операцию. В качестве хорошего примера такого

ГЛАВА 16 Автоматизированное тестирование

577

 

 

сценария можно привести тест открытия файла. Для повторного использования сценариев вы можете объединить их самыми разными способами. Например, как только вы напишете сценарий открытия файла, вы сможете включить его в три различных теста: тест открытия существующего файла, тест открытия несуществу! ющего файла и тест открытия поврежденного файла. Как и при разработке обычных программ, следует избегать включения в тесты жестко закодированных строк. Это не только облегчит интернационализацию сценария, но и упростит его адапта! цию к очередной версии системы меню и комбинаций управляющих клавиш (accelerator).

При разработке сценариев Tester нужно предусмотреть и способы проверки того, что сценарии на самом деле работают. Если вам нечем заняться, можете просто сидеть и следить за их выполнением, сравнивая результаты каждого запуска. Од! нако лучше было бы записывать основные состояния и точки сценария, чтобы сравнение результатов можно было проводить автоматически. Если для выполне! ния сценариев вы используете CSCRIPT.EXE, можете перенаправить вывод в файл методом WScript.Echo. По завершении сценария вы можете сравнить разные вер! сии полученных файлов утилитой нахождения различий версий (такой как WinDiff) и узнать, корректно ли выполнился сценарий. Помните: записываемая информа! ция должна быть нормализованной и не зависящей от деталей конкретного за! пуска сценария. Так, если вы работаете над приложением, загружающим из сети курсы акций, не следует записывать в файл время последнего обновления курса.

Что сказать об отладке сценариев Tester? Tester не включает собственного ин! тегрированного отладчика, поэтому вам понадобятся другие средства отладки, до! ступные для языка, на котором написан сценарий. Отлаживая сценарий, старай! тесь не прерываться на вызове метода PlayInput объекта Tinput, потому что при остановке на этом методе нажатия клавиш будут воспроизведены неправильному окну. Для решения этой потенциальной проблемы я обычно перед каждым вызо! вом PlayInput перемещаю окно, которому посылаю нажатия клавиш, на вершину z!порядка, вызывая метод SetForegroundTWindow объекта TWindow. Это позволяет мне прерваться на вызове SetForegroundTWindow и проверить состояние приложения, не вызывая ошибок воспроизведения нажатий клавиш.

Запись сценариев

Теперь вы понимаете работу объектов Tester и знаете, как их вызывать из собствен! ных сценариев, поэтому я хочу перейти к рассмотрению программы TESTREC.EXE, которую вы будете применять для записи взаимодействия со своими приложени! ями. Запустив TESTREC.EXE в первый раз, вы заметите, что это текстовый редак! тор, который уже при запуске генерирует некоторый объем кода. По умолчанию сценарии создаются на языке JScript, но чуть ниже я покажу, как изменить его на VBScript. Для начала записи нужно нажать на панели инструментов кнопку Record (запись) или клавиши Ctrl+R.

При записи сценария TESTREC.EXE минимизируется и изменяет заголовок на «RECORDING!», давая вам знать о происходящем. Остановить запись можно несколь! кими способами. Самый простой — сделать TESTREC.EXE активной программой, нажав Alt+Tab или выбрав ее на панели задач. Запись сценария также остановит! ся при нажатии Ctrl+Break или Ctrl+Alt+Delete; первый вариант упоминается в

578 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

документации к функциям!ловушкам, а второй позволяет принудительно завер! шить все активные ловушки записи журнала (journaling hooks), при помощи ко! торых TESTREC.EXE колдует.

Прежде чем приступить к записи своих многочисленных сценариев, вы долж! ны составить некоторый план, чтобы полностью задействовать преимущества Tester. Хотя Tester умеет обрабатывать и воспроизводить манипуляции с мышью, ваши сценарии будут гораздо более надежными, если все действия вы будете выполнять при помощи клавиатуры. Одно из достоинств Tester в том, что при записи сцена! рия он внимательно следит за тем, какому окну принадлежит фокус. По умолча! нию перед обработкой одиночных и двойных щелчков мыши Tester генерирует код, устанавливающий фокус на окно верхнего уровня. Кроме того, при записи действий с клавиатурой Tester отслеживает комбинацию Alt+Tab, также устанав! ливая фокус.

Так как запись всех событий мыши может привести к получению просто ог! ромного сценария, по умолчанию TESTREC.EXE записывает только одиночные, двойные щелчки и перемещение курсора на каждые 50 пикселов при нажатой клавише. Конечно, я позволяю точно указать параметры записи сценариев. Диа! логовое окно Script Recording Options (параметры записи сценариев) программы TESTREC.EXE, показанное на рис. 16!1, доступно при нажатии Ctrl+T или выборе пункта Script Options (параметры сценария) из меню Scripts (сценарии). На ри! сунке все пункты имеют значения по умолчанию.

Рис. 16 1. Параметры записи сценариев Tester

В самой верхней части окна Script Recording Options вы можете выбрать язык записи новых сценариев: JScript или VBScript. Установленный по умолчанию флажок Record For Multiple Monitor Playback (запись сценария для воспроизведения на нескольких мониторах), включает в сценарий вызовы метода TSystem.CheckVirtual Resolution, настраивающие размер экрана для последующих записываемых дей! ствий. Если этот флажок убрать, при нажатии кнопок мыши и доступе к точкам вне основного монитора запись будет прерываться. Возможно, вам следует отклю! чить эту функцию, если вы планируете запускать записанные сценарии на несколь!

ГЛАВА 16 Автоматизированное тестирование

579

 

 

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

Если вы создаете сценарий, включающий интенсивную работу с мышью, и желаете записать все движения мыши между нажатием и отпусканием ее клавиш, задайте в поле Minimum Pixels To Drag Before Generating A MOVETO (минималь! ное число пикселов, после которого при перетаскивании генерируется команда MOVETO) значение 0. Если вы собираетесь записать много нажатий кнопок мыши без передачи фокуса другим приложениям, снимите флажок Record Focus Changes With Mouse Clicks And Double Clicks (записывать изменения фокуса при одиноч! ных и двойных щелчках мыши). Благодаря этому TESTREC.EXE не будет генери! ровать код, форсирующий установку фокуса при каждом щелчке, что сделает ваши сценарии гораздо меньше.

При заданном флажке Do Child Focus Attempt In Scripts (выполнять попытку установки фокуса на дочернем окне) в сценарий добавляется код, пытающийся установить фокус на конкретном элементе управления или дочернем окне, в ко! тором вы щелкаете. По умолчанию этот параметр отключен, так как я генерирую команды установки фокуса на окне верхнего уровня. Такие приложения, как Notepad имеют только одно дочернее окно, однако многие другие программы характери! зуются глубоко вложенной иерархией окон, и отслеживание дочерних окон мо! жет быть сложным, когда все родительские окна не имеют заголовков и уникаль! ных классов. Изучите, например, иерархию окон редактора Visual Studio .NET при помощи утилиты Spy++. Я обнаружил, что установка фокуса на окне верхнего уров! ня перед генерированием кода нажатия кнопки мыши, как правило, работает от! лично.

Наконец, параметр Seconds To Wait Before Inserting SLEEP Statements (число секунд перед включением команд SLEEP) автоматически включает в сценарий паузы, превышающие указанное значение в секундах. Обычно вы будете хотеть, чтобы сценарии выполнялись максимально быстро, однако дополнительная пауза помо! жет скоординировать сценарии.

Сценарии Tester поддерживают тот же формат записи и воспроизведения дан! ных, что и класс .NET System.Windows.Forms.SendKeys, кроме параметра повторения клавиш. Для обработки событий мыши я расширил формат, включив в него команду повторения, а также модификаторы формата, необходимые для использования вместе с ней клавиш Ctrl, Alt и Shift. Формат команд мыши, передаваемых методу TInput.PlayInput, описан в табл. 16!1.

Табл. 16-1. Команды мыши, передаваемые методу TInput.PlayInput

Команда

Использование

MOVETO

 

{MOVETO x , y}

BTNDOWN

{BTNDOWN btn , x , y}

BTNUP

 

{BTNUP btn , x , y}

CLICK

 

{CLICK btn , x , y}

DBLCLICK

{DBLCLICK btn , x , y}

SHIFT

DOWN

{SHIFT DOWN}

SHIFT

UP

{SHIFT UP}

см. след. стр.

580

ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

 

 

Табл. 16-1.

Команды мыши … (продолжение)

 

 

Команда

Использование

CTRL

DOWN

{CTRL DOWN}

CTRL

UP

{CTRL UP}

ALT

DOWN

{ALT DOWN}

ALT

UP

{ALT UP}

 

 

btn: LEFT, RIGHT, MIDDLE

x: координата экрана X y: координата экрана Y

Есть некоторые функции мыши, которые я не смог реализовать. Во!первых, это обработка колесика. Я использовал ловушку записи журнала для перехвата дей! ствий с клавиатурой и мышью и смог получать сообщения о вращении колесика. Но, увы, из!за ошибки в функции!ловушке нет возможности узнать направление вращения колесика. Во!вторых, я не смог реализовать обработку новых клавиш X1 и X2, имеющихся на мыши Microsoft Explorer. Соответствующие сообщения WM_XBUTTON* содержат данные о нажатой клавише в старшем слове wParam. Так как сообщение WM_MOUSEWHEEL хранит направление вращения колесика там же, но фун! кция!ловушка эту информацию не получает, я сомневаюсь, чтобы в случае кноп! ки X ситуация чем!нибудь отличалась.

Реализация Tester

Вы уже представляете, как записывать и воспроизводить при помощи Tester сцена! рии автоматизации тестирования, поэтому я перейду к некоторым более существен! ным вопросам его реализации. Просуммировав объем исходных и двоичных фай! лов Tester, включая TESTER.DLL и TESTREC.EXE, вы увидите, что Tester — самая крупная, а кроме того, и самая сложная утилита в этой книге из!за COM, рекур! сивного синтаксического разбора и фоновых таймеров.

Уведомления и воспроизведение файлов в TESTER.DLL

В первом издании книги я реализовал TESTER.DLL на Visual Basic 6, потому что в то время язык и среда разработки Visual Basic 6 пользовались при работе с COM наибольшей популярностью. Однако я не хотел требовать от вас установки Visual Basic 6 только для компиляции одной DLL для COM. Прежде всего я решил пере! нести код TESTER.DLL на платформу .NET. Так как модуль воспроизведения собы! тий клавиатуры был написана на C++, я решил, что будет проще переписать часть Tester, реализованную на Visual Basic 6, на C++, задействовав при этом преимуще! ства новой технологии программирования COM на базе атрибутов (attributed COM programming).

В целом модель COM на базе атрибутов очень удобна, но мне потребовалось некоторое время для обнаружения атрибута idl_quote, необходимого для поддер! жки объявлений интерфейсов. Очень приятным сюрпризом при работе с COM на базе атрибутов оказалась чистота комбинирования языков IDL/ODL и кода C++. Кроме того, благодаря значительно улучшенным мастерам облегчилось добавле!

ГЛАВА 16 Автоматизированное тестирование

581

 

 

ние интерфейсов и их методов и свойств. Я хорошо помню, сколько времени ухо! дило на решение проблем с мастерами в предыдущих версиях Visual Studio.

Когда я только задумывал утилиту автоматизированного воспроизведения, я полагал, что могу использовать функцию SendKeys языка Visual Basic 6. Однако после тестирования я обнаружил, что такая реализация неудовлетворительна, так как она некорректно посылает события клавиатуры таким программам, как Microsoft Outlook. Это означало, что мне нужно было написать собственную функцию, ко! торая правильно посылала бы события клавиатуры и позволяла в будущем реали! зовать воспроизведение событий мыши. К счастью, я натолкнулся на функцию SendInput, поддерживаемую технологией Microsoft Active Accessibility (MSAA), и заменил ею все предыдущие низкоуровневые функции обработки событий, такие как keybd_event. Кроме того, функция SendInput помещает всю вводимую инфор! мацию в поток ввода клавиатуры или мыши в виде непрерывного блока, гаранти! руя, что вводимые вами данные не будут перемешаны с посторонней пользова! тельской информацией. Эта возможность была особенно привлекательной для Tester.

Как только я узнал, как правильно посылать нажатия клавиш, мне нужно было разработать формат их ввода. Функция SendKeys языка Visual Basic 6 или класс System.Windows.Forms.SendKeys платформы .NET уже предоставляли отличный фор! мат ввода, поэтому я решил воспроизвести его в своей функции PlayInput. Я ис! пользовал все, кроме кода повтора клавиш, и, как уже говорилось, расширил формат, включив в него поддержку воспроизведения событий мыши. В коде синтаксичес! кого разбора нет ничего особо интересного, но если вам захочется его изучить, вы найдете его на CD в файле Tester\Tester\ParsePlayInputString.CPP. Если вам за! хочется увидеть его в действии, можете проработать в отладчике программу Parse! PlayKeysTest из каталога Tester\Tester\Tests\ParsePlayKeysTest. Как можно догадать! ся по имени программы, это один из блочных тестов для Tester DLL.

Объекты TWindow, TWindows и TSystem просты, и вы сможете разобраться в их ра! боте по исходному коду. Эти три класса являются по сути оболочками для соот! ветствующих API!функций Windows. Единственный более!менее интересный ас! пект их реализации заключался в написании кода, гарантирующего, что методы

TWindow.SetFocusTWindow и TSystem.SetSpecificFocus могут сделать окно активным. Для этого они до установки фокуса выполняют присоединение к потоку вывода при помощи API!функции AttachThreadInput.

С некоторыми интересными проблемами я столкнулся при написании класса TNotify. Когда я только начал думать о том, что нужно для определения создания или уничтожения окна с конкретным заголовком, я не ожидал, что создать такой класс будет настолько трудно. Кроме того, я обнаружил, что уведомления о создании окон невозможно сделать надежными, не приложив героических усилий.

Моя первая идея заключалась в реализации системной ловушки для приложе! ний компьютерной профессиональной подготовки [computer!based training (CBT) hook]. В документации SDK подразумевается, что ловушка CBT — лучший метод перехвата событий создания и уничтожения окон. Я быстро написал пример, но вскоре столкнулся с неприятностями. Когда моя ловушка получала уведомление HCBT_CREATEWND, я не всегда мог узнать заголовок окна. По непродолжительном раз!

582 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

мышлении проблема начала обретать смысл: вероятно, ловушка CBT вызывалась во время обработки сообщения WM_CREATE, и очень немногие окна имели в этот момент установленные заголовки. Единственным типом окон, заголовки которых я мог надежно получать при помощи уведомления HCBT_CREATEWND, были диалого! вые окна. В то же время с уничтожением окон при использовании ловушки CBT все было в порядке.

Просмотрев остальные типы ловушек, я расширил свой пример и попробовал их в действии. Как я и подозревал, простое отслеживание WM_CREATE не обеспечи! вало надежного получения заголовка окна. Один друг предложил мне наблюдать только за сообщениями WM_SETTEXT, так как именно его в конечном счете исполь! зуют для установки заголовка почти все окна. Конечно, если вы рисуете в некли! ентской области окна или выполняете битовый перенос (bit blitting), вы не буде! те использовать сообщение WM_SETTEXT. По ходу дела я заметил одну интересную деталь: некоторые программы, в частности Microsoft Internet Explorer, посылают сообщения WM_SETTEXT с одним и тем же текстом много раз подряд.

Поняв, что мне нужно следить за сообщениями WM_SETTEXT, я внимательней рассмотрел типы ловушек, которые мог установить. В конце концов наилучшим вариантом оказалась ловушка вызова оконной процедуры (WH_CALLWNDPROCRET). Она позволяет с легкостью наблюдать за сообщениями WM_CREATE и WM_SETTEXT, а также за сообщениями WM_DESTROY. Сначала я полагал, что с WM_DESTROY будут некоторые проблемы, так как думал, что заголовок окна может быть уничтожен до получе! ния этого сообщения. К счастью, оказалось, что заголовок окна корректен вплоть до получения сообщения WM_NCDESTROY.

Рассмотрев плюсы и минусы обработки сообщений WM_SETTEXT только для тех окон, которые еще не имеют заголовка, я решил поступить проще и обрабаты! вать все сообщения WM_SETTEXT. Альтернативным вариантом могло бы быть созда! ние конечного автомата для отслеживания созданных окон и времени установки ими своих заголовков; это решение казалось безошибочным, однако в то же вре! мя сложным в реализации. Недостаток обработки всех сообщений WM_SETTEXT в том, что вы можете получить много уведомлений о создании одного окна. Например, если вы установите обработчик TNotify для окон, содержащих в заголовке слово «Notepad», вы будете получать уведомления не только при запуске NOTEPAD.EXE, но и при каждом открытии им нового файла. В итоге я предпочел смириться с не самой лучшей реализацией, но не проводить многие дни за отладкой «правиль! ного» решения. Кроме того, написание ловушки охватывало реализацию итого! вого класса TNotify только на четверть; остальные три четверти были посвящены уведомлению пользователя о создании и уничтожении окон.

Выше я упоминал, что использование объекта TNotify связано с некоторыми неудобствами: время от времени вы должны вызывать метод CheckNotification. Необходимость периодического вызова CheckNotification объясняется тем, что Tester поддерживает только модель разделенных потоков, которая не может быть мно! гопоточной; так что мне нужен был механизм проверки создания и уничтожения окон, работающий в том же потоке, что и оставшаяся часть Tester.

Рассмотрев некоторые аспекты механизма уведомлений, я ограничил требо! вания следующими базовыми факторами.

Соседние файлы в предмете Программирование на C++