среда, 29 декабря 2010 г.

С какими операциями не предполагалось использовать LockWindowUpdate?

Это перевод With what operations is LockWindowUpdate not meant to be used? Автор: Реймонд Чен.

OK, теперь когда мы знаем для каких операций предполагалось использовать функцию LockWindowUpdate, мы можем посмотреть на разные (неправильные) способы, которыми люди её используют.

Люди видят поведение "заблокированное вами окно не будет перерисовываться" функции LockWindowUpdate и используют его вместо сообщения WM_SETREDRAW. Хотя отправка WM_SETREDRAW не намного сложнее вызова LockWindowUpdate. Это всего лишь длиннее на двадцать символов - или вполновину меньше, если использовать оболочку SetWindowRedraw.

Вместо LockWindowUpdate(Wnd)
Используйте SendMessage(Wnd, WM_SETREDRAW, 0, 0) или
SetWindowRedraw(Wnd, False)
Вместо LockWindowUpdate(0)
Используйте SendMessage(Wnd, WM_SETREDRAW, 1, 0) или
SetWindowRedraw(Wnd, True)

Как мы заметили ранее, только одно окно в системе может быть заблокировано в конкретный момент времени. Если вы вызываете LockWindowUpdate только для того, чтобы запретить окну перерисовываться (скажем, потому что вы обновляете окно и не хотите, чтобы окно постоянно перерисовывало себя, пока вы не закончите процесс обновления), то просто отключите перерисовку у этого окна отправкой WM_SETREDRAW. Если вы используете LockWindowUpdate, то у вас появляется множество неявных проблем.

Во-первых, если какая-то другая программа ошибочно использует LockWindowUpdate по тем же причинам, что и вы, то кто-то из вас обязательно проиграет. Кто вызовет LockWindowUpdate первым, тот и получит блокировку. Второй вызов будет неудачен. Что теперь будете делать? Ваше окно теперь не заблокировано.

Во-вторых, если вы заблокировали окно и пользователь переключается на другую программу и пытается выполнить операцию перетаскивания (к примеру, просто переместить окно!), то попытка вызова LockWindowUpdate во время этой операции будет неудачна, а пользователь окажется в ситуации, когда операция перемещения перестала работать на пустом месте, по каким-то загадочным причинам. А затем, секунды спустя, всё снова работает. "Глупая багнутая Windows" - пробормочет пользователь.

И наоборот: если вы вызовите LockWindowUpdate во время операции перетаскивания, то у вас ничего не сработает.

Это только один пример более общей ошибки программирования - использование глобального состояния для управления локальным условием. Когда вы хотите отключить перерисовку в одном из ваших окон, вы не хотите, чтобы это влияло на все окна в системе; это локальное условие. Но для этого вы используете глобальное состояние (блокировку окна).

Я уже могу предвидеть, как кто-то скажет: "Ну, оконный менеджер не должен всяким-разным вызывать LockWindowUpdate, если они не собираются делать операцию по перетаскиванию". Но как он узнает? Менеджер окон увидит, что сделан вызов LockWindowUpdate, но он не знает почему. Программа вызывает LockWindowUpdate, потому что она слишком ленива, чтобы вызывать вместо неё WM_SETREDRAW? Или она делает это в ответ на ввод пользователя, от которого запускается операция перетаскивания? Заметьте, что вы не можете просто сказать: "Ну, кнопка мыши должна быть нажата", потому что пользователь может выполнять эту операцию с клавиатуры (к примеру, изменение размера окна стрелочками) - это полный эквивалент обычной операции перетаскивания. Поэтому ответ на этот вопрос потребует телепатических способностей - чего-то, чем современные компьютеры пока не обладают.

В следующий раз - завершающие заметки по LockWindowUpdate.

2 комментария:

  1. > Программа вызывает LockWindowUpdate, потому что она слишком ленива, чтобы вызывать вместо неё WM_SETREDRAW?

    Потому что найти в документации LockWindowUpdate проще, чем WM_SETREDRAW. :)

    > Поэтому ответ на этот вопрос потребует телепатических способностей - чего-то, чем современные компьютеры пока не обладают.

    Да, у Microsoft ещё долго будут проблемы, пока их разработчики не научатся собирать libastral под Windows. :)

    ОтветитьУдалить
  2. По идее, надо было не поскупиться и назвать функцию LockOnlyOneWindowUpdateAtWholeSysytem. :) По крайней мере в этом случае разработчики задумались бы и, возможно, полезли бы на форумы, спрашивая - а почему только одно на всю систему, что нельзя было больше. И тогда бы нашёлся кто-нибудь, кто рассказал бы про WM_SETREDRAW и этот ответ цитировали бы по всем интернетам. :)

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.