Мы уже не однократно использовали в своих программах модуль CRT и пару раз модуль Graph. Наверняка вы догадываетесь, что можно самим написать модуль. Разработка модулей существенно повысит вашу производительность как программиста. Например написав однажды кучу функций можно собрать их в один модуль и не копировать из файла в файл. Хочу оговориться, что модули это исключительна фишка Турбо Паскаля. В стандартном Паскале такого нет. Модули так же полезны, если код не влезает в 64 Кб (это актуально только для ДОС программ), т.к. компилятор Турбо Паскаля загоняет текст модуля в отдельный сегмент. По своей сути модуль представляет из себя ту же программу с несколько иным началом. Структура модуля такова:
UNIT имя;
INTERFACE
интерфейсная часть
IMPLEMENTATION
исполняемая часть
BEGIN
часть инициализации
END.
Начнём по порядку. ИМЯ - задаёт имя модуля (это то, которое мы потом будем объявлять в USES). Для того что бы избежать лишних проблем следует называть модуль и файл с его кодом одним именем. Т.е. если мы хотим назвать модуль так:
unit myunit;то текст его должен распологаться в файле с именем myunit.pas. Интерфейсная часть несёт в себе описание типов, переменных, констант, подпрограмм, которые можно будет использовать (вызывать) из головной программы. При описании подпрограмм нужно написать просто их заголовок. Например начнём писать простенький модуль для работы с комплексными числами. (для тех кто в танке - комплексные числа - это числа вида a + b*i, где i число, такое что i2 = -1, a и b - вещественные числа... вообщем литературу на эту тему найти легко, было бы желание). Для этого опишем запись с полями re и im (это a и b) и заголовок процедуры для сложения 2-х комплексных чисел.
unit Cmplx;
interface
type
complex = record
re, im : real;
end;
procedure AddComplex (x, y : complex; var z : complex);
Итак теперь в основной программе, подключив наш модуль, мы можем объявить переменные типа complex и вызывать процедуру AddComplex. Следует так же отметить (ведь наши программы пока для ДОСа), что все переменные объявленные в интерфейсной части модуля и все переменные основной программы помещаются в единный сегмент данных и следовательно не могут превышать 64 Кб. Переходим к исполняемой части. В ней должно содержаться описание подпрограмм, объявленных в интерфейсной части. Так же можно помещать локальные для модуля объекты (т.е. к ним нельзя обратиться из головной программы) - типы, константы, подпрограммы, переменные. Продолжим наш модуль:
unit Cmplx;
interface
type
complex = record
re, im : real;
end;
procedure AddComplex (x, y : complex; var z : complex);
implementation
procedure AddComplex;
begin
z.re := x.re + y.re;
z.im := x.im + y.im
end;
Обратите внимание на объявление процедуры AddComplex в исполняемой части модуля. Очередная халява - можно опускать список параметров (и тип результата для функции), так как они уже описаны в интерфейсной части. При этом халява не обязательная - вы вполне можете написать полный заголовок. Переходим к последней части - части инициализации. Она может быть, а может и не быть. Если она есть - тогда обрамляется begin-end. Если её нет, тогда просто пишется end. (с точкой!!). В части инициализации помещается код, который выполняется до передачи управления главной программы. Например здесь программист может присвоить переменным модуля какие-то стартовые значения. В нашем модуле нет никаких тайных махинации и поэтому мы можем опустить инициализацию и вот он - наш первый законченный модуль:
unit Cmplx;
interface
type
complex = record
re, im : real;
end;
procedure AddComplex (x, y : complex; var z : complex);
implementation
procedure AddComplex;
begin
z.re := x.re + y.re;
z.im := x.im + y.im
end;
end.
Ещё один важный момент - если нечего инициализировать, то тогда лучше вообще не писать часть инициализации (т.е. слово begin) т.к. получится так называемый пустой оператор. Что может в некоторых случаях привести к проблемам. Давайте напишем модуль с инициализацией и скрытой переменной:
unit some;
interface
procedure iplus;
implementation
uses CRT;
var
i : integer;
procedure iplus;
begin
i := i + 1;
writeLn ('I = ', i)
end;
begin
randomize;
i := random (256);
writeLn ('Start I = ', i)
end.
i - это переменная, доступная только внутри модуля! Тепрь напишем головную программу, использующую этот самый модуль:
program test;
uses some;
begin
writeLn ('Yo-ho-ho!');
iplus;
iplus;
iplus
end.
Запускаем и что мы видим?
Start I = 16 Yo-ho-ho! I = 17 I = 18 I = 19 |
Программа
В начале я хотел "отписаться" стандартным в этом случае модулем для работы с комплексными числами. Но, подумал я, неужели мы зря учили ассемблер, нет. Давайте лучше напишем модуль для работы с мышой. Думаю у вас уже неоднократно возникало желание подключить грызуна к своим программам. Сегодня мы это и сделаем. Работа с ушастым реализуется через 33h прерывание. Программа осуществляет это прерывание, передавая в регистрах необходимые параметры, и в них же получает возвращаемые значения от драйвера мыши. Наш модуль не будет поддерживать все возможности мыши, а только самые основные. Итак текст модуля:
unit mouse;
interface
const
MB_LEFT = 1;
MB_RIGHT = 2;
MB_MIDDLE = 4;
type
tPoint = record
x, y : integer
end;
tMouseState = record
loc:tPoint;
but:integer
end;
function ResetMouse:integer;
procedure ShowMouse;
procedure HideMouse;
procedure GetMouseState (var s:tMouseState);
procedure MoveMouseCursor (p :tPoint);
procedure SetMouseVert (max, min : integer);
procedure SetMouseHorz (max, min : integer);
implementation
function ResetMouse:integer;assembler;
asm
xor ax, ax
int 33h
end;
procedure ShowMouse;assembler;
asm
mov ax, 1
int 33h
end;
procedure HideMouse;assembler;
asm
mov ax, 2
int 33h
end;
procedure GetMouseState;assembler;
asm
mov ax, 3
int 33h
push es
push di
les di, dword ptr s
mov es:[di], cx
mov es:[di+2], dx
mov es:[di+4], bx
pop di
pop es
end;
procedure MoveMouseCursor;assembler;
asm
mov ax, 4
mov cx, p.x
mov dx, p.y
int 33h
end;
procedure SetMouseVert;assembler;
asm
mov ax, 8
mov cx, min
mov dx, max
int 33h
end;
procedure SetMouseHorz; assembler;
asm
mov ax, 7
mov cx, min
mov dx, max
int 33h
end;
end.
Итак наш модуль поддерживает всего 7 из 31 возможных функций мыши. Если хотите ознакомится, то в новостях сайта дана ссылка на соответствующий документ. Я не буду рассматривать, как написаны эти процедуры и функция, т.к. это простые вызовы прерываний. Если вы немнго разбираетесь в ассемблере, то вам всё понятно. Если есть вопросы - тогда пишите. Я же рассмотрю этот модуль со стороны языка Паскаль. Мы имеем общедоступными 3 константы - они определяют кнопки мыши. 2 типа:
- tPoint - описывает точку на экране
- tMouseState - описывает состояние мыши. loc - координаты, but - состояние кнопок (имено те 3 константы).
- function ResetMouse:integer;
Инициализирует мышь, если таковой не имеется вернётся нулевое значение. - procedure ShowMouse;
Показывает курсор мыши на экране. При этом курсор следует за перемещениями мыши. - procedure HideMouse;
Прячет курсор. Полезно когда надо что-то нарисовать под курсором, последовательность действий при этом: спрятали курсор, нарисовали, показали курсор. - procedure GetMouseState (var s:tMouseState);
Читает и возвращает состояние мыши в виде записи tMouseState - procedure MoveMouseCursor (p :tPoint);
Передвигает курсор мыши в точку p - procedure SetMouseVert (max, min : integer);
Устанавливает минимальную/максимальную вертикальную границу передвижения мыши - procedure SetMouseHorz (max, min : integer);
Устанавливает минимальную/максимальную горизонтальную границу передвижения мыши
program mousetest;
uses graph, mouse, crt;
var
Gd, Gm: Integer;
flag : boolean;
ms : tMouseState;
begin
Gd := Detect;
flag := false;
InitGraph(Gd, Gm, '');
if GraphResult <> grOk then
Halt(1);
Randomize;
ShowMouse;
while not flag do
begin
GetMouseState (ms);
if ms.but = MB_RIGHT then
flag := true
else if ms.but = MB_LEFT then
PutPixel (ms.loc.x - 1, ms.loc.y - 1, Random (WHITE))
end;
CloseGraph
end.Итак мы в цикле опрашиваем мышь, если нажата правая кнопка (ms.but = MB_RIGHT), тогда выходим из программы. Если нажата левая кнопка, тогда ставим точку случайного цвета на экране. Вот и всё!.

