Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу).
Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу). Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу). Homepage Карта сайта Версия для печати

Джентльменский набор Web-разработчика   Ларри Уолл о Perl6   Наблы Система Orphus
 

27. Win32 — Ассемблер — Дзэн

[26 января 2003 г.] обсудить статью в форуме

В рамках проекта Денвер-2 были разработаны несколько небольших утилит общего назначения, которые я и хотел бы быстренько представить в настоящей набле. Все описываемые далее программы работают только в Windows.

Лирическое отступление 
Отличительной особенностью утилит является их сверхмалый размер — меньше 7 КБ. Дальше это будет объяснено более подробно.

Запуск программы в Tray

Бывает, нужно выполнить какую-нибудь программу в фоновом режиме, однако ее окно мешается. Утилита Starter (6.5 КБ), доступная по адресу http://dklab.ru/chicken/nablas/demo/asm, позволяет запускать любые приложения (консольные или обычные) свернутыми на Tray. Чтобы показать окно, достаточно щелкнуть по пиктограмме; повторный шелчок, наоборот, прячет программу.

Как ей пользоваться? Это довольно забавно. Чтобы указать программу, которую вы хотите запустить, нужно взять Far (или любой редактор бинарных файлов), открыть EXE-файл и поправить прямо в нем путь к программе. Только убедитесь, что вы находитесь в режиме замены (нажата клавиша Insert), а то программа не запустится.

Чайник 

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

Вот как выглядит внутренность EXE-файла в редакторе Far-а:

В недрах Starter.exe

Как видите, не так уж и сложно вставить нужные пути и параметры.

Лирическое отступление 
В Денвере эта утилита используется для запуска Apache, а также главного скрипта запуска/остановки.

Полезной особенностью этой (и следующей) утилиты является то, что все пути отсчитываются от директории, содержащей Starter.exe (а не от текущей на момент запуска). Таким образом, чаще всего вам не придется связываться с абсолютными путями.

Переадресация на другую программу

Утилита Wrapper (4.5 КБ), также доступная по адресу http://dklab.ru/chicken/nablas/demo/asm, позволяет подменять одну программу другой. Она использует методику, похожую на Starter, однако:

  • работает только для консольных приложений;
  • позволяет устанавливать дополнительные переменные окружения перед запуском.

Зачем это нужно? Представьте, что вы установили интерпретатор Perl (perl.exe) в директорию /usr/bin/perl.exe. Однако вы хотите, чтобы он был также доступен по адресу /usr/sbin/perl, /usr/local/bin/perl и /usr/local/sbin/perl. Не инсталлировать же одно и то же четыре раза... И тут на помощь приходит Wrapper. Переименуйте его в perl.exe, пропишите внутри путь к «настоящему» Perl и скопируйте получившийся файл в нужные директории. Все будет работать, как надо.

В недрах Wrapper.exe

Лирическое отступление 
В Денвере используется именно такой подход для обеспечения лучшей совместимости с различными хостинг-провайдерами. Кроме того, возможность устанавливать дополнительные переменные окружения помогает при работе с php.exe, который не запускается, если ему не поставить REDIRECT_STATUS=200. Ну а уж о том, что та же самая утилита применяется для работы с Parser, и говорить нечего.

Управление WinAmp-ом

Когда вы что-то печатаете, параллельно слушая WinAmp, отвлекаться на переключение песни при помощи мыши весьма неприятно. Кроме того, окно WinAmp-а (даже если его уменьшить до безобразия) занимает место на экране, и мы вынуждены держать его Always-on-Top, чтобы всегда иметь возможность переключить песню.

Недавно я увидел у приятеля клавиатуру, на которой в верхнем ряду были дополнительные кнопки: Play, Pause, Forward, Back и т. д., как на магнитофоне. Он пожаловался, что они не работают с WinAmp-ом (ну еще бы они работали...).

И такие клавиатуры тоже бывают

А задача, тем временем, проста. У WinAmp-а (кто еще не знает) есть специальный API, чтобы можно было им управлять из другой программы. Его описание доступно здесь: http://winamp.com/nsdn/winamp2x/dev/sdk/api.jhtml.
«Ага (потирая руки), половина дела сделана.»

Чайник 

Сейчас 26 января 2003 года. Утилита WinAmper расчитана на применение только совместно с WinAmp версии 1 и 2, но не версии 3. Если вы пользуетесь третьей версией (этим кривейшим из глюков, когда-либо разработанных homo sapiens), немедленно уничтожьте ее и поставьте нормальную (сейчас это 2.81). Объявим бойкот разработчикам на ужасный WinAmp 3!

Осталась только одна проблема: как глобально перехватить нажатия на горячие клавиши. Вместо того, чтобы брать Microsoft Visual Studio и, обливаясь потом, разбираться с Hook-ами, лучше пойти другим путем. Не мудствуя лукаво, берем The Wonderful Icon (285 КБ, сторонняя разработка) и настраиваем в ней запуск нужной программы при нажатии на ту или иную клавишу.

Лирическое отступление 
Слава богу, The Wonderful Icon позволяет перехватывать и экзотические клавиши. Правда, она их при этом неправильно отображает, но работают они, как надо.

Что это за «нужная программа»? Это WinAmper (4.5 КБ), я написал его буквально за полчаса. Вы можете скачать утилиту с популярного сегодня в Интернете адреса http://dklab.ru/chicken/nablas/demo/asm. Дальше открывайте ее настройки и конфигурируйте так, как нарисовано ниже:

Настройка The Wonderful Icon: Win+Вправо вызывает переход к следующей песне (Next)

На рисунке используется код 40048, который в соответствии с таблицей на http://winamp.com/nsdn/winamp2x/dev/sdk/api.jhtml означает «переход к следующей песне». Я привожу здесь несколько наиболее популярных кодов управления WinAmp-ом:

Действие Код Рекомендую клавиши
Предыдущая композиция 40044 Win+Влево
Следующая композиция 40048 Win+Вправо
Пауза/Воспроизведение 40046 Win+Num5
Вперед на 5 секунд 40148 Win+Num7
Назад на 5 секунд 40144 Win+Num9
Увеличить громкость Ctrl+Plus
Уменьшить громкость Ctrl+Minus
Включить/Отключить динамики Ctrl+NumLock

Последние три действия имеют во втором столбце прочерк. Это означает, что с ними прекрасно справляется The Wonderful Icon при помощи собственных настроек. Вмешательство WinAmper-а не требуется.

Таким образом, мы устроили симбиоз двух программ и получили за счет этого универсальное решение. Сама по себе очень неплохая утилита The Wonderful Icon в сочетании с WinAmper-ом становится смертоносным орудием в руках Web-программиста.

Чайник 

Если вы задались вопросом, не будет ли слишком «тормозить» запуск нового процесса при каждом нажатии горячей клавиши (а ведь именно так работает WinAmper), то могу вас успокоить: не будет. Если не верите — протестируйте, сколько раз в секунду удастся запустить WinAmper на 486-й машине (для интереса возьмите DX2 66). Результаты весьма и весьма занятны.

Сущность дзэна

Лирическое отступление 
Если вы никогда не программировали на ассемблере, дальше вам лучше не читать. Утонете.

Конечно, вы сейчас скажете, что в наше время на ассемблере никто не пишет. И я не буду агитировать вас в пользу разработки программ на этом языке, ибо часто это действительно не оправдано.

Зачем же все описанные выше утилиты написаны (да-да, вы уже догадались) на ассемблере? Причина только одна: они написаны так потому, что они так написаны.

Чем я руководствовался, когда брался за каждую из них? А чем вы руководствуетесь, когда дышите? Когда спите? В чем сущность дзэна?

Иероглифы
Сияние солнца подобно прекрасному цветку лотоса.
А
лотос — дерьмо.

Сложно ли программировать на ассемблере под Windows? Не сложнее, чем под DOS. Вот, например, как выглядит основной кусок исходного кода WinAmper-а (я вырезал из листинга определения строковых констант и немногочисленных вспомогательных функций):

Листинг 1
.386                      ; create 32 bit code
.model flat, stdcall      ; 32 bit memory model
option casemap :none      ; case sensitive

;## Точка входа
.code
start:
      call    Main
      invoke  ExitProcess,eax
;## Конец процесса.

Main  proc
      LOCAL   buf[64]: BYTE
      invoke  ExtractArgs, ADDR buf, sizeof buf
      lea     esi, buf
      .if     byte ptr [esi] != 0
        ;# Получаем окно WinAmp-а
        invoke  NullizeStr, ADDR sWA1, sizeof sWA1
        invoke  FindWindow, ADDR sWA1, NULL
        mov     esi, eax
        .if     esi!=0 
          invoke    atoi, ADDR buf
          mov       edi, eax
          invoke    SendMessage, esi, WM_COMMAND, edi, 0
        .else
          .if       cBeep!=' ' && cBeep!=0
            invoke    MessageBeep, MB_OK
          .endif
        .endif
      .else
        ;# Usage
        invoke  MessageBox, NULL, 
                ADDR eAboutText, ADDR sUsage, 
                MB_ICONINFORMATION
      .endif
      mov     eax, 0
      ret
Main  endp
end   start

Можно видеть, что Windows думает при запуске программы недолго: она просто берет и передает управление метке start (той, которую вы указали в предложении end в самом конце). То, что будет происходить дальше, всецело в руках программиста. Хотите открыть консоль? Пожалуйста, invoke AllocConsole. Хотите вызвать Main, как это делает Си (заметьте, именно Си, а не Windows — последний ни о каком Main-е и слыхом не слыхивал)? Вызывайте на здоровье.

Полный архив файлов с исходным кодом доступен по адресу http://dklab.ru/chicken/nablas/demo/asm/srс . Там несколько лишних файлов, которые нигде не включаются — это на будущее (самый простой способ организовать библиотеку функций).

Теперь о том, чем компилировать всю эту прелесть. Есть такой компилятор — называется MASM32. Он доступен по адресу http://www.compexp.ru/rus_comp_masm.html. Писать программы с помощью этого инструмента весьма удобно. Стандартные функции Windows API доступны сразу же и без лишних разговоров. Таким образом, вы можете делать все, что заблагорассудится, даже не прибегая к Си. Наконец, хотите вызвать функцию Windows API, передав ей кучу сложных параметров? Для каждого из них в MASM32 есть своя структура, например:

Листинг 2
StartupInfo     STARTUPINFO <>
...
;# Заполняем поля.
mov     StartupInfo.cb, sizeof STARTUPINFO
lea     eax, [szFull]
mov     StartupInfo.lpTitle, eax
mov     StartupInfo.dwFlags, STARTF_USESHOWWINDOW
mov     StartupInfo.wShowWindow, SW_HIDE

Для компиляции маленьких программ (а именно такие программы — маленькие — и хорошо писать на ассемблере) удобно использовать следующий bat-файл:

Листинг 3
echo off

:# Program name.
set PROG=WinAmper
:# Comment to avoid debug info in EXE
:set DEBUG=/DEBUG 
:# CONSOLE | WINDOWS
set SUBSYS=CONSOLE

set MASM=C:\masm32
set DIR=Obj
set INCLUDE=%INCLUDE%;%MASM%
set LIB=%LIB%;%MASM%\lib

del %PROG%.exe 2>nul
mkdir %DIR% 2>nul

%MASM%\BIN\ML.EXE /nologo /c /coff /Zd /Fo%DIR%\%PROG%.obj main.asm 
%MASM%\BIN\LINK.EXE /nologo /PDB:NONE /SUBSYSTEM:%SUBSYS% %DEBUG% /Out:%DIR%\%PROG%.exe %DIR%\%PROG%.obj

copy %DIR%\%PROG%.exe %PROG%.exe >nul 2>nul
pause

Вы можете даже отлаживать получившиеся EXE-шники в Microsoft Visual Studio (File — Open — выбрать EXE-файл). Для этого раскомментируйте строчку, устанавливающую переменную окружения DEBUG, и перекомпилируйте программу. Вам будет доступна вся отладочная информация, в том числе отладка в терминах исходных кодов.

Заключительные мысли

Есть такая поговорка: «простой задаче — простое решение». Если вам нужна малюсенькая утилитка, которой не нужна:

  • работа с графикой,
  • работа с файлами,
  • динамическое выделение памяти,
то при определенной сноровке оптимальный вариант — использовать ассемблер и обычный Win32 API. Как было показано выше, программирование на асемблере для Win32 не является чем-то принципиально сложным (если только вы знаете ассемблер хотя бы чуточку).

Кроме того, желательно писать программы так, чтобы они получались как можно более универсальными. В этом случае они обязательно найдут и другое применение в будущем, о котором вы сейчас даже и не догадываетесь. Например, разрабатывая утилиты для Денвера, мне и в голову не приходило, что их можно использовать где-то еще.

Если есть выбор — написать одну большую программу, которая делает сразу все, или же две маленьких, самодостаточных и независимых друг от друга, то лучше выбрать второй вариант. Имея определенное количество мелких утилит, вы всегда можете построить из них, как из кирпичиков, здание любой сложности. Оно не разрушится от дуновения ветерка, и вам не придется периодически делать в нем ремонт. Если есть возможность использовать утилиты сторонних производителей (типа The Wonderful Icon), стоит сделать это без колебаний — незачем выполнять одну и ту же работу дважды. Пример симбиоза программ приведен выше.

Лирическое отступление 
Данная набла может являться иллюстрацией компонентного подхода, часто используемого в Web-программировании. См. также наблу о коде и шаблоне страницы. При написании статьи не пострадало ни одного шаблонизатора.

обсудить статью в форуме

 
Рекламный блок
   

На странице:
    27. Win32 — Ассемблер — Дзэн
Запуск программы в Tray
Переадресация на другую программу
Управление WinAmp-ом
Сущность дзэна
Заключительные мысли

Важное объявление:
    автор категорически против копирования и распространения в Интернете всех статей «Куроводства» с возрастом, меньшим 6 месяцев. Печальный опыт «расползания» чрезвычайно устаревших ошибочных версий статьи про Apache действительно объясняет такое решение.

Орфография на «Куроводстве»:
    если вы заметили орфографическую, стилистическую или другую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Выделенный текст будет немедленно отослан вебмастеру, а Вы даже ничего и не заметите — настолько быстро все произойдет.

На заметку:
    если вы уже вскипели насчет дизайна этой страницы, то присмотритесь повнимательнее к названию, почитайте FAQ, сходите по лебедевским местам, как это уже предлагалось выше. Можно ли считать пародию плагиатом? Надеюсь, что нет.

Параметры этой страницы
   
GZip

Ссылки от спонсоров
   


Дмитрий Котеров | 26 января 2003 г. ©1999-2016 | Генеральный спонсор: Хостинг «Джино» | Контакт Вернуться к оглавлению