понедельник, 4 июля 2022 г.

Рано или поздно особенное перестанет быть особенным

Это перевод Eventually, nothing is special any more. Автор: Реймонд Чен.

Комментатор ulric предположил, что должны существовать две функции для получения "текущего" окна: одна для обычного повседневного использования и одна для "специального использования", когда вы хотите взаимодействовать с окнами вне вашего процесса.
Однако мне было бы проще, если бы поведение API по умолчанию заключалось в том, чтобы возвращать HWND только для текущего процесса, а приложения, которым действительно нужен HWND из (потенциально) других процессов, должны использовать другой API, который специально создан только для этого.
Это отличный пример предложения того, что Windows уже делает! Специальная функция стала настолько не особенной, что вы даже не понимаете, что она особенная.

Изначально в 16-битной Windows функцией получения "текущего" окна была GetActiveWindow. Она получала активное окно всей системы. Однако одно из основных изменений Win32 - это введение модели асинхронного ввода, при которой окна из разных очередей ввода имеют независимый ввод. Таким образом, одна программа, которая перестала реагировать на ввод, не блокирует ввод других несвязанных окон. Поэтому Win32 изменила значение GetActiveWindow, чтобы она возвращала активное окно из текущей очереди ввода.

В 16-битной Windows была только одна входная очередь, глобальная. В 32-разрядной версии Windows каждый поток (или группа потоков, присоединенных к вводу) получает собственную очередь ввода.

В результате такого изменения, когда программа переносилась из 16-битной Windows в 32-битную Windows, она не "видела" окна из других программ, когда вызывала такие функции, как GetFocus или GetActiveWindow. Как должен знать каждый программист Win32, эти состояния являются локальными для вашей входной очереди.

Хорошо, давайте посмотрим, что у нас есть сейчас. GetFocus и GetActiveWindow сообщают вам статус вашей входной очереди. Другими словами, в однопоточной программе (которая в 16-битной Windows является единственным типом программ) вызов GetActiveWindow дает вам активное окно из вашей программы. Он не возвращает активное окно из другой программы.¹ Все именно так, как предложил ulric!

Теперь давайте посмотрим на вторую половину предложения. Если программе действительно нужно получить окно из (потенциально) других процессов, ей придется использовать какую-то другую функцию, специально предназначенную именно для этого. И действительно, такая функция была добавлена: это функция GetForegroundWindow. Функция GetForegroundWindow - это и есть та самая специальная функция, предназначенная для получения окон из других процессов.

Поэтому мы сделали именно то, что рекомендовал ulric - и всё равно получился бардак. Почему?

Потому что особенное не останется особенным надолго.

Это может занять некоторое время, но в конце концов люди обнаруживают, что обычная функция "не работает" (здесь "не работает" может означать что угодно), и обращаются за помощью: "Когда я вызываю GetActiveWindow, я не получаю глобальное активное окно; мне возвращается окно моего приложения. Как мне получить глобальное?" На самом деле, они, вероятно, даже не формулируют вопрос так чётко. Скорее, это больше похоже на: "Я хочу получить активное окно, но GetActiveWindow не работает".

А потом кто-то отвечает: "Да, GetActiveWindow не работает. Я обнаружил, что GetForegroundWindow работает намного лучше".

Затем следует ответ: "Вау, отлично работает! Спасибо!"

В конце концов, даже на улице говорят: "GetActiveWindow не работает. Используйте вместо неё GetForegroundWindow". Вскоре люди используют её для всего: полируют машину, успокаивают ребенка или улучшают свою сексуальную привлекательность.

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

На самом деле немодность активного окна (active window) дошла до того, что люди вообще перестали называть его активным окном! Вместо этого они называют его окном переднего плана текущего процесса (foreground window from the current process). Это всё равно, что называть наземную линию "проводным сотовым телефоном".

Требование нового флага для получения специального поведения ничего не меняет. Это та же история, только с другими именами персонажей. "GetFocalWindow² не работает, если вы не передадите флаг GFW_CROSSPROCESS". Скоро все будут передавать GFW_CROSSPROCESS не потому, что понимают, что он делает, а просто потому, что "мне так сказали делать" и "ничего не заработает, если я его не передаду".

Примечания
¹ Предполагая, что вы не пытаетесь присоединить свой поток к входной очереди какой-либо другой программы. Это довольно безопасное предположение, поскольку функция AttachThreadInput не существовала в 16-разрядной версии Windows.

² GetFocalWindow - это воображаемая функция, созданная для примера.

Комментариев нет:

Отправить комментарий

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

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

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

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

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

Примечание. Отправлять комментарии могут только участники этого блога.