TrayText. Только для Win 9x/ME.
Выводит бегущую строку вместо часов в правом нижнем углу экрана.
Пример использования перехвата функций API.


	Сие творение - пример того, что можно сделать при помощи перехвата функций WinAPI. Для понимания сути происходящего нужно ознакомиться с данной темой. Например, читайте статью WASM.RU -> СТАТЬИ -> Секреты Win32 -> Система перехвата функций API платформы Win32.
	Итак, приступим. Запустите TrayText.exe (только в Win 9x/ME !). Посмотрите в то место, где винда отображает часы. Программа уже завершила свою работу. Все, что вы видите, происходит внутри explorer.exe. Эффект снимается перезагрузкой винды.

	Далее я расскажу в целом, что делает программа. Мы перехватываем функцию DispatchMessage. Используется сплайсинг, т.е. замена первых пяти байт этой функции на переходник. Переходник представляет собой инструкцию jmp, которая ведет на обработчик. Обработчик (HANDLER) мы располагаем внутри kernel32, в остатке первой секции (первая секция занимает 8 страниц, в последней из них занято всего лишь 4 байта из 4096, дальше - нули !). Доступ на запись в это место получаем, вызывая при помощи "секретной" VxdCall0 функцию PageModifyPermissions из VMM.
	Затем мы при помощи FindWindowEx находим хэндл окна, в котором отображаются часы (это окно имеет класс TrayClockWClass). Посылаем найденному окну специальное сообщение (WM_IMPLANT). Любое окно, получив сообщение, вызывает функцию DispatchMessage. Тут-то и происходит перехват этой функции. Мы попадаем на обработчик, который делает следующее.
	Сперва проверим, вызвана ли DispatchMessage тем самым окном (с часами) и для того самого сообщения (WM_IMPLANT). Если нет, то восстанавливаем 5 байт настоящей функции, вызываем ее, после чего кладем переходник на место.
	Если же "пришел наш час", то опять-таки восстанавливаем 5 байт, вызываем настоящую DispatchMessage, но переходник обратно не кладем. Нам достаточно один раз перехватить функцию и выполнить некоторые действия от имени процесса explorer.exe, который и создал окошко с часами.
	Итак, приступаем к самому интересному. Мы от имени эксплорера выделяем (GlobalAlloc) блок памяти под две наши процедуры. Создаем шрифт, которым будет отрисовываться наш бегущий текст. Затем копируем в выделенную память код процедуры окна и процедуры таймера (о них - ниже). Пока эти две процедуры (IMPLANT) располагаются здесь же, в HANDLER'е, но мы выделяем для них свою память и переписываем их туда, чтобы они не болтались в kernel'е. Таким образом, мы "имплантировали" наш код в процесс explorer.exe. Получается такой "двухступенчатый" заброс кода в чужой процесс.
	Но это, конечно, еще не все. Надо, чтобы этот имплантированный код начал выполняться. При помощи SetWindowLong зададим для окошка с часами новую процедуру окна (метка WinProc). (Это называется субклассинг). Также установим на окошко таймер, указав ему адрес нашей процедуры таймера (метка TimerProc). Все. На этом миссия обработчика завершена. Управление передается обратно вызывавшей программе. (Напомним, что здесь мы уже не кладем переходник на место первых 5 байт).

	Собственно, на этом самая впечатляющая часть программы завершена и начинается рутинная работа.
	Что делает наша "подставная" процедура окна. Как известно, винда раз в минуту шлет WM_TIMER окошку с часами, чтобы оно отобразило новую минуту. Итак, получив WM_TIMER, вызовем процедуру KillTimer, чтобы больше не получать это сообщение. (Вместо этого мы уже установили на окошко свой таймер, с меньшим интервалом. Наш таймер при этом не будет убит, поскольку WM_TIMER не шлется, а вызывается указанная процедура таймера).
	Также нам надо подменить отрисовку окна. Т.е., когда мы будем получать WM_PAINT, мы будем выводить нашу строку в определенном месте. (Используются BeginPaint, SelectObject, SetBkMode, SetTextColor, TextOut, EndPaint). Во всех остальных случаях мы будем вызывать прежнюю процедуру окна (ее выбрасывать ни в коем случае нельзя !).
	Теперь что делает наша процедура таймера. Она всего лишь уменьшает значение координаты X, по которой выводится наш текст и при помощи InvalidateRect, UpdateWindow принудительно вызывает перерисовку окна. Таким образом, каждый раз при вызове процедуры таймера наш текст будет немного сдвигаться влево.

	Вот, собственно, и все. Еще раз поясню важнейшие моменты. Вся эта кутерьма с перехватами, имплантантами и пр. нужна лишь для того, чтобы внедрить бегущую строку в сам explorer. Так-то нам никто не мешал отрисовывать строку на месте часов прямо из нашей программы.
	Мы перехватываем функцию DispatchMessage, потому что она гарантированно вызывается при получении любым окном любого сообщения.
	Перехват нужен для того, чтобы ОТ ИМЕНИ ПРОЦЕССА EXPLORER.EXE выполнить три действия:
1. субклассинг окна (ибо "The SetWindowLong function fails if the window specified by the hWnd parameter does not belong to the same process as the calling thread");
2. установка таймера на окно (ибо "hWnd - Identifies the window to be associated with the timer. This window must be owned by the calling thread.").
3. выделение блока памяти при помощи GlobalAlloc (ну тут понятно, память выделяется только нашему процессу).
	Обработчик функции DispatchMessage  - это все, что заключено между HANDLER_BEGIN и HANDLER_END. Его мы копируем внутрь kernel32, чтобы он был "виден" всем процессам в системе, что является необходимым условием перехвата (таким способом).
	"Имплантант" - это все, что заключено между IMPLANT_BEGIN и IMPLANT_END. Его мы из обработчика копируем в блок памяти, выделенной при помощи GlobalAlloc, т.е. эта память принадлежит только процессу explorer.
	Таймер устанавливаем для того, чтобы он сдвигал наш текст. Процедуру окна перехватываем, чтобы подменить отрисовку - вместо часов выводить наш текст.

	И напоследок еще одно концептуальное замечание. Чтобы сделать бегущую строку, можно было обойтись и без перехвата функций API. Нам надо лишь выполнить код от имени другого процесса. Это можно сделать, например, поместив код в dll и установив хук (к примеру WH_CBT). Тогда наша dll-ка будет автоматически приаттачиваться к каждому процессу. А данная программа - это всего лишь "пример того, что можно сделать при помощи перехвата функций WinAPI".

Все. Как говорится, enjoy (если сумеете разобраться).


=========================================================
Компилятор: 	TASM
=========================================================

TGZ, The Great Zopuh,
great_zopuh@mail.mtu.ru













