Лабораторная работа №1 Структура приложений MS Windows Цель работы:

advertisement
Лабораторная работа №1
Структура приложений MS Windows
Цель работы: Познакомить учащихся с процессом создания и структурой приложений Windows,
Назначение работы: Дать учащимся возможность ОСВОИТЬ на практике методику создания и
познакомить с принципами построения прикладных программ под ОС Windows, которыми
необходимо овладеть для успешного изучения операционной системы.
Описание работы
MS Windows является многозадачной операционной системой с графическим интерфейсом, В
отличие от программ для MS-DOS, приложения Windows не имеют доступа к ресурсам системы
напрямую. Общение с внешней средой происходит через WinAPl — прикладной программный
интерфейс. Система сама определяет, в какой момент времени какой задаче предоставить данный
ресурс.
Оконный интерфейс — средство разделения экрана между задачами. Для того чтобы вывести
какую-либо информацию, программа должна сначала создать окно, которое станет ее рабочей
областью.
Другое отличие программ, создаваемых под Windows, заключается в том, что теперь они узнают
о всех внешних событиях из сообщений, получаемых от системы. Сообщение — это структура
данных определенного формата, которая записывается в очередь сообщений приложения. Туда
оно попадает из общей системной очереди.
typedef struct tagMSG
HWND
hwnd;
//Идентификатор окна;
UINT
message; //Номер сообщения;
WPARAM wParam; //Дополнительные сведения о сообщении,
LPARAM lParam; //зависят от сообщения;
DWORD time;
//Время посылки сообщения;
POINT рt;
//Позиция
курсора
во
время
посылки
сообщения
} MSG;
Основной цикл выборки сообщений обычно размещается в главой функции программы. Для
программ, написанных на языке Си, она называется WinMain и с нее начинается выполнение. Ее
вид в общем следующий:
int
PASCAL
WinMain{HINSTANCE
hinstCurrent,
hinstPrevious,
LPSTR ipszCmdLine,
int nCmdShow)
{
//инициализирующие
действия
. . . . . . . .
MSG msg;
while (GetMessage (&msg, 0,0,0) )
{
DispatchMessage (&msg) ;
}
//завершающие действия
. . . . . .
return 0;
}
HINSTANCE
Через параметр hinstCurrent передается идентификатор текущей копии исполняемою модуля.
hinstPrevious содержит значение, принадлежащее предыдущей запущенной копии. IpszCmdLine —
это указатель на строку параметров командной строки, nCmdShow — предписание системы о том,
в каком виде должно быть выведено па экран главное окно приложения (свернуто, развернуто ц
т.п.).
После инициализации программа входит в цикл выборки сообщений, который продолжается до
самого завершения ее работы. Функция GetMessage выбирает следующее сообщение из очереди и
помещает его описание в структуру типа MSG. Для всех сообщений, кроме WM_QUIT, она
возвращает ненулевое значение. Это сообщение посылается процедурой главного окна при его
закрытии, после которого программа должна прекращать выполнение. После того, как сообщение
извлечено из очереди, оно должно быть направлено процедуре того окна, которому оно было
послано. Функция DispatchMessage
отвечает за распределение сообщений между окнами
приложения.
Исходный текст приложения Windows состоит, по крайней мере, из двух файлов. В одном
находится код программы (с расширением .с или .срр для языка Си), в другом (с расширением
.clef) — описание параметров создаваемого исполняемого модуля. Рассмотрим вид простейшего
приложения, выводящего на экран сообщение.
//файл 01_1.срр
#include<windows.h>
#pragma argsused
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE
hPrevInst,
LPSTR lpszCmdLine, int nCmdShow)
{
MessageBox(NULL,"Пример №1", "Лабораторная работа
№1",MB_OK); return 0;
}
//файл 01_l.def
NAME
PROG01_1
EXETYPE
WINDOWS
CODE
PRELOAD MOVEABLE DISCARDABLE
DATA
PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
EXPORTS
; ===List
your
explicitly
exported
functions
here===
Эта программа не создает ни одного окна и не реализует собственного цикла обработки
сообщений, используя цикл стандартного модального диалогового окна для вывода
информационных сообщений MessageBox. Первая строка включает заголовочный файл windows.h,
содержащий объявление большинства функций
WinAPI.
Функция MessageBox
показывает на экране окошко е кнопкой "ОК" и заданными значком, текстом и заголовком. Она
имеет следующий прототип:
int
MessageBox{hwndParent, lpszText, lpszTitle,
fuStyle)
HWND hwndParent;
//родительское
окно LPCSTR
lpszText;
//выводимый
текст
LPCSTR
lpszTitle;//заголовок
окна
UINT
fuStyle; //стили окна сообщений
Значение параметра fuStyle определяется комбинацией констант, которые в том числе
определяют, какие кнопки и какой значок будут у окна. Например, МВ_ОК задает одну кнопку
"OK", MB_YESNO — две кнопки "Да" и "Нет", MB_ICONSTOP — значок "Стоп",
MB_ICONQUEST ION — значок "Вопросительный знак". Функция возвращает константу,
соответствующую нажатой кнопке: IDYES означает кнопку "Да", IDОК — "Нет", и т.д.
Файл (.def) определения модуля предоставляет компоновщику информацию об экспортируемых
функциях, атрибутах и другой информации о создаваемой программе. Он состоит из нескольких
строк, содержащих команды. В таблице ниже приводится описание некоторых из них.
CODE
[FIXED|MOVEABLE]
Задает атрибуты сегмента кода, где FIXED
[DISCARDABLE|NONDISCARD ABLE] означает, что сегмент будет фиксирован в памяти.
[PREALOAD|LOADONCALL]
— MOVEABLE перемещаемым, DISCARDABLE
— сегмент может быть сброшен,
NONDISCARDABLE — сегмент не может
сбрасываться, PREALOAD — сегмент загружается
в память при загрузке программы,
LOADONCALL — только в случае
необходимости.
DATA [NONE|SINGLE|MULTIPLE]
Задает атрибуты сегмента данных. NONE
[FIXED|MOVEABLE]
означает, что сегмент данных отсутствует, SINGLE
— что для всех экземпляров программы
загружается только один сегмент, MULTIPLE
— что все экземпляры имеют собственные сегменты
данных.
DESCRIPTION "text"
Позволяет помещать текстовое описание в файл
модуля программы.
EXETYPE [WINDOWS|OS2|DOS4]
Тип системы, для которой создается
программа.
EXPORTS Имя [@Номер]
Используется для описания имен и
атрибутов экспортируемых функций. "Имя" — имя
функции, "Номер" — номер функции,
назначаемый ей.
HEAPSIZE Размер
Определяет размер локальной динамической
памяти (до 64 Кб).
IMPORTS Имя_для_обращения
=
Задает имена и атрибуты функций,
Имя_модуля
импортируемых из динамически загружаемых
.Номер_или_имя_фуннкции
библиотек. Имя для обращения — это имя, которое
будет носить эта функция в программе. Имя
модуля — это название файла библиотеки.
Номер или имя функции — это название или
номер функции в библиотеке.
LIBRARY Название
Задает имя создаваемой динамически
подключаемой
библиотеки.
Должно
совпадать с именем файла модуля.
STACKSIZE
Размер стека в байтах.
STUB "Программа"
Указывает на ЕХЕ-программу, которая будет
помещена в создаваемый исполняемый модуль и
будет запускаться из-под MS-DOS.
Следующий более сложный пример иллюстрирует механизм создания окон и обработки
поступающих в него сообщений.
//файл
01_2.ерр
#include<windows.h>
//прототип процедуры окна
LRESULT
CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM
wParam,
LPARAM
lParam);
//название для
класса окна
char szClassName[]="05162738 49";
//название
окна
char
szWindowName[]="Лабораторная работа №1.Пример №2.";
//идентификатор главного окна
HWND hMainWnd=NULL;
//главная функция программы
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
LPSTR ipszCmdLine, int nCmdShow)
{
//создадим класс окна
WNDCLASS wc;
we.style=0;//стиль класса окна we.lpfnWndProc=WindowProc;//процедура
окна we.cbClsExtra=O;//размер дополнительной памяти для класса
wc.cbWndExtra-O;//размер дополнительной памяти для окон
we.hInstance-hlnst;//идентификатор программы, которой
//принадлежит класс we.
hIcon=LoadIcon(hInst,IDI_APPLICATION)///стандартная
пиктограмма
we. hCursor=LoadCursor(hInst,IDC_ARROW);//стандартный курсор
wc.hbrBackground=COLOR_WINDOW+l; //стандартный цвет для фона
окна
we.lpszMenuNarae=NULL;//меню нет wc.lpszClassName=szClassName;//имя
класса
окна
//зарегистрируем класс окна if(!RegisterClass(&wc))
{
//если ошибка,
выведем сообщение MessageBox(NULL,
"Ошибка
регистрации класса
окна.", "Сообщение",МВ_ОК|MB_ICONSTOP);
return
-1;
}
//создадим окно
hMainWnd=CreateWindow(
szClassName,//имя класса окна szWindowName,//название окна
WS_OVERLAPPEDWINDOW,//перекрывающееся окно
CW_USEDEFAULT,CW_USEDEFAULT, //положение по умолчанию
CW_USEDEFAULT,CW_USEDEFAULT,//размеры по умолчанию HWND
DESKTOP,//родительское окно — рабочий стол
NULL,//меню нет
hInst,//идентификатор программы-владелецы окна
NULL);//параметров нет if(hMainWnd==NULL)
{
//если
ошибка,
выведем сообщение
MessageBox (NULL',
"Ошибка регистрации класса окна.",
"Сообщение",МВ_ОК|MB_ICONSTOP);
return
-1;
}
//покажем окно на экране ShowWindow(hMainWnd,SW_SHOW) ;
//обновим его
содержимое UpdateWindow(hMainWnd);
//цикл
обработки
сообщений
MSG
msg;
while(GetMessage(&msg,0,0,0) )
{
DispatchMessage{&msg);
}
return 0;
}
//определение процедуры окна
LRESULT
CALLBACK _export
WindowProc(HWND hwnd, UINT msg,
WPARAM
wParam,
LPARAM
lParam)
//обработаем сообщения
switch(msg)
{
//перерисовка окна
case
WM_PAINT:
{
PAINTSTRUCT
ps;
HDC
hdc=BeginPaint(hwnd,&ps)///начнем вывод
//напечатаем сроку
Техtout(hdc,10,10,"Нестираемое сообщение.",22) ;
EndPaint(hwnd,&ps);//завершим вывод break;
} //нажатие левой кнопки мыши
сазе WM_LBUTTONDOWN:
{
HDC hdc=GetDC(hwnd);
TextOut(hdc,10,50,"Нажата левая кнопка мыши.",25);
ReleaseDC(hwnd,hdc); break;
}
//нажатие
правой
кнопки мыши case WM_RBUTTONDOWN:
{
HDC hdc=GetDC(hwnd);
TextOut(hdc,10,90,"Нажата правая
кнопка мыши.",26);
ReleaseDC(hwnd,hdc); break; }
//окно
закрывается case
WM_CLOSE:
//пошлем сообщение WM_QUIT программе
PostQuitMessage(0); break; //остальные
сообщения
передадим
стандартной фукнции
окна
default:
return
DefWindowProc(hwnd,
msg,
wParam,
lParara);
}
return
0;
} //файл
01_2.def
NAME
PROG01_2
EXETYPE
WINDOWS
CODE
PRELOAD MOVEABLE
DISCARDABLE
DATA
PRELOAD MOVEABLE
MULTIPLE
HEAPSIZE
1024
EXPORTS
;
===List
your
explicitly exported
functions
here===
Каждое окно создается на основе некоторого класса, который определяет его поведение. К
одному и тому же классу может принадлежать несколько окон. Примерами окон, создаваемых на
базе стандартных классов являются кнопки, выпадающие списки, полосы прокрутки и т.п. В
данном случае программа регистрирует собственный класс окна. Он определяется следующей
структурой:
typedef struct tagWNDCLASS {
UINT
style;
//стили класса
WNDPROC
lpfnWndProc;
//указатель на процедуру окна
int
cbClsExtra;
//дополнительная
память
под класс
int
cbWndExtra;
//дополнительная память под окно
HINSTANCE hInstance; //экземпляр модуля
HICON
hIcon;
//пиктограмма HCURSOR hCursor;
//курсор HBRUSH
hbrBackground;
//фон окна
LPCSTR
lpszMenuName;
//название меню
LPCSTR
lpszClassName; //название класса } WNDCLASS;
Поле style определяет стили класса, влияющие на все окна, создаваемые на его основе. Они
задаются комбинацией констант. Среди них можно отмстить следующие: CS_DBLCLKS
— окна различают двойные щелчки мышью, CS_HREDRAW — при изменении горизонтального
размера окна происходит его полная перерисовка, CS_VREDRAW — полная перерисовка
происходит при изменении вертикального размера, CS_NOCLOSE
— запрещает пункт "Закрыть" в системном меню окна. В поле lpfnWndProc должен
записываться указатель на процедуру, которая будет обрабатывать сообщения для окон,
созданных на базе данного класса. В полях hIcon и hCursor должны находиться
идентификаторы загруженных ресурсов пиктограммы и курсора. Загрузка производится
функциями LoadIcon и LoadCursor:
HICON LoadIcon(hinst, pszIcon)
HINSTANCE hinst; // идентификатор экземпляра модуля
LPCSTR pszIcon;
// имя или идентификатор ресурса пиктограммы
HCURSOR LoadCursor(hinst, pszCursor)
HINSTANCE hinst; // идентификатор экземпляра модуля
LPCSTR pszCursor; // имя или идентификатор ресурса курсора
Программа загружает ресурсы стандартных курсора и пиктограммы, используя для этого
константы IDC_ARROW и IDI_APPLICATION. Параметр задает способ закраски фона. Он может
содержать либо идентификатор физической кисти, либо один из стандартных цветов, например:
COLOR_WINDOW — выбранный в Панели управления цвет для фона окна,
COLOR_BACKGROUND — цвет рабочего стола и т.д. Параметр lpszMenuName задает имя меню,
которое будет выбираться для всех окон, для которых не задано собственное меню. Параметр
lpszClassName указывает на имя класса, которое будет его однозначно идентифицировать и
использоваться при создании окон.
После описания класса необходимо его зарегистрировать в системе. Для этого используется
функция RegisterClass:
ATOM RegisterClass(lpwc)
const WNDCLASS FAR* lpwc;
//адрес структуры с данными класса
В случае успеха она возвращает значение-атом, идентифицирующее этот класс, в случае ошибки
— нулевое значение.
Для того, чтобы создать окно, используется функция
CreateWindow:
HWND
CreateWindow(lpszClassName,
lpszWindowName,
dwStyle,
x,
y, nWidth, nHeight, hwndParent,hmenu, hinst, lpvParam)
LPCSTR lpszClassName;
//имя класса окна
LPCSTR lpszWindowName;
//название окна (показывается в заголовке)
DWORD dwStyle;
//стили окна
int x;
//горизонтальная позиция окна
int у;
//вертикальная позиция окна
int nWidth;
//ширина окна
int nHeight;
//высота окна
HWND hwndParent;//родительское OKHO
HMENU hmenu; //идентификатор меню или дочернего окна
HINSTANCE hinst; //идентификатор экземпляра приложения void FAR*
lpvParam;
//дополнительные параметры
Параметр lpszClassName должен указывать на имя класса-основы окна; lpszWindowName —
указатель на строку-имя окна, показываемое в его заголовке; dwStyle — стили окна, WS_O
VERLAPРЕDWINDOW
определяет стандартное перекрывающееся окно с рамкой,
заголовком, системным меню, кнопкой минимизации и максимизации; для параметров х, у, nWidth
и nHeight задано значение CW_USEDEFAULT, устанавливающее размеры и положение окна по
умолчанию; в качестве
значения
hwndParent
указана
константа
HWND_DESKTOP, указывающая, что родительское окно у данного окна — рабочий стол.
После того, как окно создано, оно должно быть показано на экране. Для этого используется
функция ShowWindow, а затем функция UpdateWindow, которая обновляет его содержимое:
BOOL ShowWindow(hwnd, nCmdShow)
HWND hwnd;
//идентификатор окна
int nCmdShow;
//команда void UpdateWindow(hwnd)
HWND hwnd;
//идентификатор окна
Параметр nCmdShow первой из них определяет то, что надо сделать с окном. Его значение могут
быть те же, что и у последнего параметра функции WinMain. SW_HIDE, например, означает
скрыть окно, SW_SHOW — показать в текущей позиции и размере, SW_SHOWMAXIMIZED —
максимизировать и т.д..
Процедура окна WinclowProc — это функция, которая вызывается системой при поступлении
сообщений окнам, за которые она отвечает. Она должна быть объявлена как экспортируемая
(_export). Параметр hwnd определяет идентификатор окна, для которого послано сообщение, msg
— номер сообщения (для их обозначения используются константы, например, событию нажатия
левой кнопки мыши соответствует WM_LBUTTONDOWN, закрытию окна — WM_CLOSE и т.п.)В данном примере производится обработка четырех сообщений.
Сообщение WM_PAINT посылается окну, когда его внутренняя область должна быть
перерисована, например, когда оно всплывает из-под других окон или после вызова функции
UpdateWindow. Для того, чтобы отобразить необходимую информацию, программа должна
получить контекст устройства, используемого всеми функциями рисования. Он возвращается
функцией BeginPaint:
HDC BeginPaint(hwnd, lpps)
HWNDhwnd;
//идентификатор
окна
PAINTSTRUCT
FAR*
lpps;
//структура, описывающая зарисовываемую область
Она подготавливает окно для рисования, создает для него контекст устройства и возвращает его
идентификатор. После рисования он должен быть обязательно освобожден при помощи функции
EndPaint:
void bndPaint(hwnd, lpps)
HWND hwnd;
//идентификатор окна
const PAINTSTRUCT FAR* lpps;//указатель на структуру с данными
перерисовываемой области
Эта пара функций должна вызываться только в ответ на сообщение WM_PAINT. При выводе в
других ситуациях должны быть использованы следующие функции:
HDC GetDC(hwnd) HWND hwnd;
//идентификатор окна
int ReleaseDQhwnd, hdc) HWND hwnd;//идентификатор окна
HDC hdc; //контекст освобождаемого устройства
Для вывода текста используется функция TextOut: BOOL TextOut(hdc, nXStart,
nYStart. lpszString, cbString)
HDC hdc;
//идентификатор контекста устройства
int nXStart;
//Х-координата начальной позиции вывода
int nYStart;
//У-координата начальной позиции вывода
LPCSTR lpszString; //указатель на выводимую строку int cbString;
//длина строки в символах
В качестве первого параметра она принимает контекст идентификатор контекста устройства,
полученный при помощи функций BeginPaint или GetDC, второй и третий — координаты точки,
от которой рисуется строка (по умолчанию левый верхний угол внутренней области окна имеет
координаты (0,0)), третий и четвертый — это указатель на выводимую строку и ее длина в
символах.
Сообщение WM_CLOSE посылается окну, когда оно должно быть закрыто. Когда закрывается
главное окно программы, она должна завершить свою работу. Обычно для этого используется
сообщение WM_QUIT, помещаемое в очередь приложения функцией PostQuitMessage:
void PostQuitMessage(nExitCode)
int nExitCode;
//код завершения
PostQuitMessage извещает систему о том, что программа скоро закончит свою работу, посылает
WM_QUIT и тотчас же возвращает управление назад.
Все необработанные сообщения должны быть переданы стандартной процедуре обработки. Она
вызывается функцией DefWindowProc, которая принимает те же параметры, что и процедура окна:
LRESULT DefWindowProc(hwnd, uMsg, wParam, lParam)
HWND hwnd;
//идентификатор окна
UINT uMsg;
//код сообщения
WPARAM wParam;
//дополнительные параметры, из значение
LPARAM lParam;
//зависит от сообщения
Download