Главная > Методическое пособие


3. Лабораторная работа №2

3.1. Цель работы

Получить практические навыки работы с дополнительной памятью по спецификации EMS.

3.2. Основные теоретические положения

Прежде чем перейти к изучению способов работы с расширенной памятью, рассмотрим основные термины, относящиеся к типам памяти IBM-PC.

  1. Стандартная (основная) память – Conventional Memory. Это первые 640 Кб адресного пространства, доступная MS-DOS и программам реального режима. В некоторых BIOS присутствует опция изменения размера основной памяти до 512 Кб. Основная память распределяется следующим образом:

  • 00000h – 003FFh – таблица векторов прерываний;

  • 00400h – 004FFh – BIOS Data Area – область данных BIOS, в которой хранятся важные сведения о системе;

  • 00500h – 00xxxh – DOS Area – область DOS;

  • 00xxxh – 9FFFFh – область данных пользователя.

  1. Верхняя память (UMA – Upper Memory Area). Верхняя память имеет области различного назначения, которые могут быть заполнены буферной памятью различных адаптеров (например, видео- и сетевых), постоянной памятью (ROM BIOS) или оставаться незаполненными. С появлением механизма страничной переадресации (у процессоров 80386 и выше) свободные области верхней памяти используются для отображения в них доступной расширенной памяти. Этот механизм обеспечивается драйвером EMM386.EXE. Стандартное распределение верхней памяти выглядит следующим образом:

  • A0000h – BFFFFh – 128 Кб видеопамяти. Обычно эта память используется не полностью.

  • C0000h – DFFFFh – 128 Кб, постоянной и оперативной памяти адаптеров, использующих расширения ROM BIOS (например сетевые карты с возможностью загрузки по сети) и специальное ОЗУ, разделяемое с системной шиной.

  • E0000 – EFFFFh – 64 Кб свободной области, иногда занимаемой системной BIOS.

  • F0000 – FFFFFh – 64 Кб системной BIOS.

  • FD000h – FDFFFh – ESCD (Extended System Configuration Data) - область энергонезависимой памяти (NVRAM), используемая для конфигурирования устройств Plug and Play. Эта область имеется только при наличии PnP BIOS, ее положение и размер жестко не заданы.

  1. Память выше 100000h – Extended Memory – дополнительная память, непосредственно доступная только в защищенном режиме работы процессора (80286 и выше). В ней выделяется область 100000h – 10FFEFh (высокая память, HMA – High Memory Area) – единственная область памяти, доступная процессорам 80286 и выше в реальном режиме при открытой адресной линии A20. Эту область драйвер HIMEM.SYS делает доступной для размещения ядра DOS с целью экономии стандартной памяти.

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

  1. Отображаемая память – EMS (Expanded Memory Specification) – программная спецификация использования дополнительной памяти DOS-программами реального режима через 4 страницы по 16 Кб. Эти страницы, расположенные в области UMA (обычно с адреса D0000h), могут отображать любую область дополнительной памяти. В компьютерах на процессорах 80386 и выше спецификация EMS реализуется программно и память, доступная EMS, может выделяться динамически из числа дополнительной памяти. Обращение прикладных программ к памяти EMS осуществляется через диспетчер памяти (EMM – Expanded Memory Manager), в MS-DOS эти функции выполняет драйвер EMM386.EXE.

  2. Расширенная память XMS (extended Memory Specification) – программная спецификация использования дополнительной памяти DOS-программами через переключение в защищенный режим и обратно. Данная спецификация в MS-DOS поддерживается драйвером HIMEM.SYS, поверх которого может быть загружен драйвер EMM386.EXE, использующий память XMS для эмуляции EMS-памяти.

3.2.1. Работа с дополнительной памятью по спецификации EMS

Для работы с дополнительной памятью по спецификации EMS будут использоваться функции диспетчера отображаемой памяти EMM. EMM использует программное прерывание INT 67h. Для вызова функции драйвера необходимо ее номер занести в регистр AX и вызвать прерывание INT 67h. Результат выполнения функции возвращается в регистре AH. Ненулевое значение указывает на возникновение ошибки в ходе выполнения функции.

Далее будут рассмотрены стандартные функции EMM.

Функция 4000h

Назначение: получение состояния EMM. Функция возвращает в регистре AH текущее состояние EMM. При наличии и нормальной работе драйвера отображаемой памяти значение, возвращаемое в регистре AH – 0.

Пример использования функции:

MOV AX, 4000H ; функция получения состояния EMM

INT 67H ; вызов прерывания EMM

OR AH, AH ; проверка на ненулевое значение

JNZ Error ; переход по ошибке

Error:

Функция 4100h

Назначение: получение сегментного адреса окна отображаемой памяти. Функция возвращает в регистре BX сегментный адрес окна отображаемой памяти, который может быть использован для получения доступа к страницам отображаемой памяти.

Пример использования функции:

MOV AX, 4100H ; функция получения сегмента окна

INT 67H ; вызов прерывания EMM

OR AH, AH ; проверка на ненулевое значение

JNZ Error ; переход по ошибке

Error:

Функция 4200h

Назначение: получение общего количества страниц EMS и количества свободных страниц. Функция возвращает в регистре DX общее количество страниц памяти EMS (размер страницы – 16 Кб), а в регистре BX – количество свободных страниц.

Пример использования функции:

MOV AX, 4200H ; функция получения количества страниц

INT 67H ; вызов прерывания EMM

OR AH, AH ; проверка на ненулевое значение

JNZ Error ; переход по ошибке

Error:

Функция 4300h

Назначение: выделение EMS памяти и получение дескриптора выделенного блока памяти. Дескриптор является 16-битным числом, идентифицирующим блок выделенной EMS памяти. Дескриптор используется для получения доступа к EMS памяти после ее выделения. Для вызова функции необходимо указать ее номер в регистре AX и количество выделяемых страниц EMS-памяти в регистре BX. Функция возвращает дескриптор выделенного блока памяти в регистре DX.

Пример использования функции:

MOV AX, 4300H ; функция выделения страниц EMS

MOV BX, 0100H ; 256 страниц (всего 4 Мб)

INT 67H ; вызов прерывания EMM

OR AH, AH ; проверка на ненулевое значение

JNZ Error ; переход по ошибке

Error:

Функция 44h

Назначение: отображение EMS-памяти в окно верхней памяти. Для вызова данной функции необходимо указать ее код в регистре AH, а также указать:

  1. В регистре AL – номер физической страницы окна отображения (от 0 до 3).

  2. В регистре BX – номер логической страницы из блока EMS-памяти, выделенной при помощи функции 4300h.

  3. В регистре DX – дескриптор выделенного блока памяти, возвращенный функцией 4300h.

Функция возвращает в регистре AH код ошибки или 0 при отсутствии ошибки.

Пример использования функции:

MOV AH, 44H ; функция отображения страницы

MOV AL, 1 ; физическая страница 1

MOV BX, 007Fh ; логическая страница 127

MOV DX, EMSHandle ; дескриптор блока памяти

INT 67H ; вызов прерывания EMM

OR AH, AH ; проверка на ненулевое значение

JNZ Error ; переход по ошибке

Error:

Функция 4500h

Назначение: освобождение блока ранее выделенной памяти. Для вызова функции необходимо в регистре DX указать дескриптор ранее выделенного функцией 4300h блока памяти.

Пример использования функции:

MOV AX, 4500H ; функция освобождения памяти

MOV DX, EMSHandle ; дескриптор блока памяти

INT 67H ; вызов прерывания EMM

OR AH, AH ; проверка на ненулевое значение

JNZ Error ; переход по ошибке

Error:

Функция 4600h

Назначение: получение номера версии EMM. Данная функция возвращает в регистре AL номер версии EMM в двоично-десятичном формате. Младшие 4 бита регистра AL определяют номер подверсии, а старшие 4 бита – номер основной версии. Например, для EMM версии 3.2 значение, возвращаемое в регистре AL, бедет 0x32.

Пример использования функции:

MOV AX, 4600H ; функция получения версии EMM

INT 67H ; вызов прерывания EMM

OR AH, AH ; проверка на ненулевое значение

JNZ Error ; переход по ошибке

Error:

3.2.2. Пример программы

Следующая программа, написанная на языке C++, демонстрирует использование функций EMM для работы с дополнительной памятью по спецификации EMS. Программа копирует указанный файл целиком в EMS, а затем сохраняет его под указанным именем, считывая из EMS.

#include <fstream.h>

#include <dos.h>

#include <dir.h>

// размер страницы EMS

#define FRAME_SIZE 0x4000

// указатель на окно EMS

void far *PageFrame;

void main(int argc, char **argv)

{

REGPACK regs;

ffblk ffblk;

long FileSize;

long Remainder;

unsigned int NumPages;

unsigned int Handle;

unsigned int k;

ifstream in;

ofstream out;

char *buf;

if (argc < 3)

{

cout << "Недостаточное количество параметров!\n";

return;

}

// установлен ли EMM?

regs.r_ax = 0x4000;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00)

{

cout << "Ошибка: драйвер EMM не установлен!\n";

return;

}

// открытие файла для чтения

in.open(argv[1], ios::binary);

if (!in)

{

cout << "Невозможно открыть файл!\n";

return;

}

// открытие файла для записи

out.open(argv[2], ios::binary);

if (!out)

{

cout << "Невозможно создать файл!\n";

in.close();

return;

}

// вычисление размера файла через поиск его по шаблону

if (findfirst(argv[1], &ffblk, FA_NORMAL | FA_ARCH) == -1)

{

cout << "Файл не найден!\n";

return;

}

FileSize = ffblk.ff_fsize;

// выделение памяти под буфер

buf = new char[FRAME_SIZE];

// try-блок для обработки исключений при работе с функциями EMM

try

{

// получение версии EMM

regs.r_ax = 0x4600;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00) throw 0x4600;

cout << "Версия EMM: " << char((regs.r_ax >> 4) + '0') <<

'.' << char((regs.r_ax & 0x000F) + '0') << '\n';

// получение сегмента окна EMS

regs.r_ax = 0x4100;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00) throw 0x4100;

cout << "Сегмента окна EMS: ";

cout << hex << regs.r_bx << "h\n";

// инициализация указателя на окно EMS

PageFrame = MK_FP(regs.r_bx, 0x0000);

// получение общего количества страниц EMS и числа свободных страниц

regs.r_ax = 0x4200;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00) throw 0x4200;

cout << dec;

cout << "Общее число страниц EMS: " << regs.r_dx;

cout << " (" << ((long)regs.r_dx << 4) << " Кб)\n";

cout << "Число свободных страниц EMS: " << regs.r_bx;

cout << " (" << ((long)regs.r_bx << 4) << " Кб)\n";

// вычисление необходимого числа страниц для хранения файла в памяти

NumPages = FileSize / FRAME_SIZE;

Remainder = FileSize % FRAME_SIZE;

if (Remainder) NumPages++;

// попытка выделить EMS-память

regs.r_ax = 0x4300;

regs.r_bx = NumPages;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00)

// код 0x87 или 0x88 указывает на недостаточное количество EMS

if ((regs.r_ax >> 8) == 0x87 ||

(regs.r_ax >> 8) == 0x88)

{

cout << "Недостаточно свободной EMS памяти!\n";

return;

}

else throw 0x4300;

Handle = regs.r_dx;

// цикл чтения файла в EMS-память блоками по 16 Кб

cout << "Чтение файла в память...";

for (k = 0; k < NumPages; k++)

{

// отображение очередной страницы EMS в окно

regs.r_ax = 0x4400;

regs.r_bx = k;

regs.r_dx = Handle;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00) throw 0x4400;

// чтение из файла в буфер

in.read(buf, FRAME_SIZE);

// запись из буфера в страницу EMS

memcpy(PageFrame, buf, FRAME_SIZE);

cout << '.';

}

cout << '\n';

// цикл записи файла из EMS-памяти блоками по 16 Кб

cout << "Запись файла из памяти...";

for (k = 0; k < NumPages; k++)

{

// отображение очередной страницы EMS в окно

regs.r_ax = 0x4400;

regs.r_bx = k;

regs.r_dx = Handle;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00) throw 0x4400;

// запись из страницы EMS в буфер

memcpy(buf, PageFrame, FRAME_SIZE);

// запись из буфера в файл с учетом остатка (когда размер файла

// не кратен 16 Кб

if (Remainder && k == NumPages - 1)

out.write(buf, Remainder);

else

out.write(buf, FRAME_SIZE);

cout << '.';

}

cout << '\n';

// освобождение выделенной памяти

regs.r_ax = 0x4500;

regs.r_dx = Handle;

intr(0x67, &regs);

if (regs.r_ax & 0xFF00) throw 0x4500;

}

// обработка исключительной ситуации

catch (int fNo)

{

cout << "\nОшибка вызова функции EMM " << hex << fNo << "h\n";

cout << "\tКод ошибки: " << (regs.r_ax >> 8) << "h\n";

}

// освобождение буфера и закрытие файлов

delete buf;

out.close();

in.close();

}

Примечание. Программа не работает под операционными системами Windows 2000 и Windows XP (выдается сообщение об отсутствии EMM).

3.3. Задания и методические указания
к выполнению работы

3.3.1. Задание на лабораторную работу

Написать программу на языке C/C++, использующую для выполнения конкретного задания функции диспетчера отображаемой памяти (EMM). Помимо выполнения конкретного задания программа должна выводить на экран следующую информацию:

  1. номер версии EMM;

  2. общее количество EMS-памяти;

  3. количество свободной EMS-памяти;

  4. сегментный адрес страничного кадра EMS.

Предусмотреть в программе выдачу сообщений при возникновении ошибок вызова функций EMM.

3.3.2. Методические указания к выполнению работы

Для вызова функций EMM используется функция intr библиотеки DOS языка C. Для передачи функции EMM значений регистров используется структура REGPACK. Описание и примеры использования функции intr и структуры REGPACK см. в разделе «Лабораторная работа №1».

3.4. Контрольные вопросы

  1. Какие типы памяти IBM PC Вы знаете?

  2. Какая информация хранится в верхней памяти (UMB)?

  3. Чем отличаются спецификации EMS и XMS?

  4. Каким образом можно получить доступ к странице EMS?

  5. Для чего служит дескриптор блока EMS-памяти?

3.5. Варианты заданий на лабораторную работу

  1. Написать программу, выполняющую сравнение двух файлов. Считать файлы в EMS и затем выполнить их побайтовое сравнение. В случае отличий вывести на экран смещение в файле, значение отличающегося байта из первого и из второго файла. Имена файлов вводятся в виде параметров программы с командной строки. Файлы должны иметь одинаковый размер. В противном случае выдать сообщение об ошибке.

  2. Написать программу для поиска строки в файле. Считать файл в EMS. Строка вводится с клавиатуры. Имя файла вводится в виде параметра программы с командной строки. В случае обнаружения в файле введенной строки вывести на экран соответствующее смещение в файле и продолжить поиск. Предусмотреть возможность поиска вне зависимости от регистра.

  3. Написать программу, записывающую в указанный файл шестнадцатеричный дамп памяти другого файла. Считать файл в EMS. Имена файлов вводятся в виде параметров программы с командной строки. Предусмотреть выдачу сообщения об ошибке при нехватке места на диске в процессе записи данных в файл.

  4. Написать программу для разбивки файла на несколько частей (фрагментов) заданного размера. Считать файл в EMS. Имя файла вводится в виде параметра программы с командной строки. Размер фрагмента вводится с клавиатуры. Имена файлов (фрагментов исходного файла) выбирать в формате FILENAME.N, где FILENAME – имя исходного файла, N – номер фрагмента. Предусмотреть выдачу сообщения об ошибке при нехватке места на диске в процессе записи данных в файл.

  5. Написать программу для объединения нескольких файлов в один файл. Считать файлы в EMS и затем сформировать новый файл, который является конкатенацией данных исходных файлов. Имена файлов вводятся в виде параметров программы с командной строки. Предусмотреть выдачу сообщения об ошибке при нехватке места на диске в процессе записи данных в файл.

4. Лабораторная работа №3

4.1. Цель работы

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

4.2. Основные теоретические положения

Программирование графического интерфейса пользователя в Windows 3.1 выполняется с использованием функций Windows API. Взаимодействие программы Windows с пользователем и системой осуществляется при помощи механизма сообщений.

Под сообщением понимается некая структура данных, которая содержит идентификатор окна, которому посылается сообщение и информацию о самом сообщении – его тип и данные, относящиеся к конкретному типу сообщения.

Сообщения передаются окну приложения. Окно приложения использует специальную оконную процедуру для обработки поступающих сообщений. Для передачи оконной процедуре сообщений используется очередь сообщений. Очередь сообщений выделяется системой для каждого приложения. Управление очередью сообщений обычно осуществляется из цикла функции WinMain, которая определяет точку входа в Windows-приложение.

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

Для создания окна используется специальная структура, называемая оконным классом. Оконный класс описывает такие характеристики окна, как стиль, цвет, значок, курсор мыши и указатель на оконную процедуру. Windows также поддерживает встроенные оконные классы – кнопки, переключатели, списки и т. д. Оконные классы идентифицируются символьным именем, которое присваивается оконному классу при его регистрации. При создании окна помимо указания его класса используются такие данные, как текст заголовка окна, размеры и положение окна, идентификатор родительского окна и др.

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

#include <windows.h>

#include <mem.h>

#define BITMAP_WIDTH 256

#define BITMAP_HEIGHT 128

const char szClassName[] = "ExWndClass";

const char szWindowName[] = "Простейшее Windows-приложение";

const int CMD_EXIT = 101;

HINSTANCE hInst;

void OnPaint(HDC hDC)

{

HDC MemDC = CreateCompatibleDC(hDC);

HBITMAP Bm = LoadBitmap(hInst, "BITMAP");

SelectObject(MemDC, Bm);

BitBlt(hDC, 0, 0, BITMAP_WIDTH, BITMAP_HEIGHT,

MemDC, 0, 0, SRCCOPY);

DeleteObject(MemDC);

DeleteObject(Bm);

}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

PAINTSTRUCT ps;

switch (msg)

{

case WM_DESTROY:

PostQuitMessage(0);

break;

case WM_LBUTTONDOWN:

MessageBox(hWnd, "Вы нажали левую кнопку мыши!",

"Сообщение", MB_OK | MB_ICONINFORMATION);

break;

case WM_RBUTTONDOWN:

MessageBox(hWnd, "Вы нажали правую кнопку мыши!",

"Сообщение", MB_OK | MB_ICONINFORMATION);

break;

case WM_COMMAND:

if (wParam == CMD_EXIT)

DestroyWindow(hWnd);

break;

case WM_PAINT:

BeginPaint(hWnd, &ps);

OnPaint(ps.hdc);

EndPaint(hWnd, &ps);

break;

default: return DefWindowProc(hWnd, msg, wParam, lParam);

}

return 0;

}

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASS wc;

MSG msg;

HWND hWnd;

hInst = hInstance;

memset(&wc, 0, sizeof(wc));

wc.style = CS_HREDRAW | CS_VREDRAW;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hInstance = hInstance;

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

wc.lpszClassName = szClassName;

wc.lpszMenuName = "MENU";

wc.lpfnWndProc = WindowProc;

RegisterClass(&wc);

hWnd = CreateWindow(szClassName, szWindowName,

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

HWND_DESKTOP, 0, hInstance, NULL);

if (!hWnd)

{

MessageBox(HWND_DESKTOP,

"Ошибка при создании окна!", "Ошибка",

MB_OK | MB_ICONSTOP);

return 0;

}

ShowWindow(hWnd, nCmdShow);

UpdateWindow(hWnd);

while (GetMessage(&msg, 0, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

В начале функции WinMain выполняется инициализация оконного класса. Функция LoadIcon используется для загрузки стандартного значка приложения. Функция LoadCursor используется для загрузки стандартного курсора мыши. Цвет окна (поле hbrBackground структуры WNDCLASS) устанавливается в стандартный цвет окна Windows. Параметр hInstance функции WinMain идентифицирует данный исполняемый модуль. Этот параметр используется в программе для загрузки различных ресурсов. Поле lpszMenuName структуры WNDCLASS используется для указания имени ресурса меню. При создании окна меню автоматически загружается из ресурсов исполняемого модуля.

Функция RegisterClass используется для регистрации класса окна. Далее зарегистрированный класс будет использован при создании окна.

Функция CreateWindow используется непосредственно для создания окна. При вызове функции указываются следующие параметры:

  1. имя оконного класса;

  2. заголовок окна;

  3. тип окна (в данном случае – обычное окно);

  4. расположение и размеры окна (в данном случае использованы значения по умолчанию – константы CW_USEDEFAULT);

  5. идентификатор родительского окна – в данном случае это рабочий стол (константа HWND_DESKTOP);

  6. идентификатор меню – в данном случае он равен 0, так как имя ресурса меню указано в оконном классе;

  7. идентификатор исполняемого модуля;

  8. указатель на параметр, передаваемый в сообщении создания окна – в данном случае он не нужен и равен NULL.

В случае успешного выполнения функция CreateWindow возвращает идентификатор окна. В случае возникновения ошибки возвращаемое значение равно 0.

Функция MessageBox используется для вывода сообщения в виде небольшого диалогового окна с текстом сообщения. При вызове функции указываются следующие параметры:

  1. идентификатор родительского окна;

  2. текст сообщения;

  3. заголовок сообщения;

  4. флаги – типы кнопок диалогового окна и тип значка.

Функция ShowWindow используется для отображения окна на экране. При вызове функции указывается идентификатор окна и то, каким образом отобразить окно (показать/скрыть и др.). В данном случае берется значение, переданное функции WinMain тем приложением, которое запустило данное приложение.

Функция UpdateWindow посылает окну сообщение о перерисовке, обновляя, таким образом, клиентскую часть окна.

Функция GetMessage используется для извлечения сообщения из очереди сообщений приложения. Для выполнения функции ей необходимо передать указатель на структуру сообщения (структура MSG), которая будет заполнена данными сообщения. Функция возвращает 0, если получено сообщение о закрытии главного окна приложения. Если очередь сообщений пуста, функция GetMessage ожидает появления сообщения в очереди.

Функция TranslateMessage используется для преобразования кодов виртуальных клавиш в коды ASCII.

Функция DispatchMessage используется для передачи полученного сообщения соответствующему окну.

Цикл обработки сообщений в функции WinMain состоит из следующих шагов:

  1. получить сообщение из очереди сообщения приложения (функция GetMessage);

  2. преобразовать коды виртуальных клавиш в ASCII-коды (функция TranslateMessage);

  3. передать сообщение окну приложения (функция DispatchMessage).

Цикл выполняется до тех пор, пока не получено сообщение о закрытии главного окна приложения.

При вызове оконной процедуры передаются следующие параметры:

  1. идентификатор окна, которому послано сообщение (параметр hWnd);

  2. код сообщения (параметр msg);

  3. 1-й параметр сообщения (wParam);

  4. 2-й параметр сообщения (lParam);

В Windows 3.1 параметр wParam имеет размер 2 байта (слово), а параметр lParam – 4 байта (двойное слово).

В оконной процедуре используется оператор switch для обработки кодов сообщений. В данном примере используются следующие сообщения:

  1. WM_DESTROY – посылается после закрытия окна;

  2. WM_LBUTTONDOWN – посылается при нажатии в окне левой кнопки мыши;

  3. WM_RBUTTONDOWN – посылается при нажатии в окне правой кнопки мыши;

  4. WM_COMMAND – посылается при выборе пункта меню;

  5. WM_PAINT – посылается при перерисовке окна.

В случае получения сообщения, для которого программой не предусмотрено обработки, вызывается оконная процедура по умолчанию – функция DefWindowProc, которой передаются все параметры оконной процедуры.

При получении сообщения WM_COMMAND параметр wParam содержит идентификатор пункта меню, который был выбран. В примере, если был выбран пункт меню ФайлВыход, вызывается функция DestroyWindow, которая закрывает окно и освобождает связанные с ним ресурсы. Помимо этого функция DestroyWindow посылает окну сообщение WM_DESTROY.

При получении сообщения WM_DESTROY в примере вызывается функция PostQuitMessage, которая записывает в очередь сообщений приложения сообщение о закрытии главного окна приложения. Это сообщение затем обрабатывается функцией GetMessage – она возвращает 0 и цикл обработки сообщений на этом завершается.

Рассмотрим действия, выполняемые при перерисовке окна.

Сообщение WM_PAINT посылается при необходимости перерисовки клиентской области окна. Сообщение посылается, например, при вызове функции UpdateWindow, или когда окно было перекрыто другим окном.

Функция BeginPaint подготавливает окно для перерисовки и заполняет поля структуры PAINTSTRUCT информацией о перерисовке. После вызова этой функции вызывается функция OnPaint, которая осуществляет вывод растрового изображения в окне. Одним из полей структуры PAINTSTRUCT, необходимым для вывода растрового изображения, является поле hdc – идентификатор контекста устройства. Контекст устройства представляет собой некий системный объект, используемый для вывода в окно или на принтер различных геометрических примитивов и растровых изображений.

Функция EndPaint сигнализирует оболочке о завершении перерисовки окна и всегда вызывается в паре с функцией BeginPaint.

Рассмотрим работу функции OnPaint.

Для вывода растрового изображения в окно его сначала необходимо загрузить из ресурса исполняемого модуля – это действие осуществляется функцией LoadBitmap. При выводе растрового изображения используется копирование пикселей с одного контекста устройства на другой. Поэтому необходимо создать новый контекст устройства – MemDC функцией CreateCompatibleDC. При вызове данной функции в памяти создается контекст устройства, совместимый с указанным контекстом устройства. Для копирования растрового изображения в контекст устройства используется функция SelectObject. Данная функция также используется при работе с различными режимами закраски и вывода линий. После подготовки контекста устройства вызывается функция BitBlt, которая осуществляет копирование пикселей с одного контекста устройства на другой. При вызове функции BitBlt указываются следующие параметры:

  1. контекст устройства, на который копируются пиксели;

  2. положение и размеры копируемой области;

  3. контекст устройства, с которого копируются пиксели;

  4. положение копируемой области на источнике копирования;

  5. режим копирования.

Результаты работы программы представлены на рис. 4.1.

Рис. 4.1 – результаты работы программы.

Дополнительные сведения о функциях Windows 3.1 API, предназначенных для работы с графическим интерфейсом пользователя можно получить в Windows 3.1 API Reference.

4.3. Задания и методические указания
к выполнению работы

4.3.1. Задание на лабораторную работу

Написать программу на языке C/C++, функционирующую в операционной среде Windows 3.1. Программа должна выполнять следующие функции:

  1. выводить на экран основное окно с меню;

  2. в меню должен присутствовать пункт «Выход», при выборе которого программа должна завершаться;

  3. программа также должна завершаться при закрытии основного окна;

  4. выполнять действия, указанные в конкретном задании.

4.3.2. Методические указания к выполнению работы

Для написания программы может быть использована программная среда Borland C++ 3.1 for Windows.

В качестве шаблона для программы может быть использован пример из теоретической части (см. пункт 4.2).

В каждом конкретном задании (см. пункт 4.5) указаны функции и сообщения Windows API, необходимые для его выполнения, не включая функции базового шаблона. Информацию и примеры использования указанных функций можно получить в Windows 3.1 API Reference (входит в состав Borland C++ 3.1 for Windows и других программных сред).

Программа должна быть написана лишь с использованием функций Windows API. Использование VCL, MFC, OWL и других библиотек классов не допускается.

Некоторые задания предполагают использования в программе ресурсов. Ресурсы создаются в программе Resource Workshop программной среды Borland C++ 3.1 for Windows.



Скачать документ

Похожие документы:

  1. Том 2 документации об аукционе для проведения открытого аукциона для субъектов малого предпринимательства

    Инструкция
    ... с некоторыми операционными системами) - Вес ... Методическое пособие по ... пособием и предназначена для использования на учебных занятиях по химии, и другим общеобразовательным дисциплинам ... выполнения лабораторных работ по биологии» ... (лота), указанным в томе ...
  2. Ищите тесты не только по названиям

    Тесты
    ... методического) уровня системы ... работой всех устройств ПК и процессом выполнения прикладных программ, называется 3. Операционные системы ... дисциплины ... , лабораторное оборудование ... пособия по ... по достижении: 108. Выполнение налогоплательщиком письменных указаний ...
  3. Постановление исполнительного комитета г казани 30 06 2009 №5258 об утверждении стандарта муниципальной услуги «предоставление общедоступного бесплатного начального общего основного общего среднего (полного) общего образования по основным

    Программа
    ... Д Д - 1.4 Методическое пособие для учителя К К - 1.5 Рабочие тетради по физике Д Д - 1.6 Хрестоматия по физике К** К** По возможности 1.7 Комплекты пособий для выполнения лабораторных ...
  4. III ПРИРОДНЫЙ ЗАКОН ПИТАНИЯ ЧЕЛОВЕКА

    Закон
    ... операционный ... указанный срок подлежат увольнению по профессиональной непригодности. Обязательно выполнение ... системы и системы обмена веществ, нарушается работа всей пищеварительной системы ... наглядные пособия, ... “Дисциплина” ... методически ... У лабораторных мышей ...
  5. Методическое пособие по по дисциплине «теоретические основы автоматизированного управления» и указания к выполнению лабораторных работ

    Методическое пособие
    ... Методическое пособие по по дисциплине «Теоретические основы автоматизированного управления» и указания к выполнению лабораторных работ Номер специальности – 230102 «Автоматизированные системы ... и под различными операционными системами. При этом ...

Другие похожие документы..