Сообщение WM_COPYDATA
служит для передачи блока данных от одного процесса к другому. В 32-разрядных версиях Windows память, выделенная некоторому процессу, недоступна для всех остальных процессов. Поэтому просто передать указатель другому процессу нельзя, поскольку он не сможет получить доступ к этой области памяти. При передаче сообщения WM_COPYDATA
система копирует указанный блок из адресного пространства отправителя в адресное пространство получателя, передает получателю указатель на этот блок, и при завершении обработки сообщения освобождает блок. Все это требует определенной синхронности действий, которой невозможно достичь при посылке сообщения, поэтому с помощью WM_COPYDATA
можно только отправлять, но не посылать (т.е. можно использовать SendMessage
, но не PostMessage
).
Сообщение WM_PAINT
предназначено для перерисовки клиентской облаcти окна. Если изображение сложное, этот процесс занимает много времени, поэтому в Windows предусмотрены механизмы, минимизирующие количество перерисовок. Перерисовывать свое содержимое окно должно при получении сообщения WM_PAINT
. С каждым таким сообщением связан регион, нуждающийся в обновлении. Этот регион может совпадать с клиентской областью окна или быть ее частью. В последнем случае программа может ускорить перерисовку, рисуя не все окно, а только нуждающуюся в этом часть (VCL игнорирует возможность перерисовки только части окна, поэтому при работе с этой библиотекой окно всегда перерисовывается полностью). Послать сообщение WM_PAINT
с помощью PostMessage
окну нельзя, т.к. оно не ставится в очередь. Вместо этого можно пометить регион как нуждающийся в обновлении с помощью функций InvalidateRect
и InvalidateRgn
. Если на момент вызова этих функций регион, который необходимо обновить, не был пуст, новый регион объединяется со старым. Функции GetMessage
и PeekMessage
, если очередь сообщений пуста, а регион, требующий обновления, не пуст, возвращают сообщение WM_PAINT
. Таким образом, перерисовка окна откладывается до того момента, когда все остальные сообщения будут обработаны. Отправить WM_PAINT
с помощью SendMessage
тоже нельзя. Если требуется немедленная перерисовка окна, следует вызвать функции UpdateWindow
или RedrawWindow
, которые не только отправляют сообщение окну, но и выполняют сопутствующие действия, связанные с регионом обновления. Обработка сообщения WM_PAINT
также имеет некоторые особенности. Обработчик должен получить контекст устройства окна (см. разд. 1.1.11 данной главы) с помощью функции BeginPaint
и по окончании работы освободить его с помощью EndPaint
. Эти функции должны вызываться только один раз при обработке сообщения. Соответственно, если сообщение обрабатывается поэтапно несколькими обработчиками, как это бывает при перехвате сообщений, получать и освобождать контекст устройства должен только первый из них, а остальные должны пользоваться тем контекстом, который он получил. Система не накладывает обязательных требований, которые могли бы решить проблему, но предлагает решение, которое используют все предопределенные системные классы. Когда сообщение WM_PAINT
извлекается из очереди, его параметр wParam
равен нулю. Если же обработчик получает сообщение с wParam <> 0
, то он рассматривает значение этого параметра как дескриптор контекста устройства и использует его, вместо того чтобы получать дескриптор через BeginPaint
. Первый в цепочке обработчиков должен передать вниз по цепочке сообщение с измененным параметром wParam
. Компоненты VCL также пользуются этим решением. При перехвате сообщения WM_PAINT
это нужно учитывать.
Примеры PanelMsg и Line, имеющиеся на прилагаемом компакт-диске, демонстрируют, как правильно перехватывать сообщение WM_PAINT
.
Простые таймеры, создаваемые системой с помощью функции SetTimer
, сообщают об истечении интервала посредством сообщения WM_TIMER
. Проверка того, истек ли интервал, осуществляется внутри функций GetMessage
, PeekMessage
. Таким образом, если эти функции долго не вызываются, сообщение WM_TIMER
не ставится в очередь, даже если положенный срок истек. Если за время обработки других сообщений срок истек несколько раз, в очередь ставится только одно сообщение WM_TIMER
. Если в очереди уже есть сообщение WM_TIMER
, новое в очередь не добавляется, даже если срок истек. Таким образом, часть сообщений WM_TIMER
теряется, т.е., например, если интервал таймера установить равным одной секунде, то за час будет получено не 3600 сообщений WM_TIMER
, а меньшее число, и разница будет тем больше, чем интенсивнее программа загружает процессор.
Читать дальше
Конец ознакомительного отрывка
Купить книгу