Ассемблер для Windows


Пример манипуляции с меню



Рисунок 2.4.1. Пример манипуляции с меню.

Программа на Рисунок 2.4.1 имеет ряд механизмов, к обсуждению которых я намерен сейчас приступить. Для начала замечу, что в программе используются три ресурса: два меню и таблица акселераторов (см. файл ресурсов).

1. Первое, на что хочу обратить Ваше внимание, - это переменная PRIZN. В ней хранится состояние меню: 2 - загружено меню MENUP, 1 - меню отсутствует, 0 - загружено меню MENUC. Начальное состояние обеспечивается заданием меню при регистрации класса окна:

MOV DWORD PTR [WC.CLMENNAME], OFFSET MEN

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

3. Еще одно событие, которое происходит при нажатии кнопки, это смена меню. Интересно, что смена меню происходит автоматически, если мы загрузим и установим новое меню.

4. Выбор одного из пунктов меню MENUP также приводит к смене меню. Здесь должно быть все понятно, поскольку обращение идет к тому же участку программы, что и в случае нажатия кнопки.

5. Интересная ситуация возникает с акселератором. Акселераторная клавиша у нас F5. При ее нажатии генерируется такое же сообщение, как при выборе пункта "Четвертый" меню MENUP. Важно то, что такое же сообщение будет генерироваться и тогда, когда загружается меню MENUC и когда меню не будет. А поскольку наша процедура обрабатывает сообщение в любом случае, клавиша F5 будет срабатывать всегда.

6. Рассмотрим теперь то, как производится определение названия выбранного пункта меню. Центральную роль в этом механизме играет сообщение WM_MENUSELECT. Это сообщение приходит всегда, когда выбирается пункт меню. Тут важно отметить, что когда мы активизируем меню, то в начале приходит сообщение WM_MENUSELECT со значением LPARAM, которое определяет идентификатор меню равным нулю. Этим целям служат строки:




CMP WORD PTR [EBP+14H], 0 JE FINISH
7. По получении сообщения WM_MENUSELECT в младшем слове параметра WPARAM может содержаться либо идентификатор пункта меню, либо номер заголовка выпадающего меню. Это ключевой момент. Нам важно это знать, так как строка заголовка выпадающего меню и строка пункта меню получаются по-разному. Определить, что выбрано, можно по старшему слову WPARAM. Мы используем для этого константу MF_POPUP:
TEST WORD PTR [EBP+12H], MF_POPUP.
Обратите внимание, как удобна и как кстати здесь команда SETNE.
8. Далее, для получения строки-названия используется функция GetMenuItemInfo. Третьим параметром этой функции как раз и может быть либо ноль, либо единица. Если ноль, то второй параметр - это идентификатор пункта меню, если единица, то второй параметр - номер заголовка выпадающего меню. Четвертым параметром является указатель на структуру, которая и будет заполняться в результате выполнения функции. Некоторые поля этой структуры должны быть, однако, заполнены заранее. Обращаю внимание на поле dwTypeData, которое должно содержать указатель на буфер, получающий необходимую нам строку. При этом поле cch должно содержать длину этого буфера. Но для того чтобы поля dwTypeData и cch трактовались функцией именно как указатель на буфер и его длину, поля fMask и fType должны быть правильно заполнены (см. программу). Наконец, поле cbSize должно содержать длину всей структуры.
9. После получения нужной информации, т.е. строки-названия пункта меню, при помощи функции SendMessage мы посылаем сообщение WM_SETTEXT, которое дает команду установить заголовок окна.

Содержание раздела