Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
спиос-методичка-часть2.doc
Скачиваний:
13
Добавлен:
13.04.2015
Размер:
266.75 Кб
Скачать
  1. Структура оконного приложения и обработка сообщений.

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

Изучить структуру оконных приложений в операционной система Windows, принципы передачи сообщений и их обработки.

    1. Указания по подготовке к выполнению лабораторной работы

Одной из основных проблем в многозадачной среде является организация эффективного выполнения набора параллельных задач, обмена данными между ними. Одним из способов повышения эффективности вычислений в многозадачной среде является необходимость исключения циклов опроса устройств ввода-вывода, и организацию вычисление по событийному принципу. При подготовке к лабораторной работе необходимо ознакомится с теоретическим описанием принципа обработки и передачи сообщений. Внимательно проработать вопросы организации программ реализующих событийный принцип работы. Ознакомиться набором функций WinApiдля передачи сообщений и создания оконных приложений..

При подготовке к работе необходимо изучить конспект лекций по указанной теме, методические указания, а также разделы, указанные в [16, c.763-809], [17, c.59-87].

    1. Обзор темы работы

Обработка сообщений лежит в основе работы приложений 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и у курсора мыши во время от­правки сообщения.

      1. Структура оконного приложения

В каждом оконном приложении можно выделить 4 части.

  1. Регистрация класса окна.

  2. Создание окна

  3. Цикл выбора сообщений из очереди

  4. Процедура обработки сообщений

Следует отметить, что также как и основное окно программы, все элементы управления являются окнами. Прежде чем окно будет создано, ОС должна знать какому классу оно будет принадлежать. После создания класса он может использоваться для создания любого количество окон, необходимых для приложения.

  1. Регистрация класса окна.

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

– 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).

  1. Создание окна

Создание окна осуществляется функциями 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 для каждого дочернего элемента управления и, если необходимо, инициализировать собственные структура данных.

  1. Цикл выбора сообщений

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

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

{TranslateMessage(&msg) ;

DispatchMessage(&msg) ;

}

Функция GetMessageвыбирает сообщение из очереди сообщений. За GetMessage следуют функции TranslateMessage и DispatchMessage. ФункцияTranslateMessageопределяет, является ли поступившее сообщение сообщением от алфавитно-цифровой клавиатуры, и если да, то посылает ещё одно сообщениеWM_CHAR, содержащее символ нажатой клавиши.

При регистрации класса окна было установлено соответствие WndProcвсем окнам этого окна. Во время создания конкретного окна устанавливается однозначное соответствие междуWndProcи дескриптором окна. На основании этой информации и дескриптора окна, со­держащегося в структуре сообщения, функцияDispatchMessageопределяет обработчик сообщений окна (WndProc) и отправляет данные сообщения в функциюWndProcэтого окна. По умолчанию функциейWndProcсчитается функция, содержащаяся в оп­ределении класса окна, но ее можно заменить другой, определив подкласс окна.

  1. Процедура обработки сообщений (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]

Посылая сообщения в элементы управления окна можно управлять их состоянием.