Пасьянс

3.2.1.2. Описание окон, сообщений, и относящихся к ним данных и функций (сверху - вниз, начиная с наиболее крупных, заканчивая вспомогательными).

Программа состоит из главной функции WinMain, в которую входит обработчик событий switch, функции WindowFunc, DrawCards. Так же есть дополнительные функции FillCoords, Catch. Обработчик событий switch содержит следующие ветвления:

- WM_DESTROY: /* завершение программы */

- WM_VSCROLL:/*прокрутка, содержит свой обработчик событий*/

-SB_LINEDOWN://была нажата стрелка вниз

- SB_LINEUP: // вверх

- SB_PAGEUP: //было нажато над скролом

- SB_PAGEDOWN: //было нажато под скролом

- SB_THUMBTRACK: //бегунок был перетащен вручную

- WM_LBUTTONDOWN:/*нажата левая кнопка мышки*/

- WM_COMMAND:/*выбор пункта меню*/

- WM_TIMER: /* сообщение от таймера*/

- WM_PAINT: /*отрисовка клиентской области, вызывает функцию DrawCards*/

- WM_CREATE:/*была вызвана функция создания окна, здесь созданы элементы управления – поле редактора Edit box и Check Box */

Функция DrawCards:

Объявление

void DrawCards(HWND hwnd,int x,int y,char *msg, int i, int j,float sdvig);

Вызов

DrawCards(hwnd,100,10,"Откройте любую карту .",i,j,-cyChar*iVscrollInc);

hwnd- дескриптор окна;

2-й, 3-й параметры – координаты для вывода сообщения;

4-й – текст сообщения;

5-й, 6-й – индексы для доступа к каждой отдельной карте;

7-й – праметр сдвига перерисовки при прокрутке

Функция DrawCards рисует прямоугольники с помощью функции Rectangle в цикле:

for (i=0;i<16;i++)

Rectangle(hDC,x0[i],y0[i]=(y0[i]+sdvig*100),x1[i],y1[i]=(y1[i]+sdvig*100));

Sdvig- это расстояние, на которое карты должны перерисоваться с учетом скроллинга, функция DrawCards вызывается во время скроллинга, и в кач-ве параметра сдвига ей передается выражение: -cyChar*iVscrollInc где cyChar, iVscrollInc – числовые коэффициенты, положительные\отрицательные в зависимости от напрвления прокрутки.

Перерисовка при нажатии мышки происходит в ветвлении WM_LBUTTONDOWN с помощью функции BitBlt.

ФункцияFillCoords:

Текст функции

void FillCoords(int i, int X0, int Y0, int X1, int Y1)

{

x0[i] = X0;

y0[i] = Y0;

x1[i] = X1;

y1[i] = Y1;

return;

}

Заполняет массивы х0, у0, х1, у1 необходимыми координатами;

Вызов: FillCoords(0,113,157,247,322);

Функция Catch:

void Catch(int i, int j)

{

catched[i] = catched[j] = true;

}

Выполняется, если две карты оказываюся открытыми и с одинаковыми изображениями.

Сообщения программы

Программа посылает сообщения с помощью функции SendMessage в следующих местах:

1)При загрузке информации из текстового файла в поле редактора:

SendMessage(EdtHwnd, EM_REPLACESEL, FALSE, (LPARAM)(LPCTSTR)pBuffer);

EdtHwnd//дескриптор редактора- получателя

EM_REPLACESEL// позволяет к концу одной записи прибавлять другую, выводить по несколько файлов

WPARAM wParam, // первый параметр сообщения , равен нулю

pBuffer // буфер для текста

2)При завершении работы приложения, этим сообщением вызывается стандартный диалог сохранения файла

SendMessage(hwnd,WM_COMMAND,IDM_SAVE2,0);

hwnd//дескриптор окна- получателя

WM_COMMAND// посылаемое сообщение

3.2.1. Приложение под DOS 7.0.

3.2.1.1. Общий алгоритм работы программы

При загрузке программы (не важно, СОМ или ЕХЕ) перед образом программы в памяти находится область PSP (префикс программного сегмента) размером 256 байт, последние 128 байт которой называется DTA и является файловым буфером по умолчанию для устаревших файловых функций , так же она используется для хранения строки параметров командной строки. Содержимое командной строки, следующее за именем программы при ее вызове помещается в PSP, DTA со смещением 80h и максимальным размером 128. 1ый байт содержит кол-во символов параметров комстроки (длину), со второго (смещение 81h) начинаются символы параметров. Последний символ – всегда 0dh. Программа сначала копирует имя открываемого файла из PSP в сегмент данных ,а потом настраивает регистр ds на сегмент данных, т.к при старте программы загрузчик устанавливает регистры ds и es равные сегментному адресу PSP.

mov ax,@data;

mov es,ax

Ассемблер не может определить адрес data, он пределится лишь когда объектная программа будет скомпанована и загружена для выполнения. Поскольку згрузчик может расположить программу в любом месте памяти, ассемблер оставляет данный адрес открытым, компоновщик должен подставить вместо @data действительный адрес.

mov di,81h ;начало комстроки

mov al," "

mov cx,128 ;макс длина

cld ; сбрасывает флаг DF, это необходимо, чтобы на каждом шаге

; копирования происходило увеличение

; (а не уменьшение) содержимого DI на единицу.

repe scasb ;пропускает пробелы, пока не найдет символ «не пробел»,

; причем даже когда будет найден такой символ

;di увеличится на 1

dec di ;вернет значение di, так что он будет являтся смещением 1-го

;отличного от пробела символа ES:[DI]

push di

pop si ;его адрес- в si siß---diß---ES

mov ax,@data;вручную настраиваем es на сегмент данных

mov es,ax ;ax в es т.к нет команд для непосредственной пересылки

; данных из памяти в регистр es

mov cl,ds:[80h]; кол-во символов в комстроке

dec cl ; избавляемся от Enter’а , введенного пользователем

lea di,FILE ;

rep movsb ; скопировать комстроку в FILE по адресу di

push es ;было esß---@data, настроим ds на сегмент данных

pop ds ; теперь dsß---es а значит dsß-@data

Далее программа открывает файл с помощью функции 3Dh , режим доступа –только чтение. Далее создается дескриптор файла. После этого файл читается функцией 3fh, дескриптор файла заносится в регистр bx, в регистр сх- число байтов, которое нужно прочитать, в регистр dx адрес области ввода. ( сх совпадает с размером буфера для чтения). Правильно выполненная операция считывает запись в память, сбрасывает флаг CF и устанавливает в регистре ах число дейсвительно прочитанных байтов. Нулевое значение в ах означает попытку чтения после конца файла. Мы каждый раз сравниваем значение в регистрах сх и ах и , если значения совпадают, закрываем файл с помощью функции 3Еh , предварительно занеся в регистр bx дескриптор файла.

Далее мы обрабатываем массив с файла. В регистре сх записываем, сколько нам необходимо прочитать, обращение к символу в строке происходит через регистр обработки цепочечных операций si: BUFER[si]. Мы сравниваем символ и если он совпадает с нужным нам символом мы увеличиваем счетчик и продвигаемся по строке дальше, увеличивая si. Поскольку значение счетчика –число, то для вывода на экран его необходимо преобразовать в строку (ASCII-формат).В коде ASCII на каждый символ требуется 1 байт. Например, число 25 в ASCII-коде имеет внутреннее представление 3235. Значит, чтобы преобразовать двоичное число, его нужно делить на 10 пока результат не станет меньше 10. Остатки, которые лежат в границах от 0 до 9 образуют число в ASCII-формате. Последнее частное и все остатки от деления (снизу вверх) должны записываться в память с тройками:


Страница: