Pull to refresh

Comments 61

Никогда еще так не издевались над хуками, как в этом рассказе, обозвав их «крюки»…
Да ладно вам, вы когда слово «hook» читаете оно у вас как внутри переводится? Hook — это крюк и есть.
Да, но есть термины, которые лучше не переводить (а то получится 1С). А читая статью, постоянно в голове было не WinAPI, а чье-то лицо.
Вы так говорите, как будто 1С это что-то плохое
Вы не поверите, но самый изысканный мат я слышал от двух человек: от прораба на стройке за окном, когда у них кран упал, и от знакомого одинэсника при переходе с семерки на восьмерку.
Сам с 1С хоть и не работал почти (за исключением небольшого курса в колледже), но от «Битрикса» в шоке до сих пор.
И это всё потому что в 1С операторы русскими буквами называются? Я в Экселе формулы по-русски пишу и никто не умер.
Вот кстати единственная вещь которая меня крайне раздражает в экселе так это русские слова в формулах. Например долго думал как майкрософт конкатенцию обозвали, перепробовал все возможные вариации, а нет же… оказалось сцепить.
Прораб на стройке бы вас не понял. Он то знает, что вагоны на жд станции, которая через забор, сцепляют, а не конкатенируют. Его сосед Василий, с которым они вчера выпивали, работает сцепщиком, у него в трудовой книжке так и написано.

:)
1с и битрикс имеют между собой общего только компанию 1с, которая купила компанию битрикс. А переход с семерки на восьмерку — это как переход с винапи на дотнет, и мат вашего товарища характеризует его не лучшим образом.
Применительно к IT, слово «hook», скорее, следует понимать как «ловушка», а еще лучше — как «хук» (а ля — не переводить).
Значит «ловушка», но я никогда не пойму зачем ссать и не использовать русские слова, вместо английских.
Может быть, поэтому? Гораздо лучше использовать общеупотребительные термины на английском и понимаемым любым иностранцем.
Почему «поэтому»? Вам непривычно видеть язык программирования на родном языке, потому что вы никогда с таким много не работали? Ну и что? Я в Советском Союзе родился и изучал программирование в том числе по программам на «Рапире», которые в «Науке и Жизни» печатали.

Наши специалисты, мешающие английские и русские слова звучат примерно как татары или башкиры, мешающие свой родной язык с русскими вкраплениями. Вот, послушайте пример (и мульфильм посмотрите, он стоит того, по-моему): www.youtube.com/watch?v=vTooxATVw9o
Английским языком владеет гораздо больше технически подкованных людей, чем русским. Большая часть документации пишется тоже на английском. Некоторые термины сложно перевести на русский (long double — «длинное двойное»?), а некоторые имеют несколько переводов, с которыми может возникать путаница (например, thread переводят и как «нить», но чаще как «поток», но stream — тоже «поток»).
Вдобавок у большинства современных языков программирования схожий синтаксис, и зная один, можно быстрее освоить другой. Но вот незадача — синтаксис практически у всех языков англоязычный. Русскоязычный синтаксис мало того, что придется осваивать заново, так на нем меньше людей будут писать просто потому, что они не знают русских букв. А значит, меньше людей будет работать с этим языком, меньше информации по нему в сети, выше порог вхождения.
Когда английский язык уже давно стандарт де-факто в программировании, языки программирования с иными национальными алфавитами просто не нужны.
long double — «длинное двойное»?
В чём проблема? Почему нет?

Вы много букв написали, но я так и не понял почему лучше говорить на смеси русского и плохого английского, чем на русском? Всё равно эту смесь никто из англоговорящих не поймёт.

Я и не призываю переводить языки на русский, я просто не вижу в этом ничего страшного или странного.
В том-то и проблема, что лучше плохой английский, чем никакого. Просто потому, что у английского языка больше аудитория и шанс в случае чего получить ответ на свой вопрос гораздо выше.
Речь не о плохом английском, а о смеси русского и плохого английского. Никакой англоговорящий не поймёт это.
Да причем тут смесь? В самом начале разговор шел о том, что термины типа hook лучше не переводить, а транслитерировать.
Потому что «поставить хук» — это и есть смесь русского и плохого английского.
Нет, позвольте. Если уж писать программы на русском, то давайте не забывать про спряжения, склонения и падежи. Мне искренне жаль англичан, язык которых так безобразно коверкают программы на всяких Паскалях и Бейсиках
Единственным правильным ответом на вопрос «почему нужно писать правильно, грамотно и не коверкая слова языка, на котором пишешь?» является тот факт, что такой правильно написанный текст является гораздо более удобным для восприятия другими людьми. Это единственный правильный ответ, больше нет. Все остальные ответы несколько идиотски выглядят. Самый любимый мною вариант «потому что есть правила» — чушь же. Ну какой смысл соблюдать правила того языка, который был образован благодаря многократному нарушению правил другого языка?

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

Вон, выше был пример с железнодорожной станцией и словами «сцепить»/«конкатенировать». В отношении вагонов человеку привычно слово «сцепить». В отношении слов «конкатенировать» (это уж если мы начинаем переводить название функции на русский), в тексте же можно просто написать что-то типа «объединить», «сложить» — в общем, зависит от фантазии. Тут важно чувства контекста — интуитивное понимание, будет ли ваш перевод понятен вашей целевой аудитории.

И если переведенный кусочек текста (слово, словосочетание, может даже предложение) становится менее понятным для вашей целевой аудитории, нежели до перевода — может, ну его нахер, этот перевод? Не человек для языка, а язык для человека.
Вы так оперируете словом «привычно», как будто это данность свыше. Сегодня «хук» привычно, завтра — «крюк». Причём те ребята, которые не хотят, чтобы язык почём зря разрастался, могут приложить усилия, что привычным стал «крюк».
Эх, я тогда ржал дико. Когда читал тут прикол, на дворе ещё windows 95 стоял
По-моему, хабр не место для подобного изложения информации.
UFO just landed and posted this here
А вот мне понравилось, основную мысль можно было конечно уместить в три строчки и копипаст кода. Но этот диалог я лично прочитал с удовольствием, и вынес для себя нечто полезное.
И мне понравилось. Даже представил, как советские Ватсон и Холмс обсуждают WinAPI сидя в своих огромных креслах.
Если бы хуки, не обозвали крюками, то вполне хорошо, но крюки конечно рвут шаблон.
В: Шерлок, здесь кто-то пытается объяснить, как должен выглядеть Хабр.
Ш: Школота, Ватсон, школота…
Осмелюсь поправить — Х. а не Ш.
Иначе получатся, что школота говорит о себе.
Все правильно — не дав Холмсу высказаться, полезла первой =).
А мне понравился стиль изложения, и суть статьи решает конкретную техническую проблему. Если бы еще каждый раз, натыкаясь на слово «оконный крюк», подсознание не выдавало мне ассоциацию с «невозбранно жмякнуть мышою»…
А как же заключительная часть диалога:
В: Холмс, а что вы курите, раз у вас возникают такие вопросы вместо простого использования SendMessage?
Х: Ватсон, а не выкурить ли нам еще по рюмочке редмонтовского чаю?
В: Холмс, вы же знаете, что я как доктор, выступаю за здоровый кодинг.
Ещё так можно:

В: Кажется, миссис Хадсон загорелась
Х: Ах, чёрт. Опять врата в ад открылись. Каждый раз такое, когда я начинаю разбираться с недокументированными возможностями windows API
Нет… нет… всё должно закончиться тем что Шерлок падает с Рейхенбахского водопада ))
создаст в специальном временном файле

Пайпы для этого придумали.

Да и вообще, мне кажется, можно в главном приложении локнуть какой-нибудь именованный семафор, во внедряемой либе — сразу после установки хука стартануть поток, который попытается локнуть тот же семафор, а после этого — сразу сделать UnloadLibrary. В итоге, когда нам понадобится снять хук и выгрузить либу — просто освобождаем семафор, поток в хукнутом процессе проходит заблокированную секцию кода и выгружает либу. Никаких тебе временных файлов.
Нельзя делать UnloadLibrary для той библиотеки, которую ты не загружал
Если начитаться wasm.ru, то еще и не такие чудеса можно делать.
Главное приложение читает через пайпу иды закрюкованных нитей и хранит их в памяти. Затем пользователь убивает его зачем-нибудь и запускает вновь. Новый экземпляр не имеет права ставить крюк, пока не убедится, что DLL выгружен из всех процессов. Как он это сделает?

Запускать чуждую нить в каждом UI-процессе на рабочем столе? Опасно. Есть шансы, пусть и небольшие, получить побочный эффект, редкий и трудноуловимый. Но это ерунда. Вы выгрузили DLL, а User32 думает, что она загружена, и вызывает её код.
Если вопрос только в том, как организовать межпроцессное взаимодействие — так для этого 150 тыщ библиотек есть. В одном вон только бусте наверное способов 5 реализовано. И всё там прекрасно разруливается и с упавшими клиентами в том числе.

Запускать чужую нить в каждом UI-процессе опасно? Ну да. А вешать хуки в каждый UI-процесс — типа нет?

Вот по поводу того, что User32 из-за своих багов будет продолжать думать, что она загружена — тут да, возразить нечего.
Коллега, мне видится у Вас этакое внутреннее противоречие. Глобальный крюк — штука опасная, возражений нет. Хорошо бы загружать и выполнять в чужих процессах как можно меньше кода. В том числе не применять там никаких библиотек. Библиотеки имеют, например, свой код инициализации.
читает через пайпу

Через трубу. Будьте последовательны.
Решил не рвать шаблон коллеге ради единственного случая употребления.
Спасибо, я уже думал, что на мой вопрос никто не ответит. А почему SendMessage не всегда срабатывает? (По крайней мере я не смог им выгрузить библиотеку.)
Если б не Ваш вопрос, этой заметки не было бы.

SendMessage( HWND_BROADCAST) посылает сообщения во все окна верхнего уровня. Могут существовать нити, имеющие очередь сообщений, но не имеющие окон верхнего уровня.
Х. Вообразите, что наше приложение обновило себя через Интернет и перезапускается. После перезапуска окажется, что в некоторые процессы загружена старая версия DLL, а в некоторые новая. И в данном случае старая версия не выгрузится и тогда, когда через очереди пройдут сообщения.

Вот в это верится с трудом. Этож разные инстансы. Должно быть 2 хука. А что если я с одного процесса хочу 2 хука установить?
Позвольте ещё раз и подробнее:
  • Ставим крюк на My.dll.
  • Переименовываем My.dll в Old.dll, под именем My.dll сохраняем другой DLL.
  • Снимаем крюк и сразу ставим снова (не важно, перезапускаем EXE или нет). Новый крюк нацелен на новый My.dll.

Old.dll остался загруженным во многие процессы, My.dll загружается во вновь запускаемые процессы. Если адрес крюковой функции различается, то все процессы с Old.dll вскоре повалятся.

User32 для каждого DLL, загруженного в некоторый процесс, запоминает полный путь, который DLL имел в момент загрузки. Для Old.dll и для My.dll таковой путь одинаков
Спасибо за разъяснения, я не подумал про переименование уже загруженного модуля. Разве такая операция на всех файловых системах и более старых ОС возможна? Раньше же вроде нельзя было переименовать загруженный модуль… а сейчас попробовал, можно. Во всяком случае загруженные модули я даже и не думал переименовывать… как то это неправильно что ли.
Речь, конечно, о тех DLL, которые User32 загружает сам – в ответ на вызов SetWindowsHookEx.

Если установить два крюка, нацеленные на My.dll, то в «старых» процессах оба будут нацелены на Old.dll.

Экземпляры User32, работающие в «старых» процессах, думают, что уже загруженный Old.dll это и есть My.dll.
Замечание по поводу разных команд, которые писали user32 и kernel32, не совсем корректное. Очевидно же, что механизм оконных хуков уходит корнями глубоко в недра ядра, а точнее win32k.sys. Я писал об этом очень давно ещё на wasm'е. Сейчас он, правда, в дауне, но копия статьи сохранилась: http://last-soft.ucoz.ru/publ/10-1-0-7

Так же замечу, что библиотеки с хуками не только не сразу выгружаются из всех процессов, но и не сразу подгружаются. Все эти действия происходят во время выполнения CallNextHookEx() или DispatchMessage(). Такова уж архитектура Windows, тут нечего пенять на криворукость разработчиков. Если нужно обновить библиотеку, содержащую обработчик хука, то самым корректным и рекомендованным способом будет перезагрузка системы. Вы же не пытаетесь изобрести подобные костыли, когда дело касается обновления драйверов?
Пакеты обновления устанавливаются без перезагрузки (как правило) для: MS SQL, MS Office, Visual Studio,… Все веб-браузеры обновляются без перезагрузки. Даже и для некоторых драйверов новые версии устанавливаются без перезагрузки.

На этом фоне наша маленькая утилита потребовала перезагрузки машины. Что о нас подумал пользователь?
Я писал об этом очень давно ещё на wasm'е.

Холмс. Конечно читал, сэр! И утилитой Hooks пользуюсь. Кстати, — как повезло, что я Вас встретил, — нельзя ли реализовать сортировку по столбцам? Простите уж, недосуг осваивать Дельфи самому.
И утилитой Hooks пользуюсь.

А можно линк на утилиту в студию? Спасибо.
Все линки мёртвые, судя по всему. Если дома остались сорцы, то выложу куда-нибудь.
Сортировку по столбцам может быть реализую, но не обещаю, т.к. на Делфи уже давно ничего не писал и она на Линуксе не установлена.
То что они подгружаются не сразу — это очень разумно, пользователь не замечает этой подгрузки, а стартуй они все сразу — мб система подвисала бы на некоторое время.
Холмс. Согласен, сэр. Баг не столько в том, что загрузка и выгрузка отложенная, сколько в том, что DLL идентифицируется по файловому пути, в то время как для таких целей есть индекс файла (см. BY_HANDLE_FILE_INFORMATION).
Sign up to leave a comment.

Articles