Бедная
LockWindowUpdate
, которую никто не понимает.Это первый пост в серии про
LockWindowUpdate
, то, что она делает, то, для чего она предназначена, и (возможно, самое важное) то, для чего она не предназначена.Что
LockWindowUpdate
делает - это очень просто. Когда окно заблокировано, все попытки нарисовать что-то на нём или дочерних окнах проваливаются. Вместо рисования оконный менеджер запоминает, в каких частях окна рисовали, и обновляет эти области через отправку сообщения WM_PAINT
, когда окно разблокируется - восстанавливая этим синхронизацию между видимым на экране и логическим состоянием.Это поведение "запоминай, что приложение пыталось нарисовать, пока условие X имеет силу, и перерисуй это, когда условие X не выполняется" вы уже видели в другом обличье:
CS_SAVEBITS
. В этом смысле LockWindowUpdate
делает ту же работу учёта, которая произошла если бы вы закрыли целевое окно другим с установленным стилем CS_SAVEBITS
, но только она не сохраняет никаких пикселей.Документация совершенно чётко указывает, что только одно окно (в расчёте на рабочий стол, конечно же) может быть заблокировано в любой момент времени, но это же следует и из прототипа функции. Если два окна могли бы быть заблокированы одновременно, то вы не смогли бы однозначно использовать
LockWindowUpdate
. Что должно произойти при этом?
LockWindowUpdate(hwndA); // блокирует окно A LockWindowUpdate(hwndB); // также блокирует окно B LockWindowUpdate(0); // ???Что сделает этот третий вызов
LockWindowUpdate
? Разблокирует все окна? Или только окно A? Или только B? Не важно что вы выберите - любой ответ сделает использование следующего кода ненадёжным:
procedure BeginOperationA; begin LockWindowUpdate(hwndA); ... end; procedure EndOperationA; begin ... LockWindowUpdate(0); end; procedure BeginOperationB; begin LockWindowUpdate(hwndB); ... end; procedure EndOperationB; begin ... LockWindowUpdate(0); end;Представьте что функции
BeginOperation
начинают какие-то операции, которые запускаются асинхронно. К примеру, пусть операция A - это рисование во время drag/drop, так что она запускается, когда зажимают мышь, а заканчивается, когда мышь отпускают.Теперь предположим, что операция B заканчивается пока происходит drag/drop. Тогда
EndOperationB
должна вызвать LockWindowUpdate(0)
. Если вы предполоджили что третий вызов должен разблокировать все окна, то вы только что сломали операцию A, которая ожидает, что окно hwndA
будет заблокировано. Аналогично, если вы решили, что должно разблокироваться только окно hwndA
, то снова операция A обречена, но также и операция B (поскольку тогда hwndB
останется заблокированным, даже хотя операция B завершена). С другой стороны, если вы решили, что должно разблокироваться окно hwndB
, то рассмотрите случай, когда первой заканчивается операция A.Если бы
LockWindowUpdate
могла блокировать больше одного окна, то у неё был бы иной прототип, позволяющий узнать, какая операция завершена. Есть много способов это сделать. К примеру, у неё мог быть дополнительный параметр или обратная функция:
// Метод A - новый параметр // fLock = True для блокировки, False для разблокировки function LockWindowUpdate(wnd: HWND; fLock: BOOL): BOOL; // Метод B - отдельная функция function LockWindowUpdate(wnd: HWND): BOOL; function UnlockWindowUpdate(wnd: BOOL): BOOL;Но ни один из этих случаев не имеет места. Функция
LockWindowUpdate
блокирует только одно окно. И причина для такого дизайна станет ясна, когда мы разберём для чего предназначена LockWindowUpdate
.
Большое спасибо за прояснение. Я действительно был уверен, что LockWindowUpdate блокирует всё подряд, что в нее передаем, а потом одним махом LockWindowUpdate(0) все перерисовывается, пока не начал разбираться, почему происходит не так :)
ОтветитьУдалить