Обучающие курсы:

Обучение профессии "Разработчик C#" + стажировка в Mail.ru
Обучение профессии "Разработчик Python" + трудоустройство
Обучение профессии "Веб-разработчик" + стажировка в Mail.ru


Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Среда разработки Delphi имеет много встроенных процедур обработки строк, причем довольно эффективных. Может возникнуть вопрос: зачем изобретать велосипед и писать процедуры на ассемблере, если аналогичные уже написаны на Delphi и готовы к использованию?
Не случайно выбраны последние два варианта программ в качестве примеров. Ассемблерные процедуры, выполняющие "точечные" преобразования в строке, такие как замена, поиск символов и подстрок (фрагментов строк), всегда превосходят свои аналоги на языках высокого уровня. Процедуры на ассемблере в этих случаях чрезвычайно эффективны и выполняются намного быстрее; не важно, с каким компилятором вы работаете и какую среду предпочитаете — Delphi 7 или Visual С++ .NET. Чтобы убедиться в этом, читатель может переписать приведенный последний пример, используя только высокоуровневые функции Delphi для обработки строк, и дизас- семблировать программный код.
Описание встроенного ассемблера Delphi 7 было бы неполным, если бы мы не рассмотрели еще одну замечательную возможность, предоставляемую этим средством. Ассемблерная процедура может напрямую обращаться к функциям WIN API операционной системы Windows. Это позволяет расширить возможности программы за счет манипулирования мощными функциями библиотеки WIN API. Как можно вызвать такие функции из ассемблерного кода?

Вспомним, что для вызова функций WIN API необходимо передать параметры в вызываемую функцию через стек в порядке, обратном их следованию в списке аргументов функции. В этом случае самый правый параметр функции помещается в стек первым. Кроме того, почти все функции WIN API, как мы знаем, используют соглашения директивы stdcaii. Это значит, что при возврате управления вызывающей программе вызываемая функция сама должна освобождать стек.

Рассмотрим пример использования трех функций WIN API: CreateFile, writeFile, cioseHandie. Требуется записать в файл с именем TEXTOUT строчку текста. Поместим на главной форме приложения два поля редактирования Edit С именами Editl И Edit2, Две метки Label И КНОПКУ Button. Текст для записи в файл возьмем из поля редактирования Editl. В поле редактирования Edit2 будет отображаться количество байт, записанных в файл. Процесс обработки текста, введенного пользователем, выполняется в обработчике нажатия кнопки, которую мы предварительно разместим на главной форме приложения.

Исходный текст программы приведен в листинге 6.36.
Листинг 6.36. Использование функций WIN API в блоке asm-end для записи строки текста в файл
unit apiuse;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TForml = class(TForm)
Buttonl: TButton;
Editl: TEdit;
Label1: TLabel;
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Forml: TForml;
implementation
{$R *.dfm}
procedure TForml.ButtonlClick(Sender: TObject);
var
Path: PChar;
sTitle, crText, wrText, clText: PChar;
pBuf: PChar;
lenBuf: Integer;
hFile: DWORD;
bufWritten: DWORD;
begin
sTitle : = 'WIN API USE'#0;
crText := 'File Creating Error!'#0;
wrText := 'File Writing Error!'#0;
clText := 'File Closing Error!*#0;
Path := 'TEXTOUT'#0;
lenBuf := Editl.GetTextLen;
inc(lenBuf);
GetMem(pBuf, lenBuf);
Editl.GetTextBuf(pBuf, lenBuf);
asm
push 0
push FILE_ATTRIBUTE_NORMAL
push CREATE_ALWAYS
push 0
push 0
push GENERIC_WRITE
push DWORD PTR Path
call CreateFile
cmp
je
mov
push
lea
push
dec
push
push
push
call
cmp
je
jmp
@goClose
push
call
cmp
jne
jmp
@crMes:
push
push
push
jmp
@wrMes:
push
push
push
jmp
@clMes:
push
push
push
EAX, IN VALI D__HAN DLE_VALUE
@crMes
DWORD PTR hFile, EAX
0
ESI, DWORD PTR bufWritten
ESI
DWORD PTR lenBuf
DWORD PTR lenBuf
DWORD PTR pBuf
hFile
WriteFile
EAX, 1
@goClose
@wrMes
hFile
CloseHandle
EAX, 1
@clMes
@ex
MB_OK
DWORD PTR sTitle
DWORD PTR crText
@cont
MB_OK
DWORD PTR sTitle
DWORD PTR wrText
@cont
MB_OK
DWORD PTR sTitle
DWORD PTR clText
@cont:
push О
call MessageBox
@ех:
end;
FreeMem(pBuf, lenBuf);
Edit2.Text := IntToStr(bufWritten);
end;
end.

Проанализируем исходный текст программы. В секции var объявлены следующие
переменные:
• Path определяет имя создаваемого файла;
• pBuf — указатель на буфер памяти, данные из которого будут записаны в
файл;
• lenBuf — размер буфера памяти;
• hFile — дескриптор файла, в который записываются данные;
• bufWritten содержит количество записанных байт;
• sTitle, crText, wrText, ciText— заголовок окна и сообщения, указывающие тип возможной ошибки при выполнении операции с файлом.

Первое, что делает программа, — помещает введенный в поле редактирования
текст в буфер памяти. Это выполняется группой операторов:
lenBuf := Editl.GetTextLen;
inc(lenBuf);
GetMem(pBuf, lenBuf);
Editl.GetTextBuf(pBuf, lenBuf);
Первый оператор сохраняет размер строки из поля редактирования в переменной
lenBuf. Второй по порядку оператор резервирует место для нулевого
символа через инкремент переменной lenBuf. Оператор:
GetMem(pBuf, lenBuf)
позволяет выделить память, поместив в указатель pBuf адрес первой ячейки
выделенной области. Наконец, с помощью оператора:
Editl.GetTextBuf(pBuf, lenBuf)
текст из поля редактирования Editl помещается в буфер памяти. Для записи
текстовой строки в файл вначале создадим этот файл. Это выполняется с
ПОМОЩЬЮ фуНКЦИИ CreateFile!
push О
push FILE_ATTRIBUTE_NORMAL
push CREATE_ALWAY S
push 0
push 0
push GENERIC_WRITE
push DWORD PTR Path
call CreateFile
mov DWORD PTR hFile, EAX

Параметры вызова хорошо описаны в документации по WIN API и многочисленных литературных источниках, поэтому подробно останавливаться на этом не будем. Хочется только заметить, что все системные константы Windows поддерживаются средой Delphi. Именно поэтому такая команда, как:
push GENERIC_WRITE
ошибки компилятора не вызывает.
Все параметры, передаваемые через стек, являются 32-разрядными. Все функции WIN API возвращают результат в регистре ЕАХ. Для анализа содержимого регистра ЕАХ необходимо выполнить команды:
cmp ЕАХ, INVALID_HANDLE_VALUE
je @crMes


 
 
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru