Отправляет email-рассылки с помощью сервиса Sendsay

Web-Мастеринг - с нуля до профи

  Все выпуски  

нет.


Информационный Канал Subscribe.Ru

Познавательное программирование

(comp.soft.prog.urisprog)

Выпуск 29


Здравствуйте, Уважаемые подписчики!



Статья

Введение в программирование на WinAPI.
Автор: Alexer
Источник: http://www.loonies.narod.ru/apiintrr.htm

Здесь я буду рассказывать про WinAPI. А в частности: что это, зачем это, как это использовать и многое другое.
Итак, WinAPI (Windows Application Programmer's Interface) - это набор функций (огромный набор! Тот же MSDN, который содержит некоторую часть API, занимает почти 1.5 гигабайта!), которые использует программист при написании программы под Windows прямо или же косвенно. Прямо - значит, что вызывает их непосредственно из кода, который пишет. Например: при вызове MessageBeep(10h); прозвучит звук, который Вы обычно слышите при выводе окна с сообщением об ошибке. Косвенно - значит, что при выполнении стандартных процедур языка, программа в конечном счете вызывает ту или иную функцию API. Например, при вызове MsgBox (функция в VB) VB вызовет функцию API MessageBoxA.
Так зачем же нужно WinAPI? Представьте, что Вам необходимо проиграть какой-либо WAV файл. Что для этого необходимо сделать?
  1. Перейти в 0 кольцо процессора (их существует несколько: пользовательские приложения выполняются в 3 кольце) для получения возможности обращения к портам ввода/вывода (через эти порты драйверы "общаются" с оборудованием компьютера).
  2. Проверить наличие устройств вывода звука через порты ввода/вывода.
  3. Если устройство существует, то произвести его инициализацию для вывода звука.
  4. Если инициализация прошла успешно, то прочитать файл WAV (определить частоту, размер и прочие характеристики по выводу звука из этого файла), и посылать на определённый порт команды из WAV файла.
  5. После вывода звука на устройство закрываем порты и WAV файл.
При этом в 0 кольце процессора Вы не сможете работать с интерфейсом!
Это упрощённая схема вывода звука, при этом Вам так или иначе придётся обращаться к функциям ОС, но уже на низком уровне (0 кольцо).
А причём тут WinAPI, спросите? А вот причём: вместо всей этой кучи операций, нагрузки кода этими кольцами, портами, инициализациями, достаточно вызвать всего одну (!) функцию API, где необходимо указать только этот WAV файл и свойства его проигрывания (задерживать пользовательский ввод при проигрывании файла или нет), остальное она сделает сама!
Ну хорошо, скажете Вы. А зачем, тогда, заменять вызовы стандартных функций языка на вызовы API? Дело в том, что API предоставляет Вам больший простор действий, чем стандартные функции языка. Так, например, окно сообщения при вызове MsgBox будет показываться только относительно того окна, где была вызвана эта функция (это свойство окон называется модальностью). В API есть возможность указать окно, относительно которого вывести это сообщение. Это, конечно, лирика. С помощью WinAPI можно сделать намного больше! Например создать окно, изменить любые параметры любого элемента управления на любом окне, получение всевозможных паролей, которые Windows хранит в зашифрованном виде (ого! Скажут начинающие взломщики! На самом деле не всё так просто, необходимо вызвать кучу API функций, проверить все ошибки, прежде, чем получить требуемый пароль. Можно, конечно, всё построить по шаблону, но! если возникнет какая-то ошибка, то Вы не сможете её отл адить, т. к. не знаете механизм работы этой процедуры).
Таким образом, для написания более-менее профессиональных приложений API знать необходимо.
Итак, что же такое WinAPI по своей сути? Зайдите в папку Windows\System32 (или Windows\System, если у Вас Win9x), - там лежит множество файлов с расширением DLL. Это так называемые "динамически подключаемые библиотеки". По большей части именно в них "лежат" те самые функции API, о которых шла речь выше. Как они работают? Очень просто! В любом языке есть процедуры, которые могут быть вызваны из произвольного места программы. Для чего они нужны понятно даже начинающему: выполнить ряд стандартных инструкций вместо того, чтобы писать их каждый раз заново для получения того или иного результата. Функции API - это те же самые процедуры, но расположенные в отдельных файлах и здесь действует тот же принцип.
Когда процессу нужна процедура, расположенная в DLL, сначала производится поиск библиотеки в памяти, если она не найдена, то загружается в память процесса, после чего в ней ищется требуемая процедура. Если процедура найдена, то она вызывается. Это называется динамическим вызовом.
Есть и другой способ: при загрузке программы в память необходимые библиотеки сразу же загружаются в память, а необходимые процедуры "расставляются по местам". В результате процесс не ищет нужных библиотек и функций, а просто передаёт управление по адресу, где лежит адрес процедуры. Такой способ загрузки DLL называется статической линковкой.
Разберем на примере, что происходит при вызове MessageBeep(0x10). В стек загружается число 0x10 и адрес места, с которого была вызвана функция. После чего управление передаётся на адрес, где находится инструкция, перенаправляющая на функцию MessageBeep. После входа в эту процедуру проверяется параметр в стеке (0x10), обрабатывается (издаётся звук, соответствующий числу), после чего выполняется инструкция, которая высвобождает параметр 0x10 из стека и продолжает выполнение программы по адресу, который лежал перед параметром, после чего и его высвобождает из стека. Выглядит это следующим образом:
Address   Instruction
1000000 call MessageBeep - вызов 2000000 ->
...
2000000 jmp MessageBeep - перенаправление на процедуру MessageBeep (3000000)
...
3000000 mov eax, dword ptr [esp+04] - получение параметра из стека, который выглядит так:

-Stack Base-
00 1000005 - адрес следующей после вызывающей инструкции
04 0x10 - наш параметр
После обработки выполняется инструкция ret 04. Что она делает? Она высвобождает 0x10 из стека (операнд 04 после инструкции), после передаёт управление по адресу 1000005, после чего высвобождает и его из стека.
А что же случится, если мы передадим неверное число параметров? Ведь получится, что адрес процедуры окажется неверен. Окажется либо численно равным одному из наших параметров, либо случайному месту в памяти. Тогда возникает непредсказуемая ситуация с передачей управления в произвольную область памяти.
С необходимым минимумом по вызову функций мы знакомы. Перейдём к следующему моменту: основные соглашения при вызове API функций.
Функция библиотеки user32.dll MessageBoxA (A на конце означает, что строки будут передаваться в ANSI кодировке, W - в Unicode) имеет 4 параметра: hWnd - дескриптор родительского окна, lpPrompt - текст сообщения, lpCaption - заголовок сообщения, dwType - тип сообщения. Перечислю особенности, которые необходимо знать при написании программ с использованием WinAPI:
  • Все параметры передаются функции справа налево. В случае с MessageBoxA cперва загрузим в стек dwType, потом lpCaption, потом lpPrompt, и последним - hWnd.
  • Строки передаются адресом на свое начало в памяти.
  • Функция сама выгружает все параметры из стека и возвращает управление на следующую после вызывающей команды инструкцию.
  • Функция возвращает своё значение в регистре EAX.
В завершение - пример вызова MessageBox на C++:
void Main() {
LPSTR szText="Hello, World!";
LPSTR szCaption="Message Box";
MessageBox(0, (LPSTR) szText, (LPSTR) szCaption, 0x40);
}
Комментарии к коду: родительского окна у нас нет, ставим первый параметр 0; тип сообщения выберем как Information (слева прописная "i") с кнопкой ОК: MB_ICONINFORMATION | MB_OK = 0x40; szText и szCaption - адреса на строки с текстом и заголовком сообщения соответственно.
В дальнейшем буду выкладывать информацию по конкретным функциям API с примерами их работы.




Все вопросы, пожелания и предложения ведущему рассылки, прошу слать на e-mail: urisff@inbox.ru
Все статьи публикуются здесь только с разрешения (или рекомендации) автора.
Если вы хотите опубликовать здесь свою статью, то сделайте это, переслав её мне (желательно в виде html, причём без картинок). В случае, если вы будете использовать приведённые в этой рассылке материалы, не забудьте сделать ссылку на эту рассылку.

Ведущий рассылки:
Набатников Иван, urisff@inbox.ru
TIREAL company: http://www.tireal.com
Старый сайт: http://newff.narod.ru


Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.urisprog
Архив рассылки
Отписаться Вебом Почтой
Вспомнить пароль

В избранное