среда, 12 ноября 2008 г.

Почему GetWindowText подчиняется таким странным правилам?

Это перевод Why are the rules for GetWindowText so weird? Автор: Реймонд Чен.

Джоэль Спольски совершенно справедливо заметил, что правила GetWindowText привносят утечку абстракции . Почему правила для GetWindowText сделаны такими странными?

Заведите свою машину времени на 1983 год.

Типичный персональный компьютер в те дни имел процессор Intel 8086, работающий с огромной скоростью 4.7 Мгц, два 5½-дюймовых дисковода для дискет на 360 Кб (или если бы были техно-гиком, то у вас был один дисковод и один винчестер на 10 Мб), и 256 Кб оперативной памяти.

Это был мир Windows 1.0.

Windows 1.0 была операционной системой с кооперативной многозадачностью. Никакой вытесняющей многозадачности. Что это значит? Это значит, что когда ваша программа получает управление, она держит процессор столько, сколько захочет. Никто не может отобрать у неё выполнение. Только когда она вызывает функцию типа PeekMessage или GetMessage, только тогда программа добровольно отдаёт процессор для выполнения других программ.

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

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

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

В том простом мире GetWindowText была простейшей заглушкой:
function GetWindowText(hWnd: HWND; lpString: PChar; nMaxCount: Integer): Integer; stdcall;
begin
  // Ах, старые деньки!
  Result := SendMessage(hWnd, WM_GETTEXT, nMaxCount, LPARAM(lpString));
end;
И это работало для любых окон. Всегда. Никаких специальных правил для чужих программ.

При переходе на Win32 вытесняющая многозадачность меняет правила игры. Впервые появляется возможность, что (удивление) окно, которому вы отправляете сообщение, может висеть.

Теперь у вас есть проблема обратной совместимости. Как я указал ранее в моей первой статье (прим.пер.: разумеется, имеется ввиду оригинал Реймонда), многие части самой системы и многие программы основывались на возможности мгновенного получения текста окна без зависания. Ну и как же нам сделать возможным получение текста без зависания и при этом сохранить возможность ручного управления текстом?

Правила Win32-версии GetWindowText и явились попыткой примирить эти два противоречивых требования.

(Аналогичная история с небольшими изменениями объясняет почему DDE работает так, как он работает сейчас. Но сегодня мало людей используют DDE, поэтому этот случай не так драматичен.)

1 комментарий:

  1. Application.ProcessMessages наверно примирит все Ваши зависшие окна

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

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

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

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

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

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