- •Структура оконного приложения и обработка сообщений.
- •Цель работы
- •Указания по подготовке к выполнению лабораторной работы
- •Обзор темы работы
- •Структура оконного приложения
- •Задания к лабораторной работе
- •Содержание отчета к лабораторной работе
- •Контрольные вопросы.
- •Многозадачность и многопоточность
- •Цель работы
- •Указания по подготовке к выполнению лабораторной работы
- •Обзор темы работы
- •Обобщенный алгоритм доступа к критическому ресурсу с использованием объектов синхронизации
- •Практические аспекты
- •Задания на лабораторную работу
- •Контрольные вопросы и задания
- •Управление распределением памяти (win api)
- •Цель работы
- •Указания по подготовке к выполнению лабораторной работы
- •Обзор темы работы
- •Порядок выполнения работы.
- •Задания к выполнению.
- •Содержание отчета
- •Контрольные вопросы и задания
- •Управление файлами
- •Цель работы
- •Указания по подготовке к выполнению лабораторной работы
- •Обзор темы работы
Структура оконного приложения и обработка сообщений.
Цель работы
Изучить структуру оконных приложений в операционной система Windows, принципы передачи сообщений и их обработки.
Указания по подготовке к выполнению лабораторной работы
Одной из основных проблем в многозадачной среде является организация эффективного выполнения набора параллельных задач, обмена данными между ними. Одним из способов повышения эффективности вычислений в многозадачной среде является необходимость исключения циклов опроса устройств ввода-вывода, и организацию вычисление по событийному принципу. При подготовке к лабораторной работе необходимо ознакомится с теоретическим описанием принципа обработки и передачи сообщений. Внимательно проработать вопросы организации программ реализующих событийный принцип работы. Ознакомиться набором функций WinApiдля передачи сообщений и создания оконных приложений..
При подготовке к работе необходимо изучить конспект лекций по указанной теме, методические указания, а также разделы, указанные в [16, c.763-809], [17, c.59-87].
Обзор темы работы
Обработка сообщений лежит в основе работы приложений Windows. Система и приложения вырабатывают сообщения в ответ на каждое событие, которое происходит в ОС.
Windowsвырабатывает сообщения в ответ на каждое аппаратное событие, такое как нажатие пользователем клавиши на клавиатуре или перемещение мыши. Каждый поток имеет собственную очередь сообщений и ОС передает сообщения в соответствующие очереди сообщений. Каждая нить в системе обрабатывает сообщения только из собственной очереди сообщений. Некоторые сообщения относятся ко всей системе или предназначены для нескольких нитей. Эти сообщения помещаются в очереди соответствующих нитей.
Сообщение – это фактически структура данных, которая определена следующим образом:
typedef struct tagMSG
{
HWND hwnd; /* дескриптор окна */
UINT message; /* идентификатор сообщения */
WPARAM wParam; /* значение wParam */
LPARAM lParam; /* значение lParam */
DWORD time; /* число миллисекунд с момента запуска */
POINT pt; /* положение курсора мыши в экранных
/* координатах */
} MSG;
Данные сообщения содержат дескриптор окна (hwnd), закодированный тип сообщения (message), данныеwParamиlParam, которые будут переданы функцииWndProc, отметку времени отправки сообщенияtime(в миллисекундах после запускаWindows) и структуруPOINT(pt), содержащую координатыxи у курсора мыши во время отправки сообщения.
Структура оконного приложения
В каждом оконном приложении можно выделить 4 части.
Регистрация класса окна.
Создание окна
Цикл выбора сообщений из очереди
Процедура обработки сообщений
Следует отметить, что также как и основное окно программы, все элементы управления являются окнами. Прежде чем окно будет создано, ОС должна знать какому классу оно будет принадлежать. После создания класса он может использоваться для создания любого количество окон, необходимых для приложения.
Регистрация класса окна.
В общем случае, класс окна это именованный набор информационных структур, описывающих возможное поведение и состояние окна, а также связывающих их (эти структуры) с подпрограммой обработки сообщений окна. Каждое окно обязано принадлежать какому-либо классу либо предоставляемому ОС либо зарегистрированному в программе. ОС предоставляет следующие основные классы:
– EDIT – строка ввода текста;
– LISTBOX– список;
– COMBOBOX– выпадающий список со строкой редактирования;
– BUTTON – кнопка;
и многие другие.
Основное окно, как правило, принадлежит классу, зарегистрированному в программе. Каждый класс характеризуется именем, которое является символьной строкой, заканчивающейся символом с кодом 0, с учетом регистра букв (например, EDITиEditразные классы). Регистрация класса осуществляется системным вызовомRegisterClassлибоRegisterClassEx. Рассмотрим расширенную регистрацию класса окна с помощьюRegisterClassEx.
Синтаксис: ATOM RegisterClassEx(CONST WNDCLASSEX* lpwc)
Возвращаемое значение АТОМ. В случае успешного выполнения – атомарное значение, являющееся уникальным идентификатором нового класса, который был зарегистрирован; в ином случае, возвращаемое значение равно 0.
lpwc CONST WNDCLASSEX*.Указатель на структуру данныхWNDCLASSEX, которая определена следующим образом:
typedef struct tagWNDCLASSEX
{
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hlnstance;
HICON hlcon;
HCURSOR hCursor;
HBRUSH hbrBaclcground;
LPCTSTR lps zMenuName;
LPCTSTR IpszClassName;
HICON hlconSm; } WNDCLASSEX;
Рассмотрим основные поля структуры.
cbSize UINT.Размер структуры в байтах. Установите в качестве значения этого членаsizeof(WNDCLASSEX)перед использованием структуры в функции.
Style UINT.Параметрstyleможет представлять собой один или несколько стилей, объединенных с помощью двоичного оператораOR (|). Список стилей см. в [Simon стр. 56-78].
lpfnWndProc WNDPROC.Указатель на функцию обратного вызова окна для обработки сообщений. (Описание функции обратного вызоваWndProcприведено ниже.)
cbClsExtra int.Число дополнительных байтов, которые должны быть распределены в конце структуры класса окна для хранения информации. См. описание функции SetClassLong[Simon].
cbWndExtra int.Число дополнительных байтов, которые должны быть распределены вслед за экземпляром окна. Если в приложении для регистрации диалогового окна, созданного с использованием директивыCLASSв файле ресурса, применяется структураWNDCLASS, приложение должно установить значение этого члена вDLGWINDOWEXTRA.
hInstance HINSTANCE.Дескриптор экземпляра, в котором находится оконная процедура для этого класса (обычно выступает дескриптор потока).
hIcon HICON.Дескриптор пиктограммы, которая предназначена для этого класса окна. Если это значение установлено вNULL, приложение должно выводить пиктограмму каждый раз, когда пользователь сворачивает окно.
hCursor HCURSOR.Дескриптор курсора, который предназначен для этого класса окна. Если это значение установлено вNULL, приложение должно устанавливать курсор каждый раз, когда курсор мыши уходит за пределы окна.
hbrBackground HBRUSH. Дескриптор кисти, которая предназначена для отображения фона окна. Вместо кисти может использоваться один из системных цветов,[Simon стр. 56-78]. Прибавляйте 1 к этим значениям для определения класса.
lpszMenuName LPCTSTR.Указывает на строку с нулевым символом в конце, содержащую имя меню, применяемого по умолчанию для этого класса. Устанавливается вNULL, если класс не имеет меню, применяемого по умолчанию.
lpszClassName LPCTSTR.Указывает на строку с нулевым символом в конце, содержащую имя класса. Это имя должно использоваться в параметреlpszClassNameфункцииCreateWindow.
hIconSm HICON.Дескриптор пиктограммы, которая предназначена для использования в строке заголовка окон, созданных с помощью этого класса. Размеры пиктограммы должны быть равны 16x16. Если этот член имеет значениеNULL, система ищет ресурс пиктограммы, указанный членомhIcon, чтобы найти пиктограмму подходящего размера для использования в качестве малой пиктограммы.
Во время регистрации класса окна устанавливается соответствие между окном класса и его обработчиком (В дальнейшем функцию обработчик сообщений окна будем называть WndProc).
Создание окна
Создание окна осуществляется функциями CreateWindowилиCreateWindowEx.
С помощью CreateWindowExсоздается перекрываемое, всплывающее или дочернее окно с расширенным стилем; во всем остальном эта функция идентичнаCreateWindow.
Синтаксис: HWND CreateWindowEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, HMENU hmenu, HINSTANCE hInstance, LPVOID lpvParam )
Параметры:
dwExStyle DWORD.Указывает расширенный стиль, который используется для создания окна. В качестве расширенного стиля может применяться один из стилей, перечисленных в табл. 3.5.
lpszClassName LPCTSTR.Указатель на чувствительную к регистру строку с нулевым символом в конце, содержащую допустимое имя класса для окна или целочисленное атомарное значение. Имя класса может быть создано с помощью функцииRegisterClass; оно также может представлять собой один из существующих классов, перечисленных в табл. 3.3. Если параметрlpszClassNameпредставляет собой атомарное значение, он должен быть создан с помощью предварительного вызова функцииGlobalAddAtom.
lpszWindowName LPCTSTR. Указатель на строку с нулевым символом в конце, которая содержит имя окна. Имя окна отображается в том месте, которое соответствует конкретному стилю окна.
dwStyle DWORD. Стиль окна, которое должно быть создано. Стиль состоит из значений, объединяемых друг с другом с помощью двоичного оператора OR. В качестве примера стиля можно указатьWS_CHILD | ES_LEFT. Стили могут составляться из значений, перечисленных в [Simon]
х int. Горизонтальная позиция левого верхнего угла окна или элемента управления, который должен быть создан. Если позиция не важна, используется значениеCW_USEDEFAULT. Позициихиуопределяются относительно левого верхнего угла экрана или, в случае дочерних окон и элементов управления, родительского окна. Все размеры измеряются в пикселях, поэтому дисплей с разрешающей способностью 640x480 имеет размеры 640 пикселей по горизонтали и 480 пикселей по вертикали.
y int. Вертикальная позиция левого верхнего угла окна или элемента управления, который должен быть создан. Если позиция не важна, используется значениеCW_USEDEFAULT.
nWidth int. Ширина окна или элемента управления по горизонтали. Если ширина не важна, используется значениеCW_USEDEFAULT.
пHeight int. Высота окна или элемента управления по вертикали. Если высота не важна, используется значениеCW_USEDEFAULT.
hwndParent HWND. Дескриптор родительского объекта окна или элемента управления. Если нет родительского окна, используется значениеNULL. Если родительское окно не задано, данное окно не будет уничтожено автоматически по завершении работы приложения. Для удаления окна перед закрытием приложения используетсяDestroyWindow.
hmenu HMENU. Дескриптор меню окна. Используйте значениеNULL, если должно применяться меню класса. Для элементов управления в качествеhmenuустанавливается целочисленное значение, представляющее собой идентификатор создаваемого элемента управления. Во всех сообщенияхWM_COMMANDпри выполнении какого-либо действия с этим элементом управления указывается данный идентификатор.
hInstance HINSTANCE. Дескриптор экземпляра прикладного модуля, создающего окно или элемент управления. В Windows 2000 это значение игнорируется.
lpvParam LPVOID. Указатель на данные, которые должны быть переданы в качестве параметраLPARAMсообщенияWM_CREATE. При создании окнаMDICLIENTиспользуйте указатель на структуруCLIENTCREATESTRUCT. Для большинства окон и элементов управления устанавливайте значениеlpvParamвNULL.
Возвращаемое значение: HWND. Возвращается дескриптор окна, принадлежащий вновь созданному окну, если функция была выполнена успешно;NULL, если окно нельзя было создать.
ОС автоматически посылает сообщения в WndProcприложения. Основная часть этих сообщений передается функцииDefWindowProc. По умолчанию функцияWndProcприложения должна отправлять сообщения, не обработанные приложением, в функциюDefWindowProc. Благодаря этому основная часть технической работы выполняется ОС, а приложение обрабатывает только те сообщения, которые его касаются.
При создании окна ОС не знает, какие элементы управления, и в каком месте окна должны быть установлены.
Когда функция CreateWindowсоздает главное окно приложения, она направляет в функциюWndProcпять сообщений. ФункцияWndProcобычно обрабатывает только сообщениеWM_CREATE, а остальные четыре сообщения передает функцииDefWindowProc. Приложение использует сообщениеWM_CREATEпри инициализации элементов управления окна. Сообщения перечислены в Таблица 1 .1 в порядке их получения.
Таблица1.1 – Сообщения, вырабатываемые функциейCreateWindow
Сообщение |
Описание |
WM_GETMINMAXINFO |
Определить размер и позицию создаваемого окна. |
WM_NCCREATE |
Должна быть вскоре создана неклиентская область окна. Память для окна распределена и линейки прокрутки инициализированы. |
WM_NCCALCSIZE |
Размер и позиция клиентской области окна определены. |
WM_CREATE |
Извещение о том, что должно быть создано окно. При получении этого сообщения выполняется инициализация окна. |
WM_SHOWWINDOW |
Окно должно быть вскоре отображено. |
При получении сообщения WM_CREATE,WndProcдолжна вызватьCreateWindow либо CreateWindowEx для каждого дочернего элемента управления и, если необходимо, инициализировать собственные структура данных.
Цикл выбора сообщений
Поток или процесс выбирает сообщения из очереди с использованием цикла обработки сообщений. Цикл обработки сообщений обычно имеет следующий вид:
while (GetMessage(&msg, NULL, 0, 0 ))
{TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
Функция GetMessageвыбирает сообщение из очереди сообщений. За GetMessage следуют функции TranslateMessage и DispatchMessage. ФункцияTranslateMessageопределяет, является ли поступившее сообщение сообщением от алфавитно-цифровой клавиатуры, и если да, то посылает ещё одно сообщениеWM_CHAR, содержащее символ нажатой клавиши.
При регистрации класса окна было установлено соответствие WndProcвсем окнам этого окна. Во время создания конкретного окна устанавливается однозначное соответствие междуWndProcи дескриптором окна. На основании этой информации и дескриптора окна, содержащегося в структуре сообщения, функцияDispatchMessageопределяет обработчик сообщений окна (WndProc) и отправляет данные сообщения в функциюWndProcэтого окна. По умолчанию функциейWndProcсчитается функция, содержащаяся в определении класса окна, но ее можно заменить другой, определив подкласс окна.
Процедура обработки сообщений (WndProc)
WndProc – является обобщенным названием всех обработчиков сообщений окна в программе. Каждая программа может иметь столько обработчиков, сколько окон создается в программе (при условии, что все они принадлежат разным классам). Соответственно каждая подпрограмма обработчик сообщений окна должна иметь своё уникальное имя.
WndProcосуществляет реакцию окна, на поступающие сообщения. Как было указано выше, данная функция вызывается изDispatchMessage(т.е. присутствует косвенный вызов этой функции, а не прямой).
Определение WndProcдолжно подчиняться следующему синтаксису:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Параметры: Все параметры имеют размер двойное слово.
hWnd HWND. Дескриптор окна, получающего сообщение.
uMsg UINT. Сообщение (WM_PAINTи т.д.). Это значение и следующие два значения будут получены функциейWndProcприложения при отправке сообщения приложению.
wParam WPARAM. ДанныеwParam, переданные с сообщением.
lParam LPARAM. ДанныеlParam, переданные с сообщением.
Возвращаемое значение: LRESULT. Значение зависит от обрабатываемого сообщения. Это значение возвращается из функцииWndProcприложения.
Как правило, WndProcреализуется в виде структурыswitch case.
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch( uMsg ) {
case WM_CREATE : { . . . }; break;
. . .
case WM_CHAR : { . . . }; break;
. . .
case WM_COMMAND : {
switch( wParam ) {
case 100 : { . . . }; break;
. . .
case 1000 : { . . . }; break;
}
. . .
case WM_DESTROY : { . . . }; break;
default :
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
return( 0L ) ;
}
Если сообщение не обрабатывается данной функцией, то она должна вызвать DefWindowProcи передать ей принятые параметры.
Помимо обработки сообщений возникающих от аппаратуры ЭВМ часто возникает необходимость передачи воздействиё или данных другим окнам или между элементами управления одного окна. В этом случае можно послать сообщение этому окну либо другому элементу управления. Посылка сообщений осуществляется функциями SendMessage,PostMessage.
SendMessageпосылает сообщение в очередь своего потока, аPostMessageможет посылать сообщения в другие потоки и процессы.
Функция SendMessageотправляет сообщение другому окну и ждет ответа. Это сообщение обходит очередь сообщений и все действия над ним выполняются немедленно. В приложениях функцияSendMessageчасто используется для обеспечения взаимодействия с окнами таких элементов управления, как кнопки и списки, если в программе есть ряд дочерних окон, каждое из которых имеет отдельные функции обработки сообщений. Окно-отправитель перезапускает обработку только после того, как окно-получатель обработает сообщение и возвратит результат.
Синтаксис: LRESULT SendMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Параметры: все параметры имеют размер двойное слово.
hWnd HWND. Дескриптор окна, которое должно получить сообщение. Если это значение установлено вHWND_BROADCAST, сообщение будет отправлено всем окнам верхнего уровня в системе.
uMsg UINT. Сообщение, которое должно быть отправлено.
wParam WPARAM. ЗначениеwParamдля этого сообщения.
lParam LPARAM. ЗначениеlParamдля этого сообщения.
Возвращаемое значение LRESULT. Возвращаемое значение зависит от отправленного сообщения.
Функция PostMessageпозволяет поместить сообщение в очередь, связанную с нитью, которая создала окно, и выполнить возврат, не ожидая ответа. Сообщения, которые находятся в очереди, могут быть выбраны путем вызова функцийGetMessageиPeekMessage.
Функция PostMessageобычно используется для выполнения другой части приложения после обработки текущего сообщения. ФункцияPostMessageне может применяться для отправки сообщений элементам управления, если должно быть получено возвращаемое значение.
Синтаксис: BOOL PostMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Параметры:
hWnd HWND. Дескриптор окна, принимающего выставленное сообщение. Если в качестве значения этого параметра установленоHWND_BROADCAST, сообщение будет выставлено для всех окон верхнего уровня в системе. Если в качестве значения этого параметра установленоNULL, функцияPostMessageведет себя аналогичноPostThreadMessageпри обработке сообщений, предназначенных для текущей нити.
uMsg UINT. Сообщение, которое должно быть выставлено.
wParam WPARAM. ЗначениеwParam, которое должно быть передано с сообщением.
lParam LPARAM. ЗначениеlParam, которое должно быть передано с сообщением.
Возвращаемое значение: BOOL. В случае успешного выполнения возвращаемое значение –TRUE; в ином случае возвращаемое значение –FALSE.
Каждый элемент управления обрабатывает определенное множество сообщений, перечень которых см. [http://msdn.microsoft.com/en-us/library/bb773169(VS.85).aspx]
Посылая сообщения в элементы управления окна можно управлять их состоянием.