C++ Builder
Russian LinkExchange Banner Network
Реклама - двигатель сами понимаете чего...
Delphi  |  JBuilder
::Главная ->Литература ->Руководство по программированию в Windows

Содержание
::Новости
::F.A.Q.
::Форум
::Компоненты
::Исходники
::Литература
::Рассылка
::Ссылки

Клуб
::Клуб программистов
::Члены клуба
::off-форум
::off-чат

Работа
::Есть программисты
::Есть вакансии
::Программы на заказ
::Готовые программы

Другое
::О сайте
::Голосование
::Модератору

	
	                                   Оглавление                                  
      Windows 3.0/pg/1#3                                         = 1 =

      Глава 1. Обзор среды Windows...................................6
      1.1 Сравнение Windows и DOS....................................6
      1.1.1 Интерфейс пользователя...................................7
      1.1.2 Ввод из очереди..........................................7
      1.1.3 Независимая от устройства графика........................8
      1.1.4 Многозадачность..........................................9
      1.2 Программная модель Windows.................................9
      1.2.1 Окна....................................................10
      1.2.2 Меню....................................................10
      1.2.3 Панели диалога..........................................11
      1.2.4 Цикл обработки сообщений................................11
      1.3 Библиотеки Windows........................................12
      1.4 Разработка прикладной программы для Windows...............12
      1.5 Инструментальные  средства   разработки   прикладных......13
      1.5.1 Компилятор С............................................13
      1.5.2 Компоновщик.............................................13
      1.5.3 Редакторы ресурсов......................................14
      1.5.4 Компилятор ресурсов.....................................15
      1.5.5 Средства отладки и оптимизации..........................15
      1.5.6 Сопровождение программ..................................16
      1.6 Рекомендации для разработки прикладных программ...........17
      1.7 Заключение................................................18
      ГЛАВА 2. Прикладная программа Generic.........................20
      2.1 Прикладная программа Generic..............................20
      2.2 Прикладная программа в среде Windows......................20
      2.3 Функция WinMain...........................................21
      2.3.1 Типы данных и структуры Windows.........................22
      2.3.2 Дескрипторы.............................................23
      2.3.3 Управление экземплярами.................................23
      2.3.4 Регистрация класса окна.................................24
      2.3.5 Создание окна...........................................28
      2.3.6 Отображение и корректировка окна........................30
      2.3.7 Создание цикла обработки сообщений......................30
      2.3.8 Передача управления.....................................32
      2.3.9 Завершение прикладной программы.........................32
      2.3.10 Функции инициализации..................................33
      2.3.11 Командная строка прикладной программы..................35
      2.4 Функция окна..............................................35
      2.5 Создание панели диалога About.............................37
      2.5.1 Создание шаблона панели диалога.........................38
      2.5.2. Создание включаемого файла.............................39
      2.5.3 Создание функции диалога................................40
      2.5.4 Определение меню с элементом About......................41
      2.5.5 Обработка сообщения WM_COMMAND..........................42
      2.6 Создание файла определения модуля.........................43
      2.7 Объединение компонент Generic.............................46
      2.7.1 Создание исходного файла на языке С.....................47
      2.7.2 Создание включаемого файла..............................53
      2.7.3 Создание файла описания ресурсов........................53
      2.7.4 Создание файла определения модуля.......................53
      2.7.5 Создание файла make.....................................54
      2.7.6 Запуск программы MAKE...................................56
      2.8 Использование Generic как шаблона.........................56
.
      Windows 3.0/pg/1#3                                         = 2 =

      2.9 Заключение................................................57
      ЧАСТЬ 2.  ПРОГРАММИРОВАНИЕ ПРИКЛАДНЫХ ПРОГРАММ WINDOWS........59
      Глава 3. Вывод в окно.........................................60
      3.1 Контекст отображения......................................60
      3.1.1 Использование функции GetDC.............................61
      3.1.2 Сообщение WM_PAINT......................................61
      3.1.3 Перерисовка области пользователя........................62
      3.1.4 Контекст отображения и контекст устройства..............63
      3.1.5 Система координат.......................................63
      3.2 Создание, выборка и удаление средств рисования............64
      3.3 Рисование и вывод текста..................................65
      3.4 Пример прикладной программы Output........................67
      3.4.1 Добавление новых переменных.............................68
      3.4.2 Модификация фрагмента WM_CREATE.........................68
      3.4.3 Добавление фрагмента WM_PAINT...........................69
      3.4.4 Модификация фрагмента WM_DESTROY........................72
      3.4.5 Трансляция и компоновка.................................73
      3.5 Заключение................................................73
      Глава 4. Ввод с использованием мыши и клавиатуры..............75
      4.1 Типы вводимой информации..................................75
      4.1.1 Форматы сообщений.......................................76
      4.1.2 Ввод с клавиатуры.......................................76
      4.1.3 Ввод символа............................................77
      4.1.4 Ввод с помощью мыши.....................................77
      4.1.5 Ввод от таймера.........................................78
      4.1.6 Ввод из строки прокрутки................................79
      4.1.7 Ввод из меню............................................80
      4.2 Пример прикладной программы Input.........................81
      4.2.1 Как программа Input осуществляет вывод..................82
      4.2.2 Добавление новых переменных.............................82
      4.2.3 Установка типа класса окна..............................83
      4.2.4 Модификация функции CreateWindow........................83
      4.2.5 Определение прямоугольников для текста..................84
      4.2.6  Добавление элемента WM_CREATE..........................84
      4.2.7 Модификация фрагмента WM_DESTROY........................85
      4.2.8 Добавление фрагментов WM_KEYUP и WM_KEYDOWN.............85
      4.2.9 Добавление фрагмента WM_CHAR............................85
      4.2.10 Добавление фрагмента WM_MOUSEMOVE......................85
      4.2.11 Добавление фрагментов WM_LBUTTONUP и       WM_LBUTTONDOWN....86
      4.2.12 Добавление фрагмента WM_LBUTTONDBLCLK..................86
      4.2.13 Добавление фрагмента WM_TIMER..........................86
      4.2.14 Добавление фрагментов WM_HSCROLL и WM_VSCROLL..........86
      4.2.15 Добавление фрагмента WM_PAINT..........................87
      4.2.16 Трансляция и компоновка................................87
      4.3 Заключение................................................88
      Глава 5. Иконы................................................89
      5.1  Что такое икона..........................................89
      5.1.1  Использование встроенных икон..........................90
      5.2. Использование собственных икон...........................90
      5.2.1  Создание файла иконы...................................90
      5.2.2  Определение ресурса иконы..............................91
      5.2.3  Загрузка ресурса иконы.................................91
.
      Windows 3.0/pg/1#3                                         = 3 =

      5.3 Иконы классов.............................................91
      5.4  Отображение собственных икон.............................92
      5.5 Использование икон в панели диалога.......................93
      5.6 Пример прикладной программы Icon..........................94
      5.6.1 Включение оператора ICON................................95
      5.6.2 Включение управляющего оператора ICON...................95
      5.6.3 Установка иконы класса..................................95
      5.6.4 Добавление MYICON.ICO в MAKE-файл.......................95
      5.6.5  Трансляция и компоновка................................95
      5.7  Заключение...............................................96
      Глава 6. Курсор, мышь и клавиатура............................97
      6.1. Управление формой курсора................................97
      6.1.1. Использование встроенных курсоров......................97
      6.1.2  Использование собственных курсоров.....................98
      6.2  Отображение курсора......................................99
      6.2.1 Курсор класса...........................................99
      6.2.2 Индицирование собственного курсора......................99
      6.2.3 Пример: Использование песочных часов при длительных....100
      6.3  Выбор пользователем инофрмации с помощью мыши...........101
      6.3.1  Начало выборки графики................................102
      6.3.2  Индицирование выборки.................................104
      6.3.3  Окончание выборки.....................................106
      6.4  Использование курсора с клавиатурой.....................107
      6.4.1  Использование клавиатуры для перемещения курсора......107
      6.4.2 Использование курсора при отсутствии мыши..............109
      6.5  Пример прикладной программы: Cursor.....................110
      6.5.1  Добавление оператора CURSOR...........................111
      6.5.2. Добавление новых переменных...........................112
      6.5.3  Установка курсора класса..............................112
      6.5.4  Подготовка курсора в виде песочных часов..............113
      6.5.5  Добавление длительной операции........................113
      6.5.6 Добавление фрагментов WM_LBUTTONDOWN, WM_MOUSEMOVE и...114
      6.5.7  Добавление фрагмента WM_KEYDOWN и WM_KEYUP............116
      6.5.8  Добавьте файл BULLSEYE.CUR к MAKE-файлу...............118
      6.5.9  Трансляция и компоновка...............................118
      6.6  Заключение..............................................118
      Глава 7.  Меню...............................................120
      7.1  Что такое меню..........................................120
      7.2  Определение меню........................................121
      7.2.1  Идентификаторы меню...................................122
      7.3  Подключение меню к прикладной программе.................123
      7.3.1 Определение меню в качестве меню класса................123
      7.3.2  Установка меню окна...................................123
      7.4  Обработка ввода от меню.................................124
      7.5  Работа с меню из прикладной программы...................125
      7.5.1  Доступные и недоступные элементы меню.................126
      7.5.2  Контроль элементов меню...............................127
      7.5.3  Добавление элементов к меню...........................128
      7.5.4  Модификация существующего меню........................129
      7.5.5  Удаление элемента меню................................130
      7.5.6 Использование в качестве элементов меню растровых   карт.131
      7.5.7  Замена меню...........................................132
.
      Windows 3.0/pg/1#3                                         = 4 =

      7.5.8  Создание нового  меню.................................132
      7.5.9  Инициализация меню....................................133
      7.6  Специальные возможности меню............................134
      7.6.1  Клавиши - ускорители..................................134
      7.6.2  Использование каскадных меню..........................138
      7.6.3  Использование плавающих накладываемых меню............139
      7.6.4  Создание собственных контрольных отметок..............141
      7.6.5  Использование меню, рисуемых владельцем...............143
      7.7  Пример прикладной программы: EditMenu...................145
      7.7.1  Добавление новых меню к файлу описания ресуросов......145
      7.7.2  Добавление определений во включаемый файл.............146
      7.7.3 Добавление   к   файлу   описания  ресурсов  таблицы...147
      7.7.4  Добавление новых переменных...........................147
      7.7.5  Загрузка таблицы ускорителей..........................148
      7.7.6  Модификация цикла обработки сообщений.................148
      7.7.7  Модификация фрагмента WM_COMMAND......................148
      7.7.8  Компиляция и компоновка...............................149
      7.8  Заключение..............................................149
.
      Windows 3.0/pg/1#3                                         = 5 =

      ----------------------------------------------------------------

                        ПРОГРАММА-СПРАВОЧНИК ПО

                           Microsoft Windows

                                                                                                                                                                                                Версия 3.0

          Руководство по програмированию в среде Microsoft Windows

                                  1#3



                              Москва 1991 г.
      ----------------------------------------------------------------
.
      Windows 3.0/pg/1#3                                         = 6 =

                                                                               
                      Глава 1. Обзор среды Windows.
      ----------------------------------------------------------------
            Microsoft Windows 3.0 предоставляет  много  дополнительных
       возможностей, которых  нет  в стандартной DOS.  По этой причине
       прикладные программы в среде Windows выглядят  более  сложными,
       чем стандартные DOS-программы.

            В данной главе описаны следующие разделы:

            - Сравнение прикладных программ Windows и прикладных прог-
              рамм DOS.

            - Возможности, предоставляемые средой Windows, и включение
              этих   возможностей   при  разработке  ваших  прикладных
              программ.

            - Программная модель Windows.

            - Процесс разработки прикладных программ Windows.

                                    1.1 Сравнение Windows и DOS.               

            Microsoft Windows  3.0  предоставляет много дополнительных
       возможностей, которых нет в стандартной DOS.  По  этой  причине
       прикладные  программы  в среде Windows выглядят более сложными,
       чем стандартные   DOS-программы.   Вы   поймете    это    после
       рассмотрения дополнительных возможностей, которые предоставляет
       Windows. Эти возможности включают:

            - графический   интерфейс,   обеспечивающий    возможность
       использования  в  прикладных  программах  окон,  меню,  панелей
       диалога и блоков управления;

            - ввод с использованием очередей;

            - независимая от устройств графика;

            - многозадачность;

            - обмен данными между прикладными программами.

            Большинство пользователей,  программирующих на  языке  Си,
       используют  стандартную  библиотеку  исполняющей системы Си для
       ввода,  вывода,  управления  памятью  и  других  действий.  Эта
       библиотека   подразумевает   стандартную   операционную  среду,
       включающую  алфавитно-цифровой  терминал  для  ввода/вывода   и
       единоличный доступ    к    системной   памяти   и   устройствам
       ввода/вывода  ПЭВМ.  В  среде  Windows  эти  предположения  уже
       недействительны.   Прикладные  программы,  работающие  в  среде
       Windows, разделяют  системные  ресурсы,  включая  процессор,  с
       другими    прикладными    программами   и   взаимодействуют   с
       пользователем через графический дисплей, клавиатуру и мышь.
.
      Windows 3.0/pg/1#3                                         = 7 =


            В следующих  разделах  описаны  основные   отличия   между
       стандартными   прикладными   программами   DOS   и  прикладными
       программами Windows.
                                    1.1.1 Интерфейс пользователя.              

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

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

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

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

            Одним из  основных  отличий  между Windows и стандартным С
       является метод ввода от пользователя.

            В среде DOS  программа  читает  с  клавиатуры  при  помощи
       явного вызова,  например,  функции getchar.  Эта функция обычно
.
      Windows 3.0/pg/1#3                                         = 8 =

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

            В стандартной   системе   DOS  ввод  с  клавиатуры  обычно
       осуществляется в форме 8 битовых  знаков.  Стандартные  функции
       ввода, getchar и fscanf, читают знаки с клавиатуры и возвращают
       ASCII-коды, соответствующие нажатым клавишам.  Программа  может
       перемешивать  прерывания от устройств ввода (например,  от мыши
       или таймера).

            В среде Windows для каждого созданного окна  автоматически
       предусматривается   ввод   с   клавиатуры   или   мыши.   Среда
       обеспечивает  ввод  в  унифицированном  формате  в   виде   так
       называемых  "сообщений  о  вводе",  содержащих  гораздо большую
       информацию  о  вводе,  чем  DOS.  Эти  сообщения  специфицируют
       системное  время,  положение  мыши,  состояние клавиатуры,  код
       клавиши (если она нажата),  нажатие на  кнопку  мыши,  а  также
       устройство,   генерирующее  сообщение.  Например,  имеются  два
       сообщения клавиатуры:  WM_KEYDOWN  и  WM_KEYUP.  Эти  сообщения
       соответствуют  нажатию  и отпусканию той или иной клавиши.  Для
       каждого   сообщения   система   обеспечивает   независимый   от
       устройства  виртуальный  код,  который  идентифицирует клавишу,
       зависимый от  устройства  скан-код,  генерируемый  клавиатурой,
       состояние таких клавиш,  как Shift, Ctrl или NumLock. Сообщения
       клавиатуры,  мыши и таймера  имеют  один  и  тот  же  формат  и
       обрабатываются одним и тем же способом.
                                                                               
                1.1.3 Независимая от устройства графика.

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

            Windows требует   наличия    драйверов    устройств    для
       преобразования  запросов  на  графический  вывод  в информацию,
       выводимую на принтер,  плоттер,  дисплей или другое  устройство
       вывода.   Драйвер   устройства  -  это  специальная  библиотека
       исполняющей  системы,  которую   прикладная   программа   может
       загрузить  и  присоединить к специальному устройству вывода или
       порту.  "Контекст устройства"  определяет  драйвер  устройства,
       устройство вывода и коммуникационный порт. Прикладная программа
       в  этом  случае  может   выполнить   графические   операции   в
.
      Windows 3.0/pg/1#3                                         = 9 =

       "контексте" данного устройства.
                                         1.1.4 Многозадачность.                

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

            Например, в стандартной DOS программа имеет доступ ко всей
       памяти,  не занятой системой или резидентными программами.  Это
       означает,  что  программы  вольны  использовать  всю  доступную
       память для любых своих нужд и осуществлять доступ к  ней  любым
       способом.

             В Windows  память  -  распределяемый ресурс.  Поскольку в
       один и тот же момент времени могут работать несколько программ,
       необходимо разделять  память,  чтобы  избежать  ее  исчерпания.
       Прикладные программы могут получить ту  часть  памяти  системы,
       которая им   необходима.   В   Windows  имеется  два  источника
       распределения памяти:  глобальная память для выделения  больших
       блоков памяти и локальная память для выделения небольших блоков
       памяти.  Для   наиболее   эффективного   использования   памяти
       программа  управления памятью Windows часто перемещает или даже
       сбрасывает  блоки  памяти.  Это  означает,  что  вы  не  можете
       подразумевать, что  объекты,  которые вы определили,  находятся
       там,  куда вы их поместили.  Если работает несколько прикладных
       программ,  то  перемещение  или сбрасывание блоков памяти может
       происходить достаточно часто.

            Другим примером   разделяемого   ресурса   может   служить
       системный  дисплей.  В стандартном окружении DOS система обычно
       предоставляет  вашей  программе  исключительное   использование
       системного  дисплея.  Это означает,  что вы можете использовать
       дисплей так,  как вам нравится,  изменять цвет символов и фона,
       изменять  режим  отображения  с  текстового  на  графический  и
       наоборот.  В  Windows  ваша  программа   разделяет   доступ   к
       системному дисплею вместе с другими прикладными программами,  и
       поэтому вы не получаете управления дисплеем.
                                                                               
                    1.2 Программная модель Windows.

            Большинство прикладных  программ  Windows  используют  для
       взаимодействия с пользователем следующие элементы:

            - Окна.
.
      Windows 3.0/pg/1#3                                        = 10 =


            - Меню.

            - Панели диалога.

            - Цикл обработки сообщений.

            В последующих  подразделах  эти элементы описываются более
       подробно.
                                                 1.2.1 Окна.                   

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

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

            Windows отслеживает для каждого окна те изменения, которые
       могут  влиять  на  него.  Поэтому,  каждое  окно  должно  иметь
       соответствующую  "функцию  окна".  Функция  окна  получает   от
       программы   управления  окнами  сообщения,  на  которые  должна
       соответствующим образом реагировать. Сообщения управления окном
       или определяют действия,  которые должна выполнить функция, или
       запрашивают от функции информацию.
                                                                               
                               1.2.2 Меню.

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

.
      Windows 3.0/pg/1#3                                        = 11 =

                                                                               
                          1.2.3 Панели диалога.

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

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

            Как показано на рис.  1.2, Windows собирает всю вводимую с
       клавиатуры информацию.  Windows получает ввод от  пользователя,
       когда он нажимает или отпускает клавишу. Затем она копирует эту
       информацию в соответствующую очередь прикладной программы. Цикл
       обработки   сообщений   находит   сообщение,  переводит  его  в
       сообщение типа символа ANSI,  WM_CHAR и  направляет  его  через
       Windows соответствующей функции окна.  Функция окна может затем
       с  помощью  функции  TextOut  вывести  этот  символ  в  области
       пользователя в окне.

            Windows может  получать  и  направлять сообщения ввода для
       нескольких прикладных программ одновременно.  Как  показано  на
       рисунке  1.3,  Windows получает всю вводимую информацию в форме
       сообщений в своей системной  очереди.  Затем  он  копирует  эти
       сообщения в   очередь   прикладной  программы.  Цикл  обработки
       сообщений каждой  прикладной  программы  получает  сообщения  и
       направляет их через Windows соответствующей функции окна.

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

            Когда цикл  обработки сообщений находит сообщение WM_QUIT,
.
      Windows 3.0/pg/1#3                                        = 12 =

       цикл завершается, и делается выход из основной функции.
                                                                               
                         1.3 Библиотеки Windows.

            Функции Windows такие,  например,  как функции исполняющей
       системы   С,  определяются  в  библиотеках.  Другие  библиотеки
       Windows  (не  включающие  эти  функции)  являются  специальными
       библиотеками  динамической  связи,  которые система связывает с
       прикладной программой при ее загрузке.  Библиотеки динамической
       связи являются важнейшими компонентами среды Windows, поскольку
       они минимизируют объем кода прикладных программ.

            Windows содержит три основные библиотеки:

       User     библиотека  пользователя.  Обеспечивает  управление
                всей средой Windows и окнами прикладной программы;

       Kernel   библиотека ядра. Обеспечивает системный сервис, та-
                кой как многозадачность, управление памятью и управле-
                ние ресурсами;

       GDI      библиотека GDI. Обеспечивает  интерфейс  графических
                устройств.
                     1.4 Разработка прикладной программы для Windows.          

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

            - написать функцию WinMain и функции окон и поместить их в
              исходные файлы на языке С или языке ассемблера;

            - с помощью редакторов ресурсов (SDKPaint, Dialog Editor и
              Font Editor) создать курсоры,  иконы,  растровые карты и
              шрифты, которые необходимы в прикладной программе;

            - создать файл описания ресурсов, в котором определить все
              ресурсы прикладной программы.  В файле описания ресурсов
              вы  приводите  имена  и   список   созданных   вами   на
              предшествующих  шагах  ресурсов.  Вы  также  определяете
              меню, панели диалога и другие ресурсы;

            - написать  файл  определения   модуля   (.DEF),   который
              определяет  атрибуты модулей прикладной программы,  типа
              атрибутов сегментов,  размер стека и размер динамической
              области памяти;

            - оттранслировать и скомпоновать все исходные программы на
              языке Си и ассемблера;

            - оттранслировать  с  помощью  компилятора  ресурсов  файл
              описания  ресурса  и  присоединить  его  к  выполняемому
              файлу.
.
      Windows 3.0/pg/1#3                                        = 13 =


            На рис.  1.5 представлены шаги,  необходимые для  создания
       прикладной программы в среде Windows.
                                                                               
            1.5 Инструментальные  средства   разработки   прикладных
                                     программ.

            При создании  прикладной программы необходимо использовать
       много новых инструментальных средств,  а  также  уже  известные
       инструментальные  средства  с новыми свойствами.  В последующих
       пунктах все они кратко описываются.
                                                                               
                           1.5.1 Компилятор С.

            Можно транслировать    прикладные    программы    Windows,
       используя в командной строке те  же  самые  параметры,  которые
       применяются для стандартных С-программ.  Однако Windows требует
       использования двух специальных параметров:  -Gw и -Zp. Параметр
       -Gw   добавляет   к   каждой  функции  требуемые  Windows  коды
       инициализации и завершения.  Параметр -Zp упаковывает структуры
       так,  что структуры, используемые в прикладной программе, имеют
       тот же  размер,  что  и  структуры  Windows.  Типичная  команда
       компилятора cl выглядит так:

            cl -c -AS -Gw -Os -Zdp test.c

            Параметр -c   заставляет   компилятор  производить  только
       компиляцию, но не компоновку. Этот параметр необходим в случае,
       если вы компилируете файлы с исходным кодом отдельно.
                                            1.5.2 Компоновщик.                 

            Компоновщик, поставляемый    с   Microsoft   C   Compiler,
       позволяет формировать  выполняемые  файлы  в  формате  Windows.
       Дополнительной  его  чертой  является  необходимость иметь файл
       описания модуля. Этот файл (.DEF):

            - определяет имя прикладной программы;

            - помечает,  что  прикладная программа должна иметь формат
              Windows;

            - определяет  атрибуты  прикладной  программы,  такие  как
              должен ли сегмент быть перемещаемым.

            Ниже приведен пример файла определения модуля:

            NAME Generic         ; имя прикладной программы

            DESCRIPTION 'Sample Microsoft Windows Application'

            EXETYPE WINDOWS      ; обязательно для Windows

.
      Windows 3.0/pg/1#3                                        = 14 =

            STUB 'WINSTUB.EXE'   ; печатает сообщение об ошибке при
                                 ; попытке запустить программу без
                                 ; Windows

            CODE PRELOAD MOVEABLE ; код может быть перемещаем

            ; DATA  должен быть MULTIPLE, если может работать несколько
            ; экземпляров программы одновременно

            DATA MOVEABLE MULTIPLE

            HEAPSIZE 1024
            STACKSIZE 5120 ; рекомендуемый минимум для Windows

            ; все   функции,  которые  вызывает  Windows, должны  быть
            ; экспортируемыми

            EXPORTS
                 MainWndProc  @1  ; имя функции обработки сообщений
                 AboutDlgFunc @2  ; имя функции обработки панели диа-
                                  ; лога About

            Для того,  чтобы скомпоновать прикладную программу в среде
       Windows,    необходимо    указать   имена   объектных   файлов,
       сформированных  компилятором,  имя   импортируемой   библиотеки
       Windows,  имя  файла  определения  модуля  и другие параметры и
       файлы. Ниже приводится пример типичной команды link:

            link /NOD Generic,,, slibw libw, Generic.def

            Более подробная информация по  link  и  файлу  определения
       модуля приводится в "Tools".
                                                                               
                         1.5.3 Редакторы ресурсов.

            Редакторы ресурсов используются для создания ресурсов типа
       курсоров,  икон или  растровых  карт.  После  этого  вы  можете
       заносить  эти  ресурсы в файл описания ресурсов.  Эти программы
       входят в комплект инструментальных  средств  Windows  SDK.  Это
       редакторы:

            - SDKPaint (SDKPAINT) -  для  создания  икон,  курсоров  и
              растровых карт;

            - Dialog  Editor  (DIALOG) - для создания описаний панелей
              диалога;

            - Font Editor (FONTEDIT) - редактор шрифтов  для  создания
              шрифтов.

            Поскольку данные    редакторы     являются     прикладными
       программами Windows,  то вы должны запускать их только из среды
       Windows. Подробная информация о редакторах ресурсов приведена в
.
      Windows 3.0/pg/1#3                                        = 15 =

       "Tools".
                                      1.5.4 Компилятор ресурсов.               

            Большинство прикладных программ в среде Windows использует
       ряд ресурсов,  таких,  например,  как иконы,  курсоры,  меню  и
       панели  диалога.  Эти  ресурсы необходимо описать в специальном
       файле,  называемом "файл описания ресурсов".  Этот  файл  имеет
       расширение  .RC.  Затем  оттранслировать  этот  файл  с помощью
       компилятора ресурсов (RC) и  подсоединить  его  к  выполняемому
       файлу  прикладной  программы.  Во  время  выполнения прикладной
       программы  она  может  загружать  и  использовать  ресурсы   из
       выполняемого файла.

            Ниже приводится    пример    файла    описания   ресурсов,
       идентифицирующего два ресурса - курсор и икону:

            bullseye CURSOR bullseye.cur
            Generic ICON Generic.ico

            Первый оператор   определяет   ресурс   курсора  с  именем
       Bullseye,  объявляя его курсором (CURSOR), и определяет файл, в
       котором  хранится  сам  ресурс (Bullseye.cur).  Второй оператор
       делает то же для иконы.

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

            rc example.rc

            Компилятор ресурсов полностью описан в "Tools".  Операторы
       файла  определения  ресурсов описаны во втором томе справочного
       руководства.
                              1.5.5 Средства отладки и оптимизации.            

            SDK Windows включают в  себя  несколько  средств,  которые
       помогут вам отлаживать прикладные программы и оптимизировать их
       работу:

            - CodeView для  Windows  (CVW)  позволяет  вам  отлаживать
              прикладные   программы  Windows  при  работе  Windows  в
              стандартном режиме и  в  расширенном  режиме  процессора
              386.   CVW   позволяет   устанавливать  точки  останова,
              просматривать текст программ на уровне исходного  текста
              и  выводить  символьную  информацию  во время выполнения
              прикладной программы.

            - Символьный  отладчик   (symdeb)   позволяет   отлаживать
              прикладные программы при работе в реальном режиме.

            - Шпион (SPY) позволяет вам отслеживать сообщения, которые
.
      Windows 3.0/pg/1#3                                        = 16 =

              Windows  посылает  вашей  прикладной   программе.   Этим
              средством удобно пользоваться при отладке.

            - Профилер    (PROFILER)    позволяет    вам    определить
              относительное время,   в   течение   которого   работают
              различные сегменты кода вашей программы. Это поможет вам
              улучшить характеристики вашей программы.

            - Анализатор  подкачки  (SWAP)  позволяет  вам  определить
              поведение вашей   программы   при   выполнении  подкачки
              памяти.

            - Heap  Walker   (HEAPWALK)   позволяет   вам   определить
              содержимое локальной  и  глобальной динамической области
              памяти.

            Подробно данные средства описаны в "Tools".
                                    1.5.6 Сопровождение программ.              

            Программа make  -  это  средство  сопровождения  программ,
       которое корректирует программы, сохраняя даты создания исходных
       файлов.  MAKE включена в стандартную  поставку  с  Microsoft  С
       версии 5.1  (NMAKE - это та же программа,  только с Microsoft С
       версии 6.0).  Обе программы работают с Windows. Какую вы будете
       использовать, зависит от имеющейся у вас версии С.

            Хотя MAKE  и  NMAKE поставляются с компилятором С,  а не с
       SDK,  она особенно  важна  из-за  большого  количества  файлов,
       требуемых для создания прикладных программ в Windows. Программа
       make работает с файлом make, который содержит перечень команд и
       файлов,  необходимых для создания прикладных программ.  Команды
       транслируют и компонуют различные  файлы.  Make  выполняет  эти
       команды только в том случае,  когда изменились файлы, указанные
       в  этих  командах.  Это  экономит  время   при   незначительных
       изменениях в программе.  Ниже приводится пример типичного файла
       make:

            #эта строка позволяет также использовать NMAKE
            all:Generic.exe

            #модифицировать ресурсы при необходимости
            Generic.res: Generic.rc Generic.h
                rc -r Generic.rc

            #модифицировать при необходимости объектные файлы
            Generic.obj: Generic.c Generic.h
                cl -c -AS -DLINT_ARGS -Gsw -Oat -W2 -Zped Generic.c

            #модифицировать при необходимости  .exe  файл  и  добавить
            #ресурсы.

            Generic.exe: Generic.obj Generic.def
.
      Windows 3.0/pg/1#3                                        = 17 =

                link /NOD Generic,,, SLIBEW LIBW, Generic.def
                MAPSYM Generic
                RC Generic.res

            #если обновлен  .res  файл,  а  выполняемый  файл  остался
            #прежним.

            Generic.exe: Generic.res
                RC Generic.res

            Обычно файлы make имеют то же самое имя, что и создаваемые
       прикладные программы, хотя допускаются и другие имена. Типичная
       команда make создает файл Generic:

            make Generic

            Подробное описание    программы    MAKE   вы   найдете   в
       документации по Microsoft C Optimizing Compiler.
                   1.6 Рекомендации для разработки прикладных программ.        

            Существует много   приемов    программирования,    которые
       работают в стандартном С или ассемблере, но не работают в среде
       Windows. В главе 14 "Язык С и ассемблер"  содержатся  детальная
       информация  по использованию этих языков для написания программ
       под Windows.

            При разработке  программ  необходимо   помнить   следующие
       основные правила:

              - не  стремитесь к единоличному использованию процессора
                - это разделяемый ресурс. Хотя Windows и многозадачная
                система, она  не  может  взять управление у прикладной
                программы до тех пор,  пока прикладная программа  сама
                не  вернет его.  Корректные программы позволяют другим
                программам получить доступ к процессору.

              - не пытайтесь получить непосредственный доступ к памяти
                или аппаратуре,  такой как клавиатура,  мышь,  таймер,
                дисплей,  последовательный  или   параллельный   порт.
                Windows требует абсолютного управления этими ресурсами
                для того, чтобы иметь одинаковый непрерывный доступ ко
                всем работающим прикладным программам.

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

                int PASCAL WinMain(hInst,hPrevInst,lpCmdLine,nCmdShow)
                HANDLE hInst;
.
      Windows 3.0/pg/1#3                                        = 18 =

                HANDLE hPrevInst;
                LPSTR  lpCmdShow;
                int    nCmdShow;
                {
                          .
                          .
                          .
                }

                Функция WinMain   должна  быть  объявлена  с  ключевым
                словом  PASCAL.  Хотя  Windows  вызывает  эту  функцию
                напрямую,  WinMain  не  должна  объявляться  как  FAR,
                поскольку она вызывается из подсоединенного  в  период
                компоновки стартового кода.

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

              - не используйте такие динамические функции ввода/вывода
                исполняющей системы  С как getchar,  putchar,  scanf и
                printf.

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

              - можно использовать  функции  ввода/вывода  исполняющей
                системы С для доступа к дисковым файлам.  В частности,
                используйте функцию OpenFile среды Windows  и  функции
                низкого  уровня  исполняющей  системы  С  для  ввода и
                вывода.  Хотя функции ввода/вывода исполняющей системы
                С   и   могут   быть  использованы,  вы  не  получаете
                преимуществ, которые предоставляет функция OpenFile.

              - можно использовать функции исполняющей системы  С  для
                управления памятью malloc,  calloc, realloc и free, но
                нужно быть  уверенным,  что  Windows  преобразует  эти
                функции   в   свои   собственные   функции   локальной
                динамической области памяти LocalAlloc, LocalReAlloc и
                LocalFree.  Поскольку  функции  локальной динамической
                области памяти  не  всегда  работают  точно  так,  как
                функции  исполняющей системы С для управления памятью,
                то можно получить непредсказуемый результат.
                                                 1.7 Заключение.               

            В данной  главе   приводится   обзор   среды   Windows   и
       производится  сравнение  со  стандартным окружением С-программ.
       Дополнительную информацию по различным разделам,  относящимся к
.
      Windows 3.0/pg/1#3                                        = 19 =

       Windows, в можете получить:

       Раздел               Руководство
       ---------------------------------------------------------------
       Цикл обработки       Руководство программиста, глава 2 "Приклад-
       сообщений            ная программа Generic"

       Простая программа    Руководство программиста, глава 2 "Приклад-
       Windows              ная программа Generic"

       Меню                 Руководство программиста, глава 7 "Меню"

       Панель диалога       Руководство программиста, глава 9 "Панели
                            диалога"

       Использование стан-  Руководство программиста, глава 14 "Язык С
       дартных функций С и  и язык ассемблера"
       языка ассемблера

       Функции и сообщения  Справочное руководство, том 1.
       Windows

       Средства разработки  "Tools"


.
      Windows 3.0/pg/1#3                                        = 20 =

                             ГЛАВА 2. Прикладная программа Generic.            
      ----------------------------------------------------------------
            В данной главе поясняется,  как создать простую прикладную
       программу,  названную   Generic.   Эта   прикладная   программа
       демонстрирует    принципы    создания    прикладных   программ,
       приведенные в главе 1, "Обзор среды Windows".

            В этой главе описаны следующие темы:

            - важные части прикладных программ Windows;

            - инициализация прикладных программ Windows;

            - цикл обработки сообщений;

            - завершение прикладной программы;

            - основные  шаги,  необходимые  при  создании   прикладной
              программы.

            Generic также   будет  использоваться  как  основа  других
       рассматриваемых прикладных программ в части 2. (Исходные тексты
       программы  Generic  и  других  примеров  программ  поставляются
       вместе с SDK на диске "Sample Source Code".)
                                                                               
                     2.1 Прикладная программа Generic.

            Generic - это стандартная  прикладная  программа  в  среде
       Windows,  т.е.  она отвечает рекомендациям по пользовательскому
       интерфейсу,  данным в System Application  Architecture,  Common
       User  Access:  Advansed  Interface Design Guide.  Generic имеет
       основное окно,  окантовку,  меню прикладной программы и  панели
       для  увеличения  и уменьшения размера окна.  Меню Help включает
       команду About,  которая  при  выборе  пользователем  индицирует
       панель диалога About,  описывающую Generic. Полностью Generic с
       панелью диалога About выглядит так, как показано на рис. 2.1.

            Рисунок 2.1.  Generic:  шаблон  для  создания  прикладных
                          программ для Windows.

            1. Меню Help.
            2. Панель диалога About.

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

            Прикладная программа   Windows   -  это  любая  программа,
       которая специально написана для  работы  в  операционной  среде
       Windows  и  использующая  интерфейс прикладной программы (API).
.
      Windows 3.0/pg/1#3                                        = 21 =

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

            - основную функцию WinMain;

            - функцию окна.

            Функция WinMain - это точка входа в программу; эта функция
       аналогична основной функции,  используемой в стандартной  среде
       С. Эта функция всегда называется WinMain.

            Функция окна  -  это  для  вас  новое.  Функция окна - это
       функция многократного вызова,  т.е.  функция  вашей  программы,
       которую  вызывает  Windows.  Ваша программа никогда не вызывает
       эту функцию напрямую.  Вместо этого она  ожидает,  пока  ее  не
       вызовет Windows   для   выполнения   каких-либо   действий  или
       получения информации.
                                           2.3 Функция WinMain.                

            Без нее прикладная программа работать  не  может.  Подобно
       основной функции  в  стандартной  системе  С  WinMain  является
       точкой  входа  в  прикладную   программу.   Каждая   прикладная
       программа  должна иметь функцию WinMain.  В большинстве случаев
       эта функция делает следующее:

            - вызывает  функции  инициализации,  которые  регистрируют
              классы   окон,   создают   окна   и   выполняют   другие
              инициализации;

            - запускает цикл обработки сообщений из очереди прикладной
              программы;

            - завершает программу при получении сообщения WM_QUIT.

            Функция WinMain имеет следующий вид:

            int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine,
                               nCmdShow)
            HANDLE hInstance;     /* текущий экземпляр */
            HANDLE hPrevInstance; /* предыдущий экземпляр */
            LPSTR lpCmdLine;      /* командная строка */
            int nCmdShow;         /* тип представления окна (откры-
                                     тое или в виде иконы) */
            {

            }

            Функция WinMain  использует  соглашения  по  вызову  языка
       Паскаль.

            При запуске  программы  Windows  передает  функции WinMain
       четыре параметра:
.
      Windows 3.0/pg/1#3                                        = 22 =


       Параметр      Значение, передаваемое программе
       ---------------------------------------------------------------
       hInstance     Дескриптор экземпляра программы.

       hPrevInstance Дескриптор предыдущего экземпляра программы, если
                     она уже была запущена. Если это первый экземпляр,
                     то Windows передает NULL.

       lpCmdLine     Длинный указатель на  оканчивающуюся  нулем
                     командную строку.

       nCmdShow      Целое, передаваемое функции определяет  в каком
                     виде окно должно быть индицировано:  как открытое
                     окно   или  как  икона.  Это  значение  программа
                     передает  функции  ShowWindow,  когда   возникает
                     необходимость в отображении окна.

            Более подробная   информация   находится  в  пункте  2.3.2
       "Дескрипторы".  Дополнительную информацию о параметре lpCmdLine
       вы   найдете  в  разделе  2.3.11  "Параметры  командной  строки
       программы".
                             2.3.1 Типы данных и структуры Windows.            

            Функция WinMain использует несколько  нестандартных  типов
       данных для определения своих параметров.  Например,  тип данных
       HANDLE используется  для  определения  параметров  hInstance  и
       hPrevInstance,  а тип данных LPSTR используется для определения
       параметра  lpCmdLine.   Вообще   говоря,   Windows   использует
       значительно  больше  типов  данных,  чем  встречаются в обычных
       С-программах.  Хотя  типы  данных  Windows  часто  эквивалентны
       обычным  типам данных языка С,  они более мнемоничны и помогают
       лучше понять назначение данной переменной или параметра.

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

            #include "windows.h"    /* необходима для всех программ */

            Ниже приводится перечень нескольких наиболее  используемых
       типов данных среды Windows:

       Тип              Значение
       ---------------------------------------------------------------
       WORD             Определяет 16-битовое беззнаковое целое;

       LONG             Определяет 32-битовое целое со знаком;
.
      Windows 3.0/pg/1#3                                        = 23 =


       HANDLE           Идентифицирует 16-битовое беззнаковое  целое,
                        используемое как дескриптор;

       HWND             Идентифицирует 16-битовое беззнаковое  целое,
                        используемое как дескриптор окна;

       LPSTR            Определяет  32-битовый указатель на перемен-
                        ную типа char;

       FARPROC          Определяет 32-битовый указатель на функцию.
       ---------------------------------------------------------------

            Ниже приводится    перечень   некоторых   наиболее   часто
       используемых структур:

       Структура        Описание
       ---------------------------------------------------------------
       MSG              Определяет поля полученного сообщения;

       WNDCLASS         Определяет класс окна;

       PAINTSTRUCT      Определяет структуру изображения, используемую
                        для рисования в окне;

       RECT             Определяет прямоугольник.
       ---------------------------------------------------------------

            Полный список и описание  всех  структур  и  типов  данных
       Windows приведен во втором томе "Справочного руководства".
                                                                               
                            2.3.2 Дескрипторы.

            Функция WinMain   имеет  два  параметра:  hPrevInstance  и
       hInstance,  которые называются дескрипторами.  Дескриптор - это
       уникальное целое,  которое Windows использует для идентификации
       объекта,  создаваемого или используемого прикладной программой.
       Windows использует большое число дескрипторов, идентифицирующих
       такие объекты как экземпляры прикладной программы,  окна, меню,
       блоки  управления,  распределяемую  память,  устройства вывода,
       файлы, перья и кисти GDI и многие другие.

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

.
      Windows 3.0/pg/1#3                                        = 24 =

                                   2.3.3 Управление экземплярами.              

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

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

            Для большинства  программ  первый  экземпляр  имеет особую
       роль. Поскольку программа создает много таких ресурсов, которые
       доступны  для  всех  программ (например,  классы окна),  только
       первый экземпляр программы создает эти ресурсы.  Все последущие
       экземпляры  используют эти ресурсы,  не создавая их.  Для того,
       чтобы определить какой из экземпляров является первым,  Windows
       устанавливает, параметр  hPrevInstance  функции WinMain в NULL,
       если  нет  предыдущих  экземпляров.  Ниже  дается  пример,  как
       проверить, имеется ли предыдущий экземпляр:

            int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine,
                               nCmdShow)
            HANDLE hInstance;
            HANDLE hPrevInstance;
            LPSTR lpCmdLine;
            int nCmdShow;
            {
                if (!hPrevInstance)
                 .
                 .
                 .
            }

            Можно помешать   пользователю   запустить   более   одного
       экземпляра  программы,  проверив параметр hPrevInstance,  когда
       программа запускается и сразу  возвращает  управление  Windows,
       если  значение  этого  параметра  -  не NULL.  Приведенный ниже
       пример показывает, как это сделать:

            if (hPrevInstance)
               return (NULL);

.
      Windows 3.0/pg/1#3                                        = 25 =

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

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

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

                       Заполнение структуры WNDCLASS.

            Структура WNDCLASS  передает  Windows информацию об имени,
       атрибутах,  ресурсах и функции окна данного  класса.  Структура
       WNDCLASS содержит следующий поля.

            Поле           Описание
            ----------------------------------------------------------
            lpszClassName  Указывает на имя класса окна. Имя класса
                           окна должно быть уникальным; т.е. различные
                           программы   должны  иметь  различные  имена
                           классов.

            hInstance      Определяет экземпляр программы, который
                           регистрирует класс.

            lpfnWndProc    Указывает на функцию окна, используемую
                           для обработки окна.

            style          Определяет  тип класса, такой как авто-
                           матическая перерисовка окна при перемещении
                           или изменении размеров.

            hbrBackgroung  Определяет  кисть, используемую для ри-
                           сования фона окна.

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

            hIcon          Определяет икону, используемую для пре-
                           дставления окна.

            lpszMenuName   Указывает на имя ресурса меню.

            cbClsExtra     Определяет число дополнительных байт,
                           отведенных под эту структуру.

            clWndExtra     Определяет число дополнительных байт,
                           отведенных под все структуры, созданные для
                           данного класса.
            ----------------------------------------------------------
.
      Windows 3.0/pg/1#3                                        = 26 =


            Дополнительную информацию об  этих  полях  вы  найдете  во
       втором томе "Справочного руководства".

            Некоторым полям,   таким   как   lpszClass,   hInstance  и
       lpfnWndProc, обязательно должны быть присвоены значения. Другие
       могут  быть  установлены  в NULL для использования атрибутов по
       умолчанию для окон, принадлежащих этому классу. Ниже приводится
       пример, как зарегистрировать класс окна:

       BOOL InitApplication(hInstance)
       HANDLE hInstance;
       {
       1)      WNDCLASS WC;

               /* заполнение  структуры   класса   окна,   параметрами
                  описывающими основное окно */

       2)      WC.style = NULL;          /* тип окна */
       3)      WC.lpfnWndProc = MainWndProc; /* функция окна */

       4)      WC.cbClsExtra = NULL;     /* нет дополнительных данных */
               WC.clWhdExtra = NULL;

       5)      WC.hInstance = hInstance; /* экземпляр, владелец класса */
       6)      WC.hIcon = LoadIcon(NULL, IDI_APPLICATION);
       7)      WC.hCursor = LoadCursor(NULL, IDC_ARROW);
       8)      WC.hbrBackground = GetStockObject(WHITE_BRUSH);
       9)      WC.lpszMenuName = "Generic"; /* имя меню в .RC-файле */
       10)     WC.lpszClassName = "GenericWndClass"; /* имя класса */

               /* регистрация класса */

               return(RegisterClass(&WC));
       }

       1)   В данном примере в начале объявляется структура
            WNDCLASS c именем WC.

       2)   Поле style устанавливается в NULL.

       3)   Поле lpfnWndProc содержит указатель на функцию окна с
            именем MainWndProc.  Это означает, что функция MainWndProc
            будет получать сообщения,  которые Windows будет  посылать
            окну, и эта функция будет обрабатывать эти сообщения.

            Для того,  чтобы  присвоить  адрес  функции GenericWndProc
            полю lpfnWndProc, необходимо объявить эту функцию где-либо
            перед   оператором   присваивания.   Большинство  программ
            используют прототипы фукций для их  объявления  для  того,
            чтобы использовать преимущества автоматического контроля и
.
      Windows 3.0/pg/1#3                                        = 27 =

            приведения типов при трансляции.  Ниже  приводится  пример
            правильного прототипа функции GenericWndProc:

            long FAR PASCAL MainWndProc(HWND, unsigned, WORD, LONG);

            Отметим, что   MainWndProc   должна   быть   описана   как
            экспортируемая в файле определения модуля.

       4)   Поля cbClsExtra и cbWndExtra установлены в NULL, поскольку
            не требуется  дополнительная  память  для каждого класса и
            для каждого  окна.  (Вы  можете  занести  сюда   ненулевое
            значение, и  затем  использовать эту дополнительную память
            для каждого окна.  Смотрите главу 16  "Еще  об  управлении
            памятью",    в   которой   описано   использование   этого
            дополнительного пространства.)

       5)   Поле hInstance содержит экземпляр, т.е. дескриптор, посы-
            лаемый Windows прикладной программе при запуске.

       6)   Поле hIcon получает дескриптор  встроенной иконы. Функция
            LoadIcon возвращает   дескриптор   или   встроенной,   или
            определяемой   пользователем   иконы.   В   данном  случае
            аргументы NULL  и  IDI_APPLICATION  определяют  встроенную
            икону.  (В  большинстве  программ используются собственные
            иконы. В  главе  5  "Иконы"  описано,  как   создавать   и
            использовать собственные иконы.)

       7)   Поле hCursor получает дескриптор встроенного  курсора.
            Функция LoadCursor возвращает дескрипторы  встроенных  или
            определенных   прикладной   программой   курсоров.   Здесь
            аргументы NULL и IDC_ARROW определяют встроенный курсор  в
            виде   стрелки.   (Некоторые   программы  используют  свои
            собственные курсоры.  Глава 6 "Курсор,  мышь и клавиатура"
            описывает, как   можно   создать   и   использовать   свой
            собственный курсор.)

       8)   Поле hbrBackground определяет цвет кисти, которую Windows
            будет использовать  при  рисовании  фона  окна.  В  данном
            случае программа  использует  функцию  GetStockObject  для
            получения дескриптора стандартной белой кисти.

       9)   Поле lpszMenuName определяет имя меню для окон данного
            класса, "GenericMenu".  Это  меню   будет   в   дальнейшем
            использоваться во всех окнах данного класса.  Если окно не
            должно иметь меню, данному полю присваивают значение NULL.

       10)  Поле lpszClassName определяет строку "GenericWndClass" как
            имя данного класса окон.

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

            После присваивания   значений   полям  структуры  WNDCLASS
       зарегистрируйте класс,  используя функцию  RegisterClass.  Если
.
      Windows 3.0/pg/1#3                                        = 28 =

       регистрация   прошла   успешно,   функция  возвращает  TRUE.  В
       противном  случае  она  возвращает  FALSE.  Следует   проверить
       возвращаемое значение, поскольку если класс не зарегистрирован,
       окно создавать нельзя.

            Хотя функция RegisterClass требует 32-битовый указатель на
       структуру  WNDCLASS,  в предыдущем примере знак операции взятия
       адреса (&)  генерирует  только  16-битовый  адрес.  Это  пример
       неявного   приведения   типов,   выполняемого   С-компилятором.
       Включаемый файл Windows содержит прототипы  всех  его  функций.
       Эти  прототипы определяют правильные типы для каждого параметра
       функции,  и  С-компилятор  делает  приведение  к   этим   типам
       автоматически.
                                            2.3.5 Создание окна.               

            Можно создать  окно  с  помощью функции CreateWindow.  Эта
       функция побуждает Windows создать окно, которое имеет указанный
       тип и принадлежит к определенному классу.  Функция CreateWindow
       имеет несколько параметров:

            - имя класса окна;

            - заголовок  окна;

            - тип  окна;

            - расположение  окна;

            - дескриптор родительского окна;

            - дескриптор меню;

            - дескриптор экземпляра;

            - 32 бита дополнительных данных.

            В приведенном ниже примере создается  окно,  принадлежащее
       классу "GenericWndClass":

            hWnd = CreateWindow(
       (1)      "GenericWndClass",           /* класс окна       */
       (2)      "Generic Sample Application", /* имя окна        */
       (3)      WS_OVERLAPPEDWINDOW,         /* тип окна         */
       (4)      CW_USEDEFAULT,               /* координата x     */
                CW_USEDEFAULT,               /* координата y     */
                CW_USEDEFAULT,               /* ширина           */
                CW_USEDEFAULT,               /* высота           */
       (5)      NULL,                        /* дескриптор родите-
                                                льского окна     */
       (6)      NULL,                        /* ID меню или дочер-
                                                него окна        */
       (7)      hInstance,                   /* экземпляр        */
.
      Windows 3.0/pg/1#3                                        = 29 =

       (8)      NULL);                       /* добавочная информа-
                                                ция  */

            В данном  примере создается перекрывающееся окно,  имеющее
       тип WS_OVERLAPPEDWINDOW и принадлежащее классу окна, созданному
       в предыдущем примере. В данном случае:

       1)   Первый параметр функции CreateWindow определяет имя
            класса окна,  который  Windows  должна  использовать   при
            создании    окна.    В    этом    примере    имя    класса
            "GenericWndClass".

       2)   Второй параметр определяет заголовок: "Generic Sample
            Application".

       3)   Тип WS_OVERLAPPEDWINDOW определяет окно как обычное пере-
            крываемое окно.

       4)   Следующие четыре параметра определяют положение и размеры
            окна. Поскольку  значение  CW_USEDEFAULT  определяется для
            параметров ширины и высоты  окна  и  его  координат,  окно
            будет  иметь  расположение,  ширину и высоту по умолчанию.
            Координаты окна и его  размеры  по  умолчанию  зависят  от
            системы  и  от того,  какое количество программ работает в
            среде.  (Отметим,  что Windows не индицирует окно  до  тех
            пор, пока не будет вызвана функция ShowWindow.)

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

       6)   Если при создании окна вы укажете меню, то это меню заме-
            нит меню класса (если оно есть). Поскольку это окно должно
            использовать меню класса, то данный параметр равен NULL.

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

       8)   Последний параметр - для  дополнительных  данных,  которые
            будут использоваться  функцией  окна  при  создании  окна.
            Поскольку   окно   не  использует  дополнительных  данных,
            параметр установлен в NULL.

            Когда CreateWindow    функция    создает    окно,    (т.е.
       заканчивается успешно),  она возвращает дескриптор нового окна.
       Этот дескриптор может быть использован для  выпонения  операций
       над   окнами,   таких,   например,  как  их  индицирование  или
       корректировка их области пользователя.

            Если функция  CreateWindow  не  может  создать  окно,  она
.
      Windows 3.0/pg/1#3                                        = 30 =

       возвращает  NULL.  Каждый  раз  при  создании  окна  необходимо
       контролировать дескриптор на NULL и реагировать соответствующим
       образом.  Например,  если  нельзя  создать  основное  окно  ПП,
       находясь в функции  WinMain,  необходимо  завершить  программу,
       т.е. возвратить управление Windows.
                              2.3.6 Отображение и корректировка окна.          

            Хотя функция    CreateWindow    и    создает   окно,   она
       автоматически не индицирует его.  Прикладная  программа  должна
       предусмотреть  индикацию  окна  с  помощью функции ShowWindow и
       корректировку  области  пользователя  окна  с  помощью  функции
       UpdateWindow.

            Функция ShowWindow  побуждает  Windows  индицировать новое
       окно с дескриптором hWnd.  Для основного окна программы функция
       WinMain должна вызвать функцию ShowWindow вскоре после создания
       окна и передать ей параметр nCmdShow. Этот параметр определяет,
       как индицируется окно:  как открытое окно или как икона.  Затем
       функция WinMain должна вызвать UpdateWindow. В приведенном ниже
       примере показано, как отобразить и скорректировать окно:

            ShowWindow (hWnd, nCmdShow); /* отображение окна */
            UpdateWindow (hWnd);         /* посылка сообщения
                                            WM_PRINT         */

            Примечание: Обычно,    параметр    nCmdShow   может   быть
       установлен в любое значение с помощью констант, начинающихся на
       SW_  (определены в WINDOWS.H).  Имеется единственное исключение
       при индицировании основного окна с помощью функции  ShowWindow:
       ей  передается  параметр nCmdShow,  который WinMain получает от
       Windows.  (Полный список этих констант вы найдете в первом томе
       "Справочного руководства").
                           2.3.7 Создание цикла обработки сообщений.           

            Как только  функция  WinMain  создала и индицировала окно,
       она может выполнять свою основную задачу - читать сообщения  из
       очереди  прикладной  программы и направлять их соответствующему
       окну.  Функция WinMain делает это  с  помощью  цикла  обработки
       сообщений.  Цикл  обработки  сообщений  - это программный цикл,
       обычно создаваемый с использованием оператора while, при работе
       в  котором  функция  WinMain  находит сообщения и направляет их
       соответствующим функциям.

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

.
      Windows 3.0/pg/1#3                                        = 31 =

            Наиболее простой  цикл  обработки  сообщений  состоит   из
       функций GetMessage и DispatchMessage. Этот цикл имеет следующий
       вид:

             MSG msg;
                .
                .
                .
            while (GetMessage(&msg, NULL, NULL, NULL)) {
                DispatchMessage(&msg);
            }

            В этом примере функция GetMessage  получает  сообщение  из
       очереди  прикладных  программ  и  копирует его в структуру msg.
       Аргументы  NULL  указывают,  что  должны  быть  обработаны  все
       сообщения.  Функция  DispatchMessage  побуждает Windows послать
       каждое   сообщение   соответствующей   функции   окна.   Каждое
       сообщение,   которое  получает  функция  окна  (за  исключением
       сообщения  WM_QUIT),  принадлежит  одному  из  окон,  созданных
       прикладной  программой.  Поскольку программа не должна вызывать
       непосредственно    функцию     окна,     необходима     функция
       DispatchMessage для передачи сообщений соответствующей функции.

            В зависимости  от назначения программы можно иметь и более
       сложный цикл обработки сообщений.  В частности, если необходимо
       обработать вводимые с клавиатуры символы, нужно преобразовывать
       каждое полученное сообщение с помощью функции TranslateMessage.
       Теперь цикл обработки сообщений будет выглядеть так:

            while (GetMessage(&msg, NULL, NULL, NULL)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }

            Функция TranslateMessage   отыскивает    пары    сообщений
       WM_KEYDOWN  и  WM_KEYUP  и генерирует соответствующее сообщение
       WM_CHAR для того окна,  которое содержит значение этого символа
       в коде ANSI для заданной клавиши.

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

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

            Обработка цикла сообщений продолжается до  тех  пор,  пока
.
      Windows 3.0/pg/1#3                                        = 32 =

       GetMessage не возвратит NULL, что происходит в том случае, если
       найдено  сообщение  WM_QUIT,   сигнализирующее   о   завершении
       программы.   Оно   обычно   посылается  (помещается  в  очередь
       прикладной программы)  функцией   основного   окна   прикладной
       программы.
                                                                               
                        2.3.8 Передача управления.

            Windows не является приоритетной многозадачной средой. Это
       означает,  что она не может  забрать  управление  у  программы.
       Прикладная программа сама должна вернуть управление, прежде чем
       Windows сможет передать управление другой программе.

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

            В общем, следует положиться на функцию GetMessage в смысле
       разделения  управления.  Хотя  имеется  и  явная функция Yield,
       следует избегать ее использования. Поскольку могут существовать
       моменты,  когда  программа  должна держать управление в течение
       длительного времени (например,  во время записи большого буфера
       на дисковый файл), следует попытаться минимизировать эту работу
       и  обеспечить  для   пользователя   визуальный   контроль   над
       длительными операциями.
                             2.3.9 Завершение прикладной программы.            

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

            Однако, как только функция WinMain войдет в цикл обработки
       сообщений,   единственным   способом  завершить  цикл  является
       посылка ею  (с  помощью  функции   PostQuitMessage)   сообщения
       WM_QUIT   в   очередь   прикладной   программы.  Когда  функция
       GetMessage находит сообщение WM_QUIT,  она возвращает NULL, что
       завершает  цикл обработки сообщений.  По соглашению,  сообщение
       WM_QUIT посылает только функция WinMain и только  тогда,  когда
       основное  окно  разрушено  (т.е.  когда  функция  окна получила
       сообщение WM_DESTROY).

            Хотя WinMain  определяет   тип   возвращаемого   значения,
       Windows обычно его не использует. Однако, возвращаемое значение
.
      Windows 3.0/pg/1#3                                        = 33 =

       может быть полезным во время отладки программ.  Вообще  говоря,
       можно использовать те же соглашения о коде возврата,  что и для
       обычных С-программ:  нуль для успешного завершения  выполнения,
       ненулевое   значение  -  для  ошибки.  Функция  PostQuitMessage
       позволяет  функции  окна  указать  возвращаемое  значение.  Это
       значение затем копируется в поле wParam сообщения WM_QUIT.  Для
       возврата  этого  значения  после  завершения  цикла   обработки
       сообщений используйте следующий оператор:

            return (msg.wParam); /* возвращает значение  из функции
                                   PostQuitMessage */

            Хотя стандартные   С-программы    обычно    закрывают    и
       освобождают  ресурсы  непосредственно перед завершением работы,
       программы в среде Windows должны быть готовы к закрытию по мере
       разрушения  каждого  окна.  Если  этого  не  сделать,  то можно
       потерять  некоторые  данные.  Например,   если   сама   Windows
       завершает работу,  она разрушает каждое окно,  но не возвращает
       управление циклу обработки сообщений прикладной программы.  Это
       означает,  что  цикл не получит сообщение WM_QUIT,  и операторы
       после цикла не выполнятся. В действительности, Windows посылает
       каждой  программе  сообщение перед завершением работы,  так что
       прикладная   программа   имеет   возможность   выполнить    все
       необходимые  действия  (в  главе  10  "Ввод  и  вывод  в  файл"
       поясняется работа сообщения WM_QUERYENDSESSION).
                                    2.3.10 Функции инициализации.              

            Большинство программ  используют  две  локальные   функции
       инициализации:

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

            - Функция инициализации экземпляра программы выполняет за-
              дачи, необходимые  для  инициализации каждого экземпляра
              программы.

             Использование функций   инициализации    позволяет    вам
       сохранить  функцию  WinMain простой и удобочитаемой;  они также
       позволяют вам организовать инициализацию задач так,  чтобы  они
       могли  быть  помещены  в  отдельный  кодовый сегмент и сброшены
       после использования.  Программа Generic не  сбрасывает  функции
       инициализации.  (В  главе  15,  "Управление  памятью",  описана
       простая  программа   "Memory",   которая   сбрасывает   функции
       инициализации.)

       BOOL InitApplication(hInstance)
       HANDLE hInstance;                /* текущий экземпляр */
       {
               WNDCLASS WC;
.
      Windows 3.0/pg/1#3                                        = 34 =


               /* заполнение  структуры   класса   окна   параметрами,
                  описывающими основное окно */

               WC.style = NULL;          /* тип окна */
               WC.lpfnWndProc = MainWndProc; /* функция окна */

               WC.cbClsExtra = 0;     /* нет дополнительных данных */
               WC.clWhdExtra = 0;

               WC.hInstance = hInstance; /* экземпляр, владелец класса */
               WC.hIcon = LoadIcon(NULL, IDI_APPLICATION);
               WC.hCursor = LoadCursor(NULL, IDC_ARROW);
               WC.hbrBackground = GetStockObject(WHITE_BRUSH);
               WC.lpszMenuName = "Generic"; /* имя меню в .RC-файле */
               WC.lpszClassName = "GenericWndClass"; /* имя класса */

               /* регистрация класса */

               return(RegisterClass(&WC));
       }

       BOOL InitInstance(hInstance,nCmdShow)
       HANDLE hInstance;         /* текущий экземпляр            */
       int    nCmdShow;          /* Параметр функции ShowWindow  */
       {
            HWND     hWnd;       /* Дескриптор основного окна    */

            /* Сохранить номер экземпляра  в  статической  переменной,
               которая используется в последующих вызовах Windows */

            hInst = hInstance;

            /* Создать  основное окно для данного экземпляра программы */

            hWnd = CreateWindow(
                "GenericWndClass",           /* класс окна       */
                "Generic Sample Application", /* имя окна        */
                WS_OVERLAPPEDWINDOW,         /* тип окна         */
                CW_USEDEFAULT,               /* координата x     */
                CW_USEDEFAULT,               /* координата y     */
                CW_USEDEFAULT,               /* ширина           */
                CW_USEDEFAULT,               /* высота           */
                NULL,                        /* дескриптор родите-
                                                льского окна     */
                NULL,                        /* ID меню или дочер-
                                                него окна        */
                hInstance,                   /* экземпляр        */
                NULL);                       /* добавочная информа-
                                                ция  */

            /* если окно не создано, возвращается ошибка */

.
      Windows 3.0/pg/1#3                                        = 35 =

            if(!hWnd)
               return (FALSE);

            /* Сделать окно видимым. Перерисовать область пользователя
               и вернуть код успешной операции */

            ShowWindow(hWnd,nCmdShow);       /* Отобразить окно    */
            UpdateWindow(hWnd);              /* Перерисовать область
                                                пользователя */
            return (TRUE);
       }
                                                                               
               2.3.11 Командная строка прикладной программы.

            Можно проверить  командную  строку,   использующуюся   для
       запуска  прикладной  программы,  с помощью параметра lpCmdLine.
       Этот параметр указывает на  начало  массива  символов,  который
       содержит команды точно в том виде,  в каком они были напечатаны
       пользователем.  В  отличие  от  С-программ   командная   строка
       автоматически не разбивается на отдельные поля. Если необходимо
       извлечь из командной  строки  имя  файла  или  параметры,  надо
       написать  соответствующие  операторы.  Вы  можете  использовать
       вместо   этого   параметра   переменные   __argc   и    __argv.
       Дополнительную информацию вы найдете в главе 14, "Язык С и язык
       ассемблера".
                                             2.4 Функция окна.                 

            Каждое окно  должно  иметь  функцию  окна.  Функция   окна
       обеспечивает реакцию на вводимую информацию и сообщения системы
       управления окнами,  получаемые от Windows.  Функция окна  может
       быть простой, обрабатывающей только одно или два сообщения; она
       может  быть  и  сложной,  обрабатывающей  большое  число  типов
       сообщений для ряда окон прикладной программы.

            Функция окна имеет следующий вид:

            long FAR PASCAL MainWndProc(hWnd, message, wParam,
                                        lParam)
            HWND hWnd;              /* дескриптор окна           */
            unsigned message;       /* тип сообщения             */
            WORD wParam;            /* дополнительная информация */
            LONG lParam;            /* дополнительная информация */
            {
                 .
                 .
                 .
                switch (message) {
                 .
                 .
                 .
                    default: /* если не обрабатывается */
                return (DefWindowProc(hWnd, message, wParam,
.
      Windows 3.0/pg/1#3                                        = 36 =

                                      lParam));
                }
                return(NULL);
            }

            Функция окна использует соглашение по вызову языка PASCAL.
       Поскольку Windows вызывает эту функцию непосредственно и всегда
       использует  эти  соглашения,  требуется  использовать  ключевое
       слово PASCAL. В определении функции окна имеется ключевое слово
       FAR, поскольку Windows использует при вызове 32-битовый  адрес.
       Кроме  того,  необходимо  поименовать  функцию окна в операторе
       EXPORTS файла определения модуля. Смотрите раздел 2.6 "Создание
       файла определения модуля".

            Функция окна получает сообщения от Windows. Это могут быть
       сообщения о вводе,  переданные функцией WinMain,  или сообщения
       системы   управления  окнами,  поступающие  непосредственно  от
       Windows.  Функция окна должна проверить каждое сообщение и либо
       выполнить   некоторые   специальные  действия,  основываясь  на
       сообщениях,  либо  передать  сообщение  обратно   Windows   для
       обработки по умолчанию с помощью функции DefWindowProc.

            Параметр message  определяет тип сообщения.  Этот параметр
       используется в операторе switch для выбора нужного фрагмента  и
       соответствующей   ему  обработки.  Параметры  lParam  и  wParam
       содержат дополнительную информацию о  сообщении.  Функция  окна
       обычно  использует  эти  параметры для выполнения запрашиваемых
       действий.  Если функция окна  не  обрабатывает  сообщение,  она
       должна передать его функции DefWindowProc. Это дает уверенность
       в том,  что будут выполнены любые действия,  влияющие на  окно,
       программу или на Windows.

            Большинство функций     окна     обрабатывает    сообщение
       WM_DESTROY.  Windows посылает это сообщение функции окна  сразу
       же после разрушения окна.  Сообщение предоставляет функции окна
       возможность закончить обработку и,  если эта функция  основного
       окна программы,  послать сообщение WM_QUIT в очередь прикладной
       программы.  В приведенном ниже примере  показано,  как  функция
       основного окна должна обработать это сообщение:

            case WM_DESTROY:
                PostQuitMessage(0);
                break;

            Функция PostQuitMessage   помещает   сообщение  WM_QUIT  в
       очередь прикладной программы. Когда функция GetMessage получает
       это сообщение, она завершает работу цикла обработки сообщений и
       прикладной программы.

            Функция окна  получает  сообщения  из   двух   источников:
       сообщения  о  вводе  из  цикла  обработки сообщений и сообщения
       системы управления окнами из Windows.  Сообщения о вводе  имеют
       место при вводе от "мыши",  с клавиатуры или таймера.  Типичным
.
      Windows 3.0/pg/1#3                                        = 37 =

       сообщением о вводе являются: WM_KEYDOWN, WM_KEYUP, WM_MOUSEMOVE
       и WM_TIMER, которые явно соответствуют вводу с устройств ввода.

            Windows посылает   сообщения   системы  управления  окнами
       непосредственно  функции  окна  в  обход   очереди   прикладной
       программы  или цикла обработки сообщений.  Эти сообщения обычно
       являются  запросами  на  то,  чтобы  функция   окна   выполнила
       некоторые действия,  такие,  например,  как рисование в области
       пользователя или выдача информации  об  окне.  Сообщения  могут
       также информировать функцию окна об изменениях, которые Windows
       делает с окном. Типичными сообщениями системы управления окнами
       являются: WM_CREATE, WM_DESTROY и WM_PAINT.

            Функция окна   должна  возвратить  длинное  значение.  Это
       возвращаемое значение зависит от получаемых сообщений. В первом
       томе  Справочного  руководства  описаны  возвращаемые значения,
       когда они имеют смысл.  (Для большинства сообщений возвращаемое
       значение  необязательно.)  Если  функция  окна  не обрабатывает
       сообщение,  ее   возвращаемое   значение   представляет   собой
       возвращаемое значение функции DefWindowProc.
                                2.5 Создание панели диалога About.             

              Документ System  Application  Architecture,  Common User
       Access: Advanced Interface Design Guide, рекомендуется в каждую
       прикладную  программу  включать  панель  диалога About.  Панель
       диалога - это временное окно,  которое индицирует информацию  и
       запрашивает   ввод   от   пользователя.  Панель  диалога  About
       индицирует имя прикладной программы и информацию  об  авторском
       праве. Пользователь индицирует панель диалога About, выбирая из
       меню команду About. ( Соглашения по поводу панелей дилога About
       вы найдете в документе System Application Architecture,  Common
       User Access: Advanced Interface Design Guide.)

            Создание и индицирование панели диалога  осуществляется  с
       помощью  функции  DialogBox.  Эта  функция  для создания панели
       диалога использует  шаблон  панели  диалога,  адрес  экземпляра
       процедуры  и  дескриптор  родительского  окна.  Функция создает
       панель диалога,  с помощью которой вы можете выводить и вводить
       данные.

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

            1) создать шаблон панели диалога и добавить его к файлу
               описания ресурсов;

            2) создать функцию диалога и добавить  ее  к  исходному
               С-файлу;

            3) экспортировать  функцию диалога в файле определения
               модуля;

.
      Windows 3.0/pg/1#3                                        = 38 =

            4) добавить меню в файл описания ресурсов;

            5) обработать сообщение WM_COMMAND в прикладной программе.

            После выполнения   указанных   шагов   пользователь  может
       вывести панель диалога About при выборе команды About из  меню.
       В следующих разделах эти шаги разбираются более подробно.
                             2.5.1 Создание шаблона панели диалога.            

            Шаблон панели  диалога  -  это  текстовое  описание  типа,
       содержимого,  формы и размера панели диалога.  Можно  создавать
       шаблон  вручную  или  с  помощью  Windows 3.0 Dialog Editor.  В
       данном примере шаблон создается вручную.  Использование  Dialog
       Editor описано в "Tools".

            Шаблон панели диалога создается в файле описания ресурсов.
       Файл описания ресурсов содержит определения  ресурсов,  которые
       будут  использоваться  прикладной программой,  таких как иконы,
       курсоры и шаблоны панели диалога.  Для создания шаблона  панели
       диалога   About   необходимо  использовать  оператор  DIALOG  и
       заполнить его операторами блоков управления, как показано ниже:

       (1)      AboutBox DIALOG 22, 17, 144, 75
       (2)      STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
                CAPTION "About Generic"
       (3)      BEGIN
       (4)          CTEXT "Microsoft Windows"     -1,  0,  5, 144,  8
                    CTEXT "Generic Application"   -1,  0, 14, 144,  8
                    CTEXT "Version 3.0"           -1,  0, 34, 144,  8
       (5)          DEFPUSHBUTTON "ВК"         IDOK, 53, 59,  32, 14,
                                               WS_GROUP
                END

       1)   Оператор DIALOG  начинает  шаблон  панели   диалога.   Имя
            AboutBox идентифицирует шаблон,  когда для создания панели
            диалога используется функция DialogBox. Верхний левый угол
            панели размещается в точке с координатами (22,17)  области
            пользователя родительского  окна.  Панель имеет ширину 144
            единицы и высоту 75 единиц.  Единица ширины панели диалога
            равна  одной  четверти  ширины  символа системного шрифта.
            Единица высоты панели диалога равна одной  восьмой  высоты
            символа   системного  шрифта.  Функция  GetDialogBaseUnits
            возвращает размер единицы панели диалога в пикселях.

       2)   Оператор STYLE определяет тип панели диалога. В частности,
            в данном  примере  тип - накладываемое окно с окантовкой в
            виде рамки и системным меню.  Этот тип обычно используется
            в модальных панелях диалога.

       3)   Операторы BEGIN и END помечают начало и конец  определений
            блоков управления.  Панель  диалога   содержит   текст   и
            альтернативную   клавишу   по   умолчанию.  Альтернативная
.
      Windows 3.0/pg/1#3                                        = 39 =

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

            Операторы, строки и целые,  содержащиеся между операторами
            BEGIN  и  END,  описывают   содержимое   панели   диалога.
            Поскольку  вы  обычно  создаете  панели  диалога с помощью
            Dialog  Editor  то  в  данном  руководстве  не  приводится
            информация о числах и операторах, используемых в описании.
            Смотрите полное описание Dialog Editor в "Tools".

       4)   Оператор CTEXT создает прямоугольник с текстом в кавычках,
            расположенным в   центре   прямоугольника.  Этот  оператор
            встречается несколько раз  с  различным  текстом,  который
            появляется в панели диалога.

       5)   Оператор DEFPUSHBUTTON создает альтернативную клавишу, ко-
            торая дает  возможность   пользователю   дать   ответ   по
            умолчанию.  В  этом  случае при выборе мягкой клавиши "OK"
            панель диалога исчезает.

            Константы DS_MODALFRAME,  WS_CAPTION,  WS_SYSMENU и  IDOK,
       используемые в шаблоне панели диалога, определены во включаемом
       файле среды Windows. Следует включить этот файл в файл описания
       ресурсов, использовав директиву #include в начале файла.

            Операторы данного  файла были созданы с помощью текстового
       редактора и основывались  на  панели  диалога,  используемой  в
       другой программе. Вы можете многие ресурсы копировать из других
       программ и модифицировать с помощью  текстового  редактора.  Вы
       можете также  создавать панели диалога с помощью Dialog Editor.
       (Файлы,  созданные Dialog Editor,  содержат операторы,  которые
       несколько  отличаются от приведенных здесь.  Такие файлы обычно
       редактируются только с помощью Dialog Editor.  Более  подробное
       описание  использования  Dialog  Editor  для  создания  панелей
       диалога приводится в "Tools".)
                            2.5.2. Создание включаемого файла                  

            Часто бывает полезно создать включаемый  файл,  в  котором
       определяются константы и прототипы функций для вашей программы.
       Большинство прикладных программ содержат по  крайней  мере  два
       исходных файла,  разделяющих общие константы: исходный С-файл и
       файл  описания  ресурсов.  Поскольку  компилятор  ресурсов   rc
       выполняет  ту  же  самую  предобработку,  что  и  С-компилятор,
       полезно и удобно поместить определение констант в  единственный
       включаемый файл и затем включить его как в исходный С-файл, так
       и в файл описания ресурсов.

            Например, для программы Generic можно поместить  прототипы
       функций   WinMain,   MainWndProc,  About  и  InitApplication  и
       InitInstnce,  а также определение ID меню для команды About  во
       включаемый файл Generic.h. Файл будет выглядеть так:

.
      Windows 3.0/pg/1#3                                        = 40 =

            #define IDM_ABOUT 100

            int PASCAL            WinMain(HANDLE, HANDLE, LPSTR, int);
            BOOL                  InitApplication(HANDLE);
            BOOL                  InitInstance(HANDLE,int);
            long FAR PASCAL       MainWndProc(HWND, unsigned, WORD,
                                  LONG);
            BOOL FAR PASCAL       About(HWND, unsigned, WORD, LONG);

            Поскольку данный включаемый файл ссылается на типы  данных
       среды  Windows,  то  его  необходимо  вставить после того,  как
       подсоединен включаемый файл WINDOWS.H.  Другими словами, начало
       файла ресурсов должно выглядеть так:

            #include "windows.h"      /* требуется для всех программ */
            #include "generic.h"      /* нужен для данной программы */
                                   2.5.3 Создание функции диалога.             

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

            Функция, которая обрабатывает вводимую  в  панель  диалога
       About информацию называется About. Функция About подобно другим
       функциям диалога  использует  те  же  самые  параметры,  что  и
       функция   окна,   но   обрабатывет  только  сообщения,  которые
       специфичны для  панели  диалога.  (Функция  диалога  возвращает
       TRUE,  если обработала сообщение,  и FALSE в противном случае.)
       Функция  диалога  как  и  обычная   функция   окна   использует
       соглашение  по  вызову  языка PASCAL и объявляется как FAR.  Вы
       должны также указать эту  функцию  в  операторе  EXPORTS  файла
       определения  модуля.  Как  и  функцию  окна  вы  не должны явно
       вызывать в прикладной программе функцию диалога.

            В отличие   от   функции   окна   функция   About   обычно
       обрабатывает  только  сообщения о вводе от пользователя (такие,
       например,  как WM_COMMAND) и не должна посылать  необработанные
       сообщения   функции   DefWindowProc.  Функция  About  программы
       Generic выглядит так:

       BOOL FAR PASCAL About(hDlg, message, wParam, lParam)
       HWND hDlg;            /* дескриптор окна панели диалога */
       unsigned message;     /* тип сообщения                  */
       WORD wParam;          /* информация, зависящая от типа  */
       LONG lParam;          /* сообщения                      */
       {
                switch (message) {
                    case WM_INITDIALOG: /* сообщение: инициализация
                                           панели диалога        */
                        return (TRUE);
.
      Windows 3.0/pg/1#3                                        = 41 =


                    case WM_COMMAND:    /* сообщение: получение
                                           команды               */
                        if (wParam == IDOK||
                            wParam == IDCUNCEL) {  /* выбрана па-
                                       нель "ОК"? или "Close" */
                            EndDialog(hDlg, NULL); /* Завершение
                                                      работы с па-
                                                      нелью диало-
                                                      га         */
                            return (TRUE);
                        }
                        break;
                }
                return (FALSE);       /* сообщение не обработано */
            }

            Функция About  обрабатывает  два  сообщения:  WM_COMMAND и
       WM_INITDIALOG.  Сообщение  WM_INITDIALOG   посылается   Windows
       функции   диалога  для  того,  чтобы  функция  подготовилась  к
       индицированию  панели  диалога.  В  этом  случае  WM_INITDIALOG
       возвращает   TRUE,   так   что  ввод  захватывает  первый  блок
       управления  в  панели  диалога,  в   котором   установлен   бит
       WS_TABSTOP  (это  будет  альтернативная  клавиша по умолчанию).
       Если WM_INITDIALOG возвратит FALSE,  то ни один блок управления
       не захватит ввод.

            В отличие   от   этого   сообщения   WM_COMMAND   являются
       результатом ввода от  пользователя.  About  отвечает  на  выбор
       клавиши  "OK"  или  "Close"  в  системном  меню вызовом функции
       EndDialog, которая удаляет панель диалога, и Windows продолжает
       выполнение прикладной программы. Функция EndDialog используется
       для завершения работы панели диалога.
                           2.5.4 Определение меню с элементом About.           

            Теперь, когда имеется  панель  диалога  About,  необходимо
       дать пользователю возможность указать, когда ее индицировать. В
       большинстве прикладных программ команда About  добавляется  как
       последняя  команда  в  меню Help.  Если прикладная программа не
       имеет меню Help,  то команда добавляется в  первое  меню,  чаще
       всего  это  меню  File.  В  Generic  есть только команда About,
       которая добавляется как элемент меню Help.

            Чаще всего меню создают,  определяя  его  ресурс  в  файле
       описания   ресурсов.   Поместите  следующие  операторы  в  файл
       описания ресурсов:

            GenericMenu             MENU
            BEGIN
                POPUP               "&Help"
                BEGIN
                    MENUITEM        "About Generic...",IDM_ABOUT
.
      Windows 3.0/pg/1#3                                        = 42 =

                END
            END

            Эти операторы описывают меню с именем  "GenericMenu"  и  с
       единственной  командой Help.  Эта команда отображает выпадающее
       меню с единственным элементом "About Generic...".

            Отметим знак амперсанда "&" в строке "&Help".  Этот символ
       непосредственно предшествует мнемонике команды. Мнемоника - это
       уникальный символ или цифра,  с  помощью  которой  пользователь
       может взаимодействовать с меню или командами. Это часть прямого
       доступа к Windows. Если пользователь нажимает клавишу мнемоники
       вместе  с  клавишей ALT,  Windows выбирает меню или команду.  В
       случае "&Help"   Windows   заменяет    знак    амперсанда    на
       подчеркивание  символа,  которому  он  предшествует,  в  данном
       случае "H", при выводе меню.

            Пользователь может увидеть команду About при  выборе  меню
       Help.   Если   пользователь  выбирает  команду  About,  Windows
       посылает  функции   окна   сообщение   WM_COMMAND,   содержащее
       идентификатор команды About, в данном случае IDM_ABOUT.
                              2.5.5 Обработка сообщения WM_COMMAND.            

            После добавления  команды  к  меню  Generic вам необходима
       возможность ответить на выбор пользователем этой  команды.  Для
       этого   необходимо  обработать  сообщение  WM_COMMAND.  Windows
       посылает  это  сообщение  функции  окна,   когда   пользователь
       выбирает команду из меню прикладной программы. Windows помещает
       ID  команды   меню   в   параметр   wParam,   так   что   можно
       проконтролировать,  какая команда выбрана. Можно проверить этот
       параметр,  используя  оператор  switch.  Если  параметр   равен
       IDM_ABOUT (ID команды About), то индицируется панель диалога. В
       случае любого другого значения  необходимо  передать  сообщение
       функции  DefWindowProc.  Если  этого не сделать,  то все другие
       команды меню сделаются недоступными.

            Фрагмент WM_COMMAND должен выглядеть так

            FARPROC lpProcAbout;
                .
                .
                .
                case WM_COMMAND:              /* сообщение: команда
                                                системного меню  */
                    if (wParam == IDM_ABOUT) {
       (1)             lpProcAbout = MakeProcInstance(About,hInst);
       (2)             DialogBox(hInst,        /* текущий экземп-
                                                  ляр            */
                                 "AboutBox",   /* используемый ре-
                                                  сурс           */
                                 hWnd,         /* дескриптор роди-
                                                  тельского окна */
.
      Windows 3.0/pg/1#3                                        = 43 =

                                 lpProcAbout); /* адрес экземпляра
                                                  функции About()*/
       (3)             FreeProcInstance(lpProcAbout);
                       break;
                    }
                    else     /* обработка сообщений Windows  */
                        return (DefWindowProc(hWnd, message,
                                              wParam, lParam));

       (1)  Для индицирования панели диалога необходим адрес экземпля-
            ра функции диалога. Адрес экземпляра процедуры создается с
            помощью  функции  MakeProcInstance.  Эта функция связывает
            сегмент данных текущего экземпляра прикладной программы  с
            указателем функции.  Это  дает  гарантию  того,  что когда
            Windows вызовет функцию диалога,  она  будет  использовать
            данные   текущего  экземпляря,  а  не  некоторого  другого
            экземпляря программы.

            Функция MakeProcInstance   возвращает   адрес   экземпляра
            процедуры.  Это  значение должно быть присвоено переменной
            указателя, имеющей тип FARPROC.

       (2)  Функция DialogBox создает панель диалога.  Для нее необхо-
            димы дескриптор текущего экземпляра прикладной программы и
            имя шаблона панели диалога.  Она использует эту информацию
            для  загрузки  шаблона  панели диалога.  Функция DialogBox
            также  использует  дескриптор  родительского  окна  (окна,
            которому  принадлежит  панель  диалога) и адрес экземпляра
            процедуры.

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

       (3)  Когда функция  DialogBox возвращает управление,  адрес эк-
            земпляря функции  диалога  становится больше не нужным,  и
            функция FreeProcInstance   освобождает   его.   При   этом
            содержимое переменной указателя становится неопределенным,
            и при попытке ее повторного использования выдается ошибка.
                               2.6 Создание файла определения модуля.          

            Каждая прикладная программа должна иметь файл  определения
       модуля. Этот файл определяет имя, сегменты, требования к памяти
       и  экспортируемые  функции  прикладной  программы.  Для   такой
       простой прикладной  программы  как  Generic  необходимо иметь в
       нем,  по крайней мере,  операторы  NAME,  STACKSIZE,  HEAPSIZE,
       EXETYPE  и  EXPORTS.  Однако  большинство  прикладных  программ
       включают полное определение модуля, как это показано ниже:

            ;файл определения модуля для Generic -- используется
.
      Windows 3.0/pg/1#3                                        = 44 =

            ;link.exe

       (1)  NAME Generic            ;имя модуля прикладной программы

       (2)  DESCRIPTION 'Пример прикладной программы'

       (3)  EXETYPE  WINDOWS        ;требуется для всех программ
                                    ;Windows

       (4)  STUB  'WINSTUB.EXE'     ;генерация сообщения об ошибке,
                                    ;если программа запущена без
                                    ;Windows

       (5)  CODE  MOVEABLE DISCARDABLE ;кодовый сегмент перемещаем в
                                    ;памяти и удаляем

            ;сегмент DATA должен быть типа MULTIPLE, если программа
            ;вызывается более одного раза

       (6)  DATA  MOVEABLE MULTIPLE

       (7)  HEAPSIZE  1024

       (8)  STACKSIZE 5120          ;рекомендованный минимум для Windows

            ;все функции, которые  вызываются  любой  подпрограммой
            ;Windows, должны быть экспортируемыми

       (9)  EXPORTS
                MainWndProc  @1  ;имя функции, обрабатывающей окно
                AboutDlgProc @2  ;имя функции, обрабатывающей
                                 ;панель диалога

            Точка с запятой - это  ограничитель  комментария  в  файле
       определения модуля.

       1)   Оператор NAME определяет имя прикладной программы, исполь-
            зуемое Windows для идентификации программы.  Оператор NAME
            является обязательным.

       2)   Оператор DESCRIPTION является  необязательным  оператором,
            который помещает сообщение "Пример прикладной программы" в
            выполняемый   файл  прикладной  программы.  Этот  оператор
            обычно используется для занесения в файл  или  версии  или
            информации об авторских правах.

       3)   Оператор EXETYPE идентифицирует выполняемый файл  как вы-
            полняемый файл в  формате  Windows  или  в  формате  OS/2.
            Прикладные  программы  для  Windows  должны иметь оператор
            EXETYPE  WINDOWS,  поскольку  по   умолчанию   компоновщик
            создает файлы в формате OS/2.

       4)   Оператор STUB специфицирует  другой  необязательный  файл,
.
      Windows 3.0/pg/1#3                                        = 45 =

            определяющий выполняемый модуль специального типа, который
            должен  быть  помещен  в  начало  файла.  Этот выполняемый
            модуль индицирует предупреждающее  сообщение  и  завершает
            программу,  если  пользователь  пытается  выполнить ее вне
            среды Windows. Вместе с SDK поставляется файл WINSTUB.EXE.
            Этот  модуль выводит предупреждающее сообщение и завершает
            выполнение программы  при  запуске  программы  вне   среды
            Windows. Вы можете указать собственный модуль STUB.

       5)   Оператор CODE определяет требования к  памяти  со  стороны
            кодового сегмента  прикладной  программы.  Он  состоит  из
            выполняемого  кода,  который  генерируется  при трансляции
            файла Generic.c.  Generic - это программа в модели  памяти
            SMALL только с одним кодовым сегментом,  который определен
            как MOVEABLE DISCARDABLE.  Если программа  не  работает  и
            Windows необходимо дополнительное место в памяти,  система
            может переместить кодовый сегмент  для  того,  чтобы  дать
            место  другим  сегментам,  или  при  необходимости  вообще
            удалить его из памяти. При необходимости удаленный сегмент
            загружается Windows автоматически.

       6)   Оператор DATA определяет требования к  памяти  со  стороны
            сегмента данных  прикладной  программы.   Сегмент   данных
            содержит    место   для   всех   статических   переменных,
            объявленных в файле Generic.c. Он также содержит место для
            стека  программы  и локальной динамической области памяти.
            Сегмент данных  также  определен  как  MOVEABLE.  Ключевое
            слово  MULTIPLE  служит  для  указания Windows на создание
            нового  сегмента  данных  для  прикладной  программы   при
            запуске каждого нового экземпляра. Ключевое слово MULTIPLE
            является обязательным,  если имеется  возможность  запуска
            нескольких экземпляров прикладной программы.

       7)   Оператор HEAPSIZE определяет размер в байтах локальной ди-
            намической области памяти  прикладной  программы.  Generic
            использует   ее   для   отведения   временной   структуры,
            используемой для регистрации класса окна,  занимающей 1024
            байта   памяти.   Прикладные   программы,   которые  часто
            используют локальную динамическую область  памяти,  должны
            специфицировать больший объем памяти.

       8)   Оператор STACKSIZE определяет размер в байтах стека  прик-
            ладной программы.   Стек   используется   для   временного
            хранения  аргументов  функции.  Любая  программа,  которая
            вызывает свои собственные локальные функции,  должна иметь
            стек.   Generic   использует   5120   байт   для  стека  -
            рекомендованный средой Windows минимум.

       9)   Оператор EXPORTS  определяет  имена  и  порядковые  номера
            функций, которые  должны  быть  экспортированы  прикладной
            программой.  Generic  экспортирует   свою   функцию   окна
            MainWndProc,   которая   имеет  порядковый  номер  1  (это
            идентификатор;  он может быть любым целым, но обычно такие
.
      Windows 3.0/pg/1#3                                        = 46 =

            значения     присваиваются     экспортируемым     функциям
            последовательно в порядке перечисления).  Windows требует,
            чтобы  все функции за исключением WinMain,  которые должны
            быть вызваны средой Windows,  были бы экспортированы таким
            способом.   На   эти  функции  ссылаются  как  на  функции
            многократного  вызова.  К  функциям  многократного  вызова
            относятся следующие:

            - Все функции окон.

            - Все функции диалога.

            - Специальные  функции  многократного  вызова типа функций
              перечисления, которые требуются для функций Windows API.

            - Любые другие функции,  которые могут быть вызваны из вне
              вашей программы.

            Подробная информация   по  функциям  многократного  вызова
       содержится в главе 14 "Язык С и язык ассемблера".

            Подробная информация  по  операторам   файла   определения
       модуля содержится во втором томе Справочного руководства.
                                2.7 Объединение компонент Generic.             

            Теперь вы готовы к тому,  чтобы объединить отдельные части
       нашего  примера  Generic.  (Вы  можете  скопировать   файлы   с
       исходными  текстами  Generic  с  диска  "SDK Sample Source Code
       Disk".)

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

            1) создать исходный файл на языке С (.С).

            2) создать включаемый файл (.Н).

            3) создать файл описания ресурсов (.RC).

            4) создать файл определения модуля (.DEF).

            5) создать файл make;

            6) запустить make для трансляции и компоновки программы.

            В следующих разделах эти шаги описаны более подробно.

            Примечание: Вместо  того,  чтобы  набирать  вручную данные
       примеры,  вы возможно найдете более удобным просто  скопировать
       исходные  файлы с диска,  поставляемого с SDK и откомпилировать
       их.

.
      Windows 3.0/pg/1#3                                        = 47 =

                          2.7.1 Создание исходного файла на языке С.           

            Исходный файл на языке С должен содержать функцию WinMain,
       функцию  окна  MainWndProc,  функцию  диалога  About  и функции
       инициализации  InitApplication  и  InitInstance.  Назовем  файл
       Generic.c.

            Общий вид этого файла:

       /*************************************************************
            PROGRAM: GENERIC

            НАЗНАЧЕНИЕ: Шаблон для создания  прикладных  программ  для
                        Windows.

            ФУНКЦИИ:

                  WinMain() - вызывает функции инициализации, запуска-
                              ет цикл обработки сообщений.
                  InitApplication() - инициализирует данные окна и ре-
                              гистрирует окно.
                  InitInstance() -  сохраняет  дескриптор экземпляра и
                              создает основное окно.
                  MainWndProc() - обрабатывает сообщения.
                  About() -   обрабатывает сообщения,  для  панели  диалога
                              About.

            КОММЕНТАРИИ:

                  Windows может иметь несколько копий вашей прикладной
                  программы, работающих одновременно. Переменная hInst
                  содержит номер экземпляра для того,  чтобы обработка
                  сообщений   производилась    для    соответствующего
                  экземпляра программы.
       ***************************************************************/

       #include "windows.h" /* требуется для всех программ Windows */
       #include "Generic.h" /*  специфично для этой программы  */

       HANDLE  hInst;       /* текущий экземпляр */

       /*************************************************************
            ФУНКЦИЯ: WinMain(HANDLE,HANDLE,LPSTR,int)

            НАЗНАЧЕНИЕ: вызов функций инициализации,  запуск цикла об-
                        работки сообщений.

            КОММЕНТАРИЙ:

                  Windows рассматривает эту функцию как исходную точку
                  входа в  программу.  Эта  функция  вызывает  функции
                  инициализации  прикладной  программы.  Если  не были
                  запущены другие экземпляры этой  программы,  то  она
.
      Windows 3.0/pg/1#3                                        = 48 =

                  также  вызывает  функцию  инициализации  экземпляра.
                  Затем,  она  запускает  цикл  обработки   сообщений,
                  который    является    высокоуровневой    структурой
                  обработки  для  остальной  части   программы.   Цикл
                  обработки   сообщений   завершается   при  получении
                  сообщения WM_QUIT,  и функция  завершает  выполнение
                  программы, возвращая в качестве кода возврата число,
                  передаваемое функцией PostQuitMessage.

                  Если функция завершается до входа в  цикл  обработки
                  сообщений, то по соглашению она возвращает NULL.

       ***************************************************************/

        int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine,
                           nCmdShow)
        HANDLE hInstance;     /* текущий экземпляр */
        HANDLE hPrevInstance; /* предыдущий экземпляр */
        LPSTR lpCmdLine;      /* командная строка */
        int nCmdShow;         /* тип представления окна (откры-
                                 тое или в виде иконы) */
        {
        MSG msg;              /* сообщение       */

       if (!hPrevInstance)    /* инициализирована ли программа? */
           if (!InitApplication(hInstance)) /* инициализация */
               return (FALSE); /* выход, если инициализация не
                                  произведена                */

       /* инициализация экземпляра */

       if(!InitInstance(hInstance,nCmdShow))
           return(FALSE);

       /* цикл обработки сообщений */

       while (GetMessage(&msg,      /* структура сообщения   */
               NULL,                /* дескриптор окна, полу-
                                       чившего сообщение     */
               NULL,                /* проверяемое сообщение,
                                       имеющее наименьший код*/
               NULL))               /* проверяемое сообщение,
                                       имеющее наибольший код*/
            {
            TranslateMessage(&msg); /* преобразовать  коды
                                       виртуальных клавиш    */
            DispatchMessage(&msg);  /* передать сообщение
                                       окну                  */
             }
       return (msg.wParam); /* возвращаемое значение функции
                               PostQuitMessage               */
       }

.
      Windows 3.0/pg/1#3                                        = 49 =

       /*************************************************************
            ФУНКЦИЯ: InitApplication(HANDLE)

            НАЗНАЧЕНИЕ: Инициализирует   данные  окна  и  регистрирует
                        класс окна.

            КОММЕНТАРИИ:

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

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

       ***************************************************************/

       BOOL InitApplication(hInstance)
       HANDLE hInstance;                /* текущий экземпляр */
       {
               WNDCLASS WC;

               /* заполнение структуры класса окна параметрами описы-
                  вающими основное окно */

               WC.style = NULL;          /* тип окна */
               WC.lpfnWndProc = MainWndProc; /* функция окна */

               WC.cbClsExtra = 0;     /* нет дополнительных данных */
               WC.clWhdExtra = 0;

               WC.hInstance = hInstance; /* экземпляр, владелец класса */
               WC.hIcon = LoadIcon(NULL, IDI_APPLICATION);
               WC.hCursor = LoadCursor(NULL, IDC_ARROW);
               WC.hbrBackground = GetStockObject(WHITE_BRUSH);
               WC.lpszMenuName = "Generic"; /* имя меню в .RC-файле */
               WC.lpszClassName = "GenericWndClass"; /* имя класса */

               /* регистрация класса */

               return(RegisterClass(&WC));
       }

       /*************************************************************
            ФУНКЦИЯ: InitInstance(HANDLE,int)

            НАЗНАЧЕНИЕ: Сохраняет  дескриптор  экземпляра  и   создает
.
      Windows 3.0/pg/1#3                                        = 50 =

                        основное окно.

            КОММЕНТАРИИ:

                  Эта функция  вызывается  во  время инициализации для
                  каждого экземпляра программы.  Эта функция выполняет
                  те  инициализации,  которые  не могут быть разделены
                  между различными экземплярами.

                  В данном случае мы сохраняем дескриптор экземпляра в
                  статической переменной, создаем и индицируем окно.

       ***************************************************************/

       BOOL InitInstance(hInstance,nCmdShow)
       HANDLE hInstance;         /* текущий экземпляр            */
       int    nCmdShow;          /* Параметр функции ShowWindow  */
       {
            HWND     hWnd;       /* Дескриптор основного окна    */

            /* Сохранить номер экземпляра  в  статической  переменной,
               которая используется в последующих вызовах Windows */

            hInst = hInstance;

            /* Создать  основное окно для данного экземпляра программы */

            hWnd = CreateWindow(
                "GenericWndClass",           /* класс окна       */
                "Generic Sample Application", /* имя окна        */
                WS_OVERLAPPEDWINDOW,         /* тип окна         */
                CW_USEDEFAULT,               /* координата x     */
                CW_USEDEFAULT,               /* координата y     */
                CW_USEDEFAULT,               /* ширина           */
                CW_USEDEFAULT,               /* высота           */
                NULL,                        /* дескриптор родите-
                                                льского окна     */
                NULL,                        /* ID меню или дочер-
                                                него окна        */
                hInstance,                   /* экземпляр        */
                NULL);                       /* добавочная информа-
                                                ция  */

            /* если окно не создано, возвращается ошибка */

            if(!hWnd)
               return (FALSE);

            /* Сделать окно видимым. Перерисовать область пользователя,
               и вернуть код успешной операции */

            ShowWindow(hWnd,nCmdShow);       /* Отобразить окно    */
            UpdateWindow(hWnd);              /* Перерисовать область
.
      Windows 3.0/pg/1#3                                        = 51 =

                                                пользователя */
            return (TRUE);
       }

       /*************************************************************
            ФУНКЦИЯ: MainWndProc(HWND,unsigned,WORD,LONG)

            НАЗНАЧЕНИЕ: Обработка сообщений.

            КОММЕНТАРИИ:

                    Для обработки   сообщения   IDM_ABOUT   вызывается
                    MakeProcInstance для получения  адреса  экземпляра
                    процедуры функции About.  Затем вызывается функция
                    DialogBox,  которая  создает  панель   диалога   в
                    соотвествии  с  шаблоном  из  файла  Generic.rc  и
                    передает   управление   функции    About.    После
                    возвращения   управления   она  освобождает  адрес
                    экземпляра процедуры.

       ***************************************************************/

       long FAR PASCAL MainWndProc(hWnd, message, wParam,
                                   lParam)
       HWND hWnd;              /* дескриптор окна           */
       unsigned message;       /* тип сообщения             */
       WORD wParam;            /* дополнительная информация */
       LONG lParam;            /* дополнительная информация */
       {

            FARPROC lpProcAbout;

           switch (message) {

                case WM_COMMAND:              /* сообщение: команда
                                                системного меню  */
                    if (wParam == IDM_ABOUT) {
                       lpProcAbout = MakeProcInstance(About,hInst);
                       DialogBox(hInst,        /* текущий экземп-
                                                  ляр            */
                                 "AboutBox",   /* используемый ре-
                                                  сурс           */
                                 hWnd,         /* дескриптор роди-
                                                  тельского окна */
                                 lpProcAbout); /* адрес экземпляра
                                                  функции About()*/
                       FreeProcInstance(lpProcAbout);
                       break;
                    }
                    else     /* обработка сообщений Windows  */
                        return (DefWindowProc(hWnd, message,
                                              wParam, lParam));

.
      Windows 3.0/pg/1#3                                        = 52 =


                case WM_DESTROY:  /* окно разрушено */
                    PostQuitMessage(0);
                    break;

               default: /* если не обрабатывается */
                    return (DefWindowProc(hWnd, message, wParam,
                                 lParam));
           }
           return(NULL);
       }

       /*************************************************************
            ФУНКЦИЯ: About(HWND,unsigned,WORD,LONG)

            НАЗНАЧЕНИЕ: Обработка сообщений панели диалога "About".

            КОММЕНТАРИИ:

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

                    Ожидает, пока пользователь не нажмет клавишу "OK",
                    и затем закрывает панель диалога.

       ***************************************************************/

       BOOL FAR PASCAL About(hDlg, message, wParam, lParam)
       HWND hDlg;            /* дескриптор окна панели диалога */
       unsigned message;     /* тип сообщения                  */
       WORD wParam;          /* информация, зависящая от типа  */
       LONG lParam;          /* сообщения                      */
       {
                switch (message) {
                    case WM_INITDIALOG: /* сообщение: инициализация
                                           панели диалога        */
                        return (TRUE);

                    case WM_COMMAND:    /* сообщение: получение
                                           команды               */
                        if (wParam == IDOK||
                            wParam == IDCUNCEL) {  /* выбрана па-
                                       нель "ОК"? или "Close" */
                            EndDialog(hDlg, NULL); /* Завершение
                                                      работы с па-
                                                      нелью диало-
                                                      га         */
                            return (TRUE);
                        }
                        break;
                }
                return (FALSE);       /* сообщение не обработано */
            }
.
      Windows 3.0/pg/1#3                                        = 53 =

                                                                               
                     2.7.2 Создание включаемого файла.

            Во включаемом файле содержатся определения  и  объявления,
       требуемые для файла с исходным текстом на С, который включается
       в файл с исходным текстом с помощью директивы #include.  Файл с
       именем Generic.h будет выглядеть следующим образом:

            #define IDM_ABOUT 100

            int PASCAL            WinMain(HANDLE, HANDLE, LPSTR, int);
            BOOL                  InitApplication(HANDLE);
            BOOL                  InitInstance(HANDLE,int);
            long FAR PASCAL       MainWndProc(HWND, unsigned, WORD,
                                  LONG);
            BOOL FAR PASCAL       About(HWND, unsigned, WORD, LONG);

                             2.7.3 Создание файла описания ресурсов.           

            Файл описания  ресурсов  должен  содержать  шаблон  панели
       диалога About и шаблон меню Help. Имя этого файла - Generic.rc.
       Общий вид:


            #include "windows.h"
            #include "generic.h"
            GenericMenu             MENU
            BEGIN
                POPUP               "&Help"
                BEGIN
                    MENUITEM        "About Generic...",IDM_ABOUT
                END
            END

            AboutBox DIALOG 22, 17, 144, 75
            STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
            CAPTION "About Generic"
            BEGIN
                CTEXT "Microsoft Windows"     -1,  0,  5, 144,  8
                CTEXT "Generic Application"   -1,  0, 14, 144,  8
                CTEXT "Version 3.0"           -1,  0, 34, 144,  8
                DEFPUSHBUTTON "ВК"         IDOK, 53, 59,  32, 14,
                                           WS_GROUP
            END
                            2.7.4 Создание файла определения модуля.           

            Файл определения   модуля   должен  содержать  определение
       модуля программы Generic.  Дадим файлу имя  Generic.def.  Общий
       его вид будет следующим:

.
      Windows 3.0/pg/1#3                                        = 54 =

            ;файл определения модуля для Generic -- используется
            ;link.exe

            NAME Generic            ;имя модуля прикладной программы

            DESCRIPTION 'Пример прикладной программы'

            EXETYPE  WINDOWS        ;требуется для всех программ
                                    ;Windows

            STUB  'WINSTUB.EXE'     ;генерация сообщения об ошибке,
                                    ;если программа запущена без
                                    ;Windows

            CODE  MOVEABLE DISCARDABLE ;кодовый сегмент перемещаем в
                                    ;памяти и удаляем

            ;сегмент DATA должен быть типа MULTIPLE, если программа
            ;вызывается более одного раза

            DATA  MOVEABLE MULTIPLE

            HEAPSIZE  1024

            STACKSIZE 5120          ;рекомендованный минимум для Windows

            ;все функции, которые  вызываются  любой  подпрограммой
            ;Windows, должны быть экспортируемыми

            EXPORTS
                MainWndProc  @1  ;имя функции, обрабатывающей окно
                AboutDlgProc @2  ;имя функции, обрабатывающей
                                 ;панель диалога
                                      2.7.5 Создание файла make.               

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

            - использовать  компилятор  С  с  именем cl для трансляции
              файла Generic.c.

            - использовать компоновщик link для компоновки  объектного
              файла Generic.obj  с  библиотекой   Windows   и   файлом
              описания модуля Generic.def.

            - использовать компилятор ресурсов rc для создания  двоич-
              ного файла ресурсов и подсоединить  его  к  выполняемому
              файлу прикладной программы.

            Ниже приводятся соответствующие операторы для трансляции и
       компоновки файлов Generic:

       # Стандартный  Make-файл Windows.  Служебная программа MAKE.EXE
.
      Windows 3.0/pg/1#3                                        = 55 =

       # сравнивает дату создания файлов с левой стороны от  двоеточия
       # с  датой  создания  файлов  справа  от двоеточия.  Если файлы
       # справа новее, чем слева, MAKE запускает командные строки, ко-
       # торые  следуют  за этой строкой и сдвинуты по крайней мере на
       # один пробел или символ табуляции. Могут быть использованы лю-
       # бые допустимые командные строки MS-DOS.

       # Корректировка ресурса в случае необходимости

       (1)    generic.res: generic.rc generic.h
                    rc -r generic.rc

       # Корректировка объектного файла в случае необходимости

       (2)    generic.obj: generic.c generic.h
                    cl -c -Gsw -Oas -Zpe generic.c

       # Корректировка выполняемого файла в случае необходимости,
       # и присоединение к нему ресурсов

       (3)    generic.exe: generic.obj generic.def
                    link4 /NOD generic, , , slibew libw, generic.def
                    rc generic.res

       # Если файл .res - новый, а файл .exe не изменялся,
       # скорректировать ресурсы
       # Заметим, что файл .rc может корректироваться без повторной
       # трансляции или компоновки

       (4)    generic.exe: generic.res
                    rc generic.res

       1)   Первые две строки служат make для создания оттранслирован-
            ного файла ресурсов generic.res, если были скорректированы
            или файл описания ресурсов generic.rc или включаемый  файл
            generic.h. Параметр -r команды rc служит для создания фай-
            ла ресурсов без подсоединения его к выполняемому файлу.

       2)   Следующие две  строки  служат  make  для  создания   файла
            generic.obj,  если файлы generic.c или generic.h имеют бо-
            лее позднюю версию (по сравнению с  generic.obj).  Команда
            cl имеет несколько параметров в командной строке,  которые
            служат для подготовки прикладной программы к выполнению  в
            среде  Windows.  Минимально  требуемые параметры - это -c,
            -Gw, -Zp.  В этом случае  подразумевается,  что  программа
            Generic -  это  программа  в  малой  модели  памяти.  (Все
            программы  в  данном  руководстве  используют малую модель
            памяти).


       3)   Затем программа make создает файл generic.exe,  если любой
            из файлов generic.obj,  generic.def  имеют  более  позднюю
            версию (по сравнению с generic.exe).  Малые программы типа
.
      Windows 3.0/pg/1#3                                        = 56 =

            Generic должны быть  скомпонованы  с  библиотекой  Windows
            slibw.lib и  с  библиотекой  Windows,  содержащей  функции
            исполняющей системы С.  Объектный файл generic.obj и  файл
            определения  модуля generic.def используются как аргументы
            в командной строке link.

       4)   Последняя команда rc автоматически подсоединяет  скомпили-
            рованные ресурсы  файла  generic.res  к выполняемому файлу
            generic.exe.
                                                                               
                          2.7.6 Запуск программы MAKE.

            После создания  make-файла  вы  можете  откомпилировать  и
       скомпоновать  свою  программу  с  помощью  утилиты  MAKE.  Ниже
       показано, как это сделать для программы Generic:

            MAKE GENERIC
                             2.8 Использование Generic как шаблона.            

            Программа Generic и не имеет никаких  "лишних"  функций  и
       может  служить  отправной точкой для создания ваших собственных
       программ. Она   использует   стандарты   данные   в    :"System
       Application   Architecture,   Common   User   Access:  Advansed
       Interface Design Guide",  и содержит все файлы,  которые  может
       содержать  прикладная  программа:  .def,  .h,  .rc,  .c и make.
       Включена  также  стандартная  панель  диалога  About,  а  также
       команда меню Help - About Generic.

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

            Ниже описывается,  как  использовать  Generic  в  качестве
       шаблона:

            1. Выберите свое имя файла программы.

            2. Скопируйте указанные ниже имена файлов, изменив их име-
               на в  соответствии  с  именем   программы:   generic.c,
               generic.h, generic.def, generic.rc и generic.

            3. С  помощью  текстового редактора измените все вхождения
               слова generic в исходном Си-файле прикладной  программы
               (в   первую   очередь   generic.c)  на  имя  прикладной
               программы. Имеются в виду изменения:

               - имени класса GenericWndClass;

               - имени меню класса: GenericMenu;
.
      Windows 3.0/pg/1#3                                        = 57 =


               - заголовка окна "Пример прикладной программы Generic";

               - имени включаемого файла generic.h;

            4. Используйте текстовый редактор  для  изменения  каждого
               вхождения слова   Generic  в  файл  определения  модуля
               программы  на  имя  вашей  программы.  Имеются  в  виду
               изменения:

               - имени программы Generic;

            5. Используйте текстовый редактор  для  изменения  каждого
               вхождения слова  Generic  в  файл   описания   ресурсов
               программы  на  имя  вашей  программы.  Имеются  в  виду
               изменения:

               - имени включаемого файла generic.h;

               - заголовка программы "Generic Application";

               - имени меню GenericMenu.

            6. Используйте текстовый редактор  для  изменения  каждого
               вхождения слова  Generic  в  файл make программы на имя
               вашей программы. Имеются в виду изменения:

               - имени исходного файла на языке С generic.c;

               - имени объектного файла generic.obj;

               - имени выполняемого файла generic.exe;

               - имени файла определения модуля generic.def.

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

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

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

.
      Windows 3.0/pg/1#3                                        = 58 =

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

       Раздел               Руководство
       ---------------------------------------------------------------
       Программная модель   Руководство программиста, глава 1, "Обзор
       Windows              среды Windows"

       Цикл обработки       Руководство программиста, глава 2, "Приклад-
       сообщений            ная программа Generic"

       Меню                 Руководство программиста, глава 7, "Меню"

       Панель диалога       Руководство программиста, глава 9, "Панели
                            диалога"

       Использование стан-  Руководство программиста, глава 14, "Язык С
       дартных функций С и  и язык ассемблера"
       языка ассемблера

       Функции и сообщения  Справочное руководство, том 1.
       Windows

       Сообщение WM_COMMAND Справочное руководство, том 1, глава 6,
                            "Список сообщений"

       Типы данных и струк- Справочное руководство, том 2, глава 7,
       туры                 "Типы и структуры данных"

       Средства разработки "Tools"


.
      Windows 3.0/pg/1#3                                        = 59 =

                 ЧАСТЬ 2.  ПРОГРАММИРОВАНИЕ ПРИКЛАДНЫХ ПРОГРАММ WINDOWS.       
      ----------------------------------------------------------------
            Так же  как  и остальные прикладные программы,  прикладные
       программы в среде Windows производят  ввод  от  пользователя  и
       выполняют вывод  на  экран  и  принтер.  Однако,  в  отличие от
       стандартных программ,   программы   в   среде   Windows   могут
       взаимодействовать   друг   с   другом   внутри  мультизадачного
       графического окружения.  По   этой   причине   они   не   могут
       осуществлять непосредственный  ввод  с  клавиатуры  и  выводить
       непосредственно на устройства вывода.  Вместо этого они  должны
       иметь  между  программой  и системными ресурсами среду Windows.
       Это неудобство  уменьшается  благодаря  встроенной  в   Windows
       мощной   поддержке   интерфейса  пользователя  и  интерфейса  с
       системным оборудованием.

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

            В части  1  содержится  обзор  среды  Windows  и   базовой
       структуры   прикладной   программы,  и  представлены  некоторые
       основные  элементы  прикладных  программ,  типа  окон,  меню  и
       панелей диалога.

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

            Каждая глава   части  2  посвящена  определенному  разделу
       программирования в среде Windows и содержит  пример  программы,
       иллюстрирующий  использование  концепций,  приведенных в данной
       главе.



.
      Windows 3.0/pg/1#3                                        = 60 =

                                                                               
                          Глава 3. Вывод в окно.
      ----------------------------------------------------------------
            В Windows  весь  вывод  в  окно  осуществляется  с помощью
       интерфейса графического устройства (GDI).

            В данном разделе поясняется:

            - описывается процесс рисования в среде Windows.

            - назначение контекста отображения и сообщения WM_PAINT.

            - как использовать функции GDI  для  рисования  в  области
              пользователя окна.

            - как  нарисовать  линии  и произвольные фигуры,  записать
              текст и создать перо или кисть.

            Кроме этого  в  данной  главе  описывается,  как   создать
       простую   прикладную  программу  Output,  которая  иллюстрирует
       использование некоторых из этих концепций.
                                       3.1 Контекст отображения.               

            Контекст отображения определяет устройство вывода, текущие
       средства рисования, цвета и другую информацию, используемую GDI
       для  генерации   вывода.   Дескриптор   контекста   отображения
       необходим  всем  функциям вывода GDI.  Никакой вывод невозможен
       без контекста отображения.

            Для рисования  внутри  окна  необходим  только  дескриптор
       окна.  Этот  дескриптор  используется для получения дескриптора
       контекста отображения области пользователя окна.

            Способ, используемый для получения дескриптора, зависит от
       того,  где планируется выполнить операции вывода. Хотя для этих
       операций можно использовать любую  точку  прикладной  программы
       (включая функцию WinMain),  большинство программ размещают их в
       функции окна.  Хотя функция окна может рисовать внутри  области
       пользователя   в  ответ  на  почти  любое  сообщение,  наиболее
       подходящим моментом  для  этого  является  ответ  на  сообщение
       WM_PAINT.  Windows  посылает это сообщение функции окна,  когда
       корректировки   окна   могут   изменить   содержимое    области
       пользователя.  Поскольку только прикладная программа знает, что
       находится в области пользователя,  Windows  посылает  сообщение
       функции    окна,   чтобы   она   могла   восстановить   область
       пользователя.

            Для генерации сообщения WM_PAINT  необходимо  использовать
       функцию  BeginPaint.  Если  предполагается  рисовать  в области
       пользователя в любой момент времени (не обязательно в ответ  на
       сообщение  WM_PAINT),  нужно  использовать  функцию  GetDC  для
       получения дескриптора контекста отображения.

.
      Windows 3.0/pg/1#3                                        = 61 =

            Необходимо помнить,  что  контекст  передается  прикладной
       программе   только   временно.   Контекст   отображения  -  это
       разделяемый ресурс,  и если  одна  прикладная  программа  имеет
       контекст  отображения,  то  другая  программа не может получить
       его.  Это означает,  что пользователь должен как  можно  скорее
       освободить контекст отображения после того, как использовал его
       для рисования в окне.  Если контекст отображения был получен  с
       помощью  функции GetDC,  то он должен быть освобожден с помощью
       функции  ReleaseDC.  Аналогично,  если  использовалась  функция
       BeginPaint, то нужна функция EndPaint.
                                3.1.1 Использование функции GetDC.             

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

            В приведенном  ниже  примере  показано,  как  использовать
       функцию GetDC для получения дескриптора контекста отображения и
       записать строку "Привет, Windows!" в область пользователя:

            hDC=GetDC(hWnd);
            TextOut(hDC, 10, 10, "Привет, Windows!", 14);
            ReleaseDC(hWnd, hDC);

            В этом   примере   функция   GetDC   возвращает   контекст
       отображения   окна,   идентифицированного  параметром  hWnd,  а
       функция TextOut записывает строку, начиная с позиции (10, 10) в
       области   пользователя   окна.  Функция  ReleaseDC  освобождает
       контекст отображения.

            Все, что нарисовано в области пользователя,  будет стерто,
       как  только  Windows  пошлет  сообщение  WM_PAINT функции окна.
       Причина этого заключается в том, что Windows посылает сообщение
       WM_ERASEBKGND   функции  окна  как  часть  обработки  сообщения
       WM_PAINT.  Если  сообщение  WM_ERASEBKGND  передается   функции
       DefWindowProc,  то  она  заполняет  область пользователя кистью
       фона класса, полностью стирая всю ранее выведенную информацию.
                                       3.1.2 Сообщение WM_PAINT.               

            Windows посылает сообщение WM_PAINT,  когда  в  результате
       действий   пользователя   окно  изменяется.  Например,  Windows
       посылает сообщение WM_PAINT, когда пользователь закрывает окно,
       перекрывающее  часть  другого  окна.  Поскольку  окно разделяет
       экран с другими окнами, то все, что пользователь делает в одном
       окне,  может воздействовать на содержимое и внешний вид другого
       окна.  Однако,  никакие   действия   по   изменению   окна   не
       допускаются, пока программа не получит сообщение WM_PAINT.

.
      Windows 3.0/pg/1#3                                        = 62 =

            Windows посылает  сообщение WM_PAINT,  делая его последним
       сообщением в очереди прикладной программы.  Это  означает,  что
       любая вводимая информация обрабатывается до обработки сообщения
       WM_PAINT.  Функция GetMessage обрабатывает сообщение  WM_PAINT,
       если  в  очереди  нет других сообщений.  Это делается для того,
       чтобы  дать  программе  возможность  выполнить  все   операции,
       которые  могут  воздействовать  на  вид  окна.  Вообще  говоря,
       операции вывода следует выполнять  как  можно  реже  для  того,
       чтобы избежать мерцания и других отвлекающих эффектов.  Windows
       это гарантирует,  удерживая сообщение WM_PAINT до тех пор, пока
       оно не будет последним в очереди.

            В приведенном   ниже   примере  показано,  как  обработать
       сообщение WM_PAINT:

            PAINTSTRUCT ps;
              .
              .
              .
            case WM_PAINT:
                 hDC=BeginPaint(hWnd, &ps);
                 /* операции вывода */
                 EndPaint(hWnd, &ps);
                 break;

            Необходимо использовать  функции  BeginPaint  и  EndPaint.
       Функция   BeginPaint   заполняет   структуру  PAINTSTRUCT  (ps)
       информацией о запросе на рисование, такой как, например, размер
       части области пользователя,  которую необходимо перерисовать, и
       возвращает дескриптор контекста  отображения.  Этот  дескриптор
       может  использоваться  в  любых  функциях  вывода GDI.  Функция
       EndPaint  оканчивает   обработку   запроса   на   рисование   и
       освобождает контекст отображения.

            Вместо функций  BeginPaint  и EndPaint нельзя использовать
       функции  GetDC  и  ReleaseDC.  Функции  BeginPaint  и  EndPaint
       выполняют   специальные  задачи,  такие  как  проверка  области
       пользователя и посылка сообщения  WM_ERASEBKGND,  которые  дают
       уверенность в том, что запрос на рисование обработан правильно.
       Если вместо BeginPaint использовать GetDC,  запрос на рисование
       никогда не будет удовлетворен,  и функция окна будет продолжать
       получать тот же самый запрос на рисование.
                             3.1.3 Перерисовка области пользователя.           

            Windows не  является  единственным  источником   сообщений
       WM_PAINT. Можно также генерировать эти сообщения, используя две
       функции:  InvalidateRect и InvalidateRgn.  Эти функции помечают
       часть   или   всю   область   пользователя  как  нуждающуюся  в
       перерисовке.  Например,  приведенная ниже функция помечает  всю
       область пользователя:

            IvalidateRect(hWnd, NULL, TRUE);
.
      Windows 3.0/pg/1#3                                        = 63 =


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

            Когда область  пользователя  помечается  для  перерисовки,
       Windows посылает сообщение  WM_PAINT.  Если  помечаются  другие
       части  области  пользователя  для перерисовки,  новое сообщение
       WM_PAINT  не  посылается.  Вместо  этого   помеченные   области
       объединяются и обрабатываются одним сообщением WM_PAINT.

            Если намерение     перерисовать    область    пользователя
       изменилось,  можно снять пометку с помощью функций ValidateRect
       и  ValidateRgn.  Эти функции удаляют предыдущие пометки и могут
       удалить сообщение WM_PAINT,  если помеченных областей больше не
       остается.

            Если нет  желания  ждать,  пока  сообщение  WM_PAINT будет
       взято  из  очереди  прикладной  программы,  можно   форсировать
       обработку этого сообщения, используя функцию UpdateWindow. Если
       существует  помеченная  часть  области  пользователя,   функция
       UpdateWindow  берет  сообщение  WM_PAINT  для  данного  окна из
       очереди и посылает его непосредственно функции окна.
                                                                               
             3.1.4 Контекст отображения и контекст устройства.

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

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

            Можно модифицировать эту систему координат,  изменив режим
       отображения  и  начало  координат  экрана.  Режим   отображения
       определяет  единицы  системы  координат.  Режим  по умолчанию -
       MM_TEXT   или   один   пиксель   на   единицу.   Можно    также
.
      Windows 3.0/pg/1#3                                        = 64 =

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

            Для простоты  примеры,  приведенные  в  данном  разделе  и
       руководстве, используют систему координат по умолчанию.
                    3.2 Создание, выборка и удаление средств рисования.        

            GDI дает возможность использовать в окне ряд  средств  для
       рисования.  GDI предоставляет перья для рисования линий,  кисти
       для заливки внутренних областей и  шрифты  для  записи  текста.
       Чтобы  использовать  эти  средства,  надо  их создать с помощью
       функций CreatePen и  CreateSolidBrush  и  затем  выбрать  их  в
       контексте отображения,  использовав функцию SelectObject. После
       применения средств рисования их можно удалить с помощью функции
       DeleteObject.

             Можно создать   перо  для  рисования  линий  и  окантовок,
       используя функцию  CreatePen.  Функция  возвращает   дескриптор
       пера,  имеющего  указанный  тип,  ширину  и цвет.  (Не забудьте
       проверить  возвращаемое  функцией  CreatePen  значение,   чтобы
       убедиться, что вы получили допустимый дескриптор.)

            В приведенном  ниже  примере  создается  пунктирное черное
       перо шириной в один пиксель:

            HPEN hDashPen;
              .
              .
              .
            hDashPen=CreatePen(PS_DASH, 1, RGB(0, 0, 0));
            if(hDashPen)     /* проверка допустимости дескриптора */
              .
              .
              .

            Служебная команда   RGB   создает   32-битовое   значение,
       указывающее  красное,  зеленое  и синее цветовые значения.  Три
       аргумента специфицируют интенсивность цветов -  соответственно,
       красного,  зеленого и синего.  В данном примере все цвета имеют
       нулевую интенсивность, так что указан черный цвет.

            Можно создать сплошную  кисть  для  рисования  и  заливки,
       используя  функцию  CreateSolidBrush.  Эта  функция  возвращает
       дескриптор  кисти  специфицированного  сплошного   цвета.   (Не
       забудьте   проверить   возвращаемое  функцией  CreateSolidBrush
       значение,  чтобы  убедиться,   что   вы   получили   допустимый
       дескриптор.)

            В приведенном  ниже примере показано,  как создать красную
.
      Windows 3.0/pg/1#3                                        = 65 =

       кисть:

            HBRUSH hRedBrush
              .
              .
              .
            hRedBrush=CreateSolidBrush(RGB(255, 0, 0));
            if(hRedBrush)   /* проверка допустимости дескриптора */
              .
              .
              .

            Как только средство рисования создано, его можно выбрать в
       контексте   отображения   с  помощью  функции  SelectObject.  В
       приведенном  ниже  примере   выбирается   красная   кисть   для
       рисования:

            HBRUSH hOldBrush;
               .
               .
               .
            hOldBrush=SelectObject(hDC, hRedBrush);

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

            Не следует создавать или выбирать средство рисования перед
       использованием   контекста  отображения.  Windows  обеспечивает
       средства рисования по умолчанию  своим  собственным  контекстом
       отображения; к  ним  относятся:  черное  перо,  белая  кисть  и
       системный шрифт.

            Можно удалить объекты рисования, если они больше не нужны,
       используя функцию  DeleteObject.  В  приведенном  ниже  примере
       удаляется кисть, идентифицированная дескриптором hRedBrush:

            DeleteObject(hRedBrush);

            Не следует удалять выбранное средство рисования.  Но  если
       это необходимо,  то можно использовать функцию SelectObject для
       восстановления предыдущего средства рисования и  потом  удалить
       ненужные средства, как показано ниже:

            SelectObject(hDC, hOldBrush);
            DeleteObject(hRedBrush);

            Поскольку работа  со  шрифтами  -  довольно  специфический
       процесс,  полное  описание  процесса  создания и выборки шрифта
       приводится в главе 18, "Шрифты".

.
      Windows 3.0/pg/1#3                                        = 66 =

                                    3.3 Рисование и вывод текста.              

            GDI обеспечивает  широкий  спектр   операций   вывода   от
       рисования   линий   до  записи  текста.  В  самом  деле,  можно
       использовать функции  LineTo,  Rectangle,  Ellipse,  Arc,  Pie,
       TextOut   и  DrawText  для  рисования  линий,  прямоугольников,
       окружностей,  дуг, секторов круговых диаграмм и текста. Во всех
       случаях функции используют выбранное перо и кисть для рисования
       окантовок и заливки  внутренних  областей,  а  также  выбранные
       шрифты для записи текста.

            Линии рисуются  с  использованием  функции LineTo.  Обычно
       функции MoveTo и LineTo используются  совместно  для  рисования
       линий.  В приведенном ниже примере рисуется линия от точки (10,
       90) до точки (360, 90):

            MoveTo(hDC, 10, 90);
            LineTo(hDC, 360, 90);

            Прямоугольник рисуется  с  помощью функции Rectangle.  Эта
       функция использует выбранное перо  для  рисования  окантовки  и
       выбранную  кисть для заливки внутренней области.  В приведенном
       ниже примере рисуется прямоугольник, координаты верхнего левого
       и нижнего правого углов которого,  соответственно, - точки (10,
       30) и (60, 80):

            Rectangle (hDC, 10, 30, 60, 80);

            Эллипс или окружность рисуются с помощью функции  Ellipse.
       Функция  использует  выбранное  перо  для рисования окантовки и
       выбранную кисть для заливки внутренней области.  В  приведенном
       ниже     примере    рисуется    эллипс,    который    ограничен
       прямоугольником, определенным точками (160, 30) и (210, 80):

            Ellipse (hDC, 160, 30, 210, 80);

            Дуги рисуются с помощью  функции  Arc.  Дуга  определяется
       окружностью  и точками начала и конца дуги.  В приведенном ниже
       примере показано, как нарисовать дугу, начиная с точки (10, 90)
       и  кончая точкой (360,  90).  Дуга рисуется от точки (10,90) до
       точки (360,90):

            Arc (hDC, 10, 90, 360, 120, 10, 90, 360, 90);

            Сектор круговой  диаграммы   рисуется   с   использованием
       функции  Pie.  Этот  сектор  состоит  из  дуги и двух радиусов,
       идущих  от  центра  окружности  к  концам  дуги.  Функция   Pie
       использует  выбранное  перо для рисования окантовки и выбранную
       кисть  для  заливки  внутренней  области.  В  приведенном  ниже
       примере   рисуется   сектор  круговой  диаграммы,  ограниченный
       прямоугольником,  который специфицирован точками  (310,  30)  и
       (360, 80) и который начинается и заканчивается, соответственно,
       в точках (360, 30) и (360, 80):

.
      Windows 3.0/pg/1#3                                        = 67 =

            Pie (hDC, 310, 30, 360, 80, 360, 30, 360, 80);

            Текст индицируется при  помощи  функции  TextOut.  Функция
       индицирует   строку,  начиная  со  специфицированной  точки.  В
       приведенном ниже примере индицируется строка  "Пример  строки",
       начиная с точки (1, 1):

            TextOut(hDC, 1, 1, "Пример строки", 13);

            Можно также    индицировать   текст,   используя   функцию
       DrawText.  Эта функция аналогична TextOut за исключением  того,
       что  она  позволяет  записывать  текст  в  несколько  строк.  В
       приведенном   ниже   примере   строка   "Эта   длинная   строка
       иллюстрирует работу функции DrawText" индицируется в нескольких
       строках специфицированного прямоугольника:

            RECT rcTextBox;
            PSTR lpText="Эта длинная строка иллюстрирует работу функции
                   DrawText";
            .
            .
            .
            SetRect(&rcTextBox, 1, 10, 160, 40);
            DrawText(hDC, lpText, strlen(pText), &rcTextBox, DT_LEFT);

            В этом  примере  строка,  на  которую  указывает  параметр
       lpText,  индицируется в одну или  несколько  выравненных  влево
       строк  в прямоугольнике,  определенном точками (1,  10) и (160,
       40).

            Хотя вы можете создавать и  отображать  в  окне  растровые
       карты,  в  данной  главе этот процесс не описывается.  Смотрите
       главу 11, "Растровые карты".

                             3.4 Пример прикладной программы Output.           

            Эта прикладная   программа  показывает,  как  использовать
       сообщение WM_PAINT для рисования внутри области пользователя, а
       также как создать и использовать средства рисования. Прикладная
       программа Output - это  просто  расширение  программы  Generic,
       описанной   в   предыдущем  разделе.  Для  создания  прикладной
       программы  Output  скопируйте  и  переименуйте  исходные  файлы
       программы Generic, а затем сделайте следующие изменения:

            1) добавьте новые переменные;

            2) модифицируйте фрагмент WM_CREATE;

            3) добавьте фрагмент WM_PAINT;

            4) модифицируйте фрагмент WM_DESTROY;

.
      Windows 3.0/pg/1#3                                        = 68 =

            5) оттранслируйте и скомпонуйте программу.

            Вы можете  взять  исходные  тексты этой программы с диска,
       поставляемого с SDK: "SDK Sample Source Code Disk".

            Для этого примера необходим цветной дисплей. Если его нет,
       GDI   будет   моделировать   некоторые   из   выводимых  цветов
       квантованием.  Квантование - это метод моделирования  цвета  из
       двух доступных цветов.  На цветных мониторах,  которые не могут
       отображать оранжевый цвет,  Windows моделирует его,  комбинируя
       красные  и  желтые  пиксели.  На  черно-белых мониторах Windows
       моделирует цвета,  используя черные и белые цвета  и  различные
       степени серого.

            Вместо того, чтобы вводить тексты, приведенные в следующих
       разделах, вам возможно будет удобнее просто переписать исходные
       тексты из SDK.
                                                                               
                    3.4.1 Добавление новых переменных.

            Для данного  примера необходимы несколько новых глобальных
       переменных.  Добавьте  приведенные  ниже  переменные  в  начало
       исходного С-файла:

            HPEN hDashPen;       /* дескриптор пера "---"     */
            HPEN hDotPen;        /* дескриптор пера "..."     */
            HBRUSH hOldBrush;    /* дескриптор старой кисти   */
            HBRUSH hRedBrush;    /* дескриптор красной кисти  */
            HBRUSH hGreenBrush;  /* дескриптор зеленой кисти  */
            HBRUSH hBlueBrush;   /* дескриптор синей кисти    */

            Также необходимы  новые  локальные  переменные  в  функции
       окна. Объявите в начале функции MainWndProc:

            HDC hDC;        /* переменный контекст отображения */
            PAINTSTRACT ps; /* структура рисования */
            RECT rcTextBox; /* приямоугольная рамка для текста */
            HPEN hOldPen;   /* дескриптор старого пера */
                             3.4.2 Модификация фрагмента WM_CREATE.            

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

       case WM_CREATE:

            /* создать кисти */

            hRedBrush   =  CreateSolidBrush(RGB(255,  0,  0)
.
      Windows 3.0/pg/1#3                                        = 69 =

            hGreenBrush =  CreateSolidBrush(RGB(  0,255,  0)
            hBlueBrush  =  CreateSolidBrush(RGB(  0,  0,255)

            /* создание пера "---" */

            hDashPen = CreatePen(PS_DASH,             /* тип     */
                1,                                    /* толщина */
                RGB(0, 0, 0));                        /* цвет    */

            /* сорздание пера "..." */

            hDotPen = CreatePen(PS_DOTT,              /* тип     */
                1,                                    /* толщина */
                RGB(0, 0, 0));                        /* цвет    */

            Функции CreateSolidBrush  создают сплошные кисти,  которые
       должны быть использованы для заливки прямоугольника,  эллипса и
       окружности  в  программе  Output в ответ на получение сообщения
       WM_PAINT.    Функции    CreatePen    создают    пунктирную    и
       штрих-пунктирную линии, используемые для рисования окантовки.
                               3.4.3 Добавление фрагмента WM_PAINT.            

            Сообщение WM_PAINT  информирует вашу программу о том,  что
       необходима перерисовка всей или части области пользователя. Для
       обработки этого сообщения добавьте следующий фрагмент к функции
       окна:

            case WM_PAINT:
                {
                TEXTMETRIC textmetric;
                int nDrawX;
                int nDrawY;
                char szText[300];

                /* Получить контекст отображения для начала рисования */

                hDC = BeginPaint(hWnd, &ps);

                /* Получить размер текущего шрифта. Эта информация ис- */
                /* пользуется для определения промежутков между строка- */
                /* ми на экране. */

                GetTextMetrics(hDC,&textmetric);

                /* Определить позицию вывода в 1/4 дюйма от верхней гра- */
                /* ницы окна и от левого края верхнего левого угла об- */
                /* ласти пользователя окна */

                nDrawX = GetDeviceCaps (hDC, LOGPIXELSX) / 4;   /* 1/4 inch */
                nDrawY = GetDeviceCaps (hDC, LOGPIXELSY) / 4;   /* 1/4 inch */

                /* Вывести символы на экран. После вывода каждой строки */
.
      Windows 3.0/pg/1#3                                        = 70 =

                /* текста увеличивается вертикальная позиция точки вы- */
                /* вода. Расстояние (в пикселях) между верхней точкой */
                /* каждой строки равно стандартной высоте символа шрифта */
                /* (tmHeight) плюс стандартное расстояние между стро- */
                /* ками (tmExternaleading). */

                strcpy (szText, "These characters are being painted using ");
                TextOut (hDC, nDrawX, nDrawY, szText, strlen (szText));
                nDrawY += textmetric.tmExternalLeading + textmetric.tmHeight;

                strcpy (szText, "the TextOut() function, which is fast and ");
                TextOut (hDC, nDrawX, nDrawY, szText, strlen (szText));
                nDrawY += textmetric.tmExternalLeading + textmetric.tmHeight;

                strcpy (szText, "allows programmer control of placement and ")      ;
                TextOut (hDC, nDrawX, nDrawY, szText, strlen (szText));
                nDrawY += textmetric.tmExternalLeading + textmetric.tmHeight;

                strcpy (szText, "formatting details.  However, TextOut() ");
                TextOut (hDC, nDrawX, nDrawY, szText, strlen (szText));
                nDrawY += textmetric.tmExternalLeading + textmetric.tmHeight;

                strcpy (szText, "does not provide any automatic formatting.");
                TextOut (hDC, nDrawX, nDrawY, szText, strlen (szText));
                nDrawY += textmetric.tmExternalLeading + textmetric.tmHeight;

                /* Вывести текст в прямоугольник размером 5 на 1 дюйм. */
                /* В начале определим прямоугольник */

                nDrawY += GetDeviceCaps (hDC, LOGPIXELSY) / 4;  /* 1/4 inch */
                SetRect (
                      &rcTextBox
                    , nDrawX
                    , nDrawY
                    , nDrawX + (5 * GetDeviceCaps (hDC, LOGPIXELSX)) /* 5" */
                    , nDrawY + (1 * GetDeviceCaps (hDC, LOGPIXELSY)) /* 1" */
                );

                /* Вывести текст в границах этого прямоугольника */

                strcpy (szText, "This text is being displayed with a single "
                            "call to DrawText().  DrawText() isn't as fast "
                            "as TextOut(), and it is somewhat more "
                            "constrained, but it provides numerous optional "
                            "formatting features, such as the centering and "
                            "line breaking used in this example.");
                DrawText (
                      hDC
                    , szText
                    , strlen (szText)
                    , &rcTextBox
                    , DT_CENTER | DT_EXTERNALLEADING | DT_NOCLIP
                                                | DT_NOPREFIX | DT_WORDBREAK
.
      Windows 3.0/pg/1#3                                        = 71 =

                );

                /* Вывести следующие объекты сразу же под прямоуголь- */
                /* ником с текстом. */

                nDrawY = rcTextBox.bottom;

                /* Координаты объектов должны лежать ниже и правее, */
                /* чем текущие координаты (nDrawx,nDrawy). */

                /* Нарисовать красный прямоугольник */

                hOldBrush = SelectObject(hDC, hRedBrush);
                Rectangle (
                      hDC
                    , nDrawX
                    , nDrawY
                    , nDrawX + 50
                    , nDrawY + 30
                );

                /* Нарисовать зеленый эллипс */

                SelectObject(hDC, hGreenBrush);
                Ellipse (
                      hDC
                    , nDrawX + 150
                    , nDrawY
                    , nDrawX + 150 + 50
                    , nDrawY + 30
                );

                /* Нарисовать синий сектор круговой диаграммы */

                SelectObject(hDC, hBlueBrush);
                Pie (
                      hDC
                    , nDrawX + 300
                    , nDrawY
                    , nDrawX + 300 + 50
                    , nDrawY + 50
                    , nDrawX + 300 + 50
                    , nDrawY
                    , nDrawX + 300 + 50
                    , nDrawY + 50
                );

                nDrawY += 50;

                /* Восстановить старую кисть */

                SelectObject(hDC, hOldBrush);

.
      Windows 3.0/pg/1#3                                        = 72 =

                /* Выбрать "- -" перо, сохранить старое значение */

                nDrawY += GetDeviceCaps (hDC, LOGPIXELSY) / 4;  /* 1/4 inch */
                hOldPen = SelectObject(hDC, hDashPen);

                /* Перейти в указанную точку */

                MoveTo(hDC, nDrawX, nDrawY);

                /* Нарисовать линию */

                LineTo(hDC, nDrawX + 350, nDrawY);

                /* Выбрать "..." перо, сохранить старое значение */

                SelectObject(hDC, hDotPen);

                /* Нарисовать дугу, соединяющую концы линии */

                Arc (
                      hDC
                    , nDrawX
                    , nDrawY - 20
                    , nDrawX + 350
                    , nDrawY + 20
                    , nDrawX
                    , nDrawY
                    , nDrawX + 350
                    , nDrawY
                );

                /* Восстановить старое перо */

                SelectObject(hDC, hOldPen);

                /* Сообщить Windows о завершении рисования */

                EndPaint(hWnd, &ps);
                }
            break;
                                                                               
                  3.4.4 Модификация фрагмента WM_DESTROY.

            Перед завершением  программы  Output  необходимо   удалить
       средства рисования,  созданные для окна Output, для того, чтобы
       освободить  память,  занимаемую  этими  средствами.  Это  можно
       сделать   с   помощью  функции  DeleteObject,  которая  удаляет
       различные перья и кисти в фрагменте  WM_DESTROY.  Модифицируйте
       этот фрагмент так, чтобы он имел следующий вид:

            case WM_DESTROY:

               DeleteObject(hRedBrush);
.
      Windows 3.0/pg/1#3                                        = 73 =

               DeleteObject(hGreenBrush);
               DeleteObject(hBlueBrush);
               DeleteObject(hDashPen);
               DeleteObject(hDotPen);
               PostQuitMessage(0);
               break;

            Для каждого   удаляемого   объекта  необходим  один  вызов
       функции DeleteObject.
                                                                               
                      3.4.5 Трансляция и компоновка.

            Для перетрансляции и перекомпоновки  программы  Output  не
       требуется  вносить  какие-либо  изменения  в  файл make.  После
       трансляции  и  компоновки  запустите   Windows   и   прикладную
       программу.   Прикладная  программа  будет  выглядеть  так,  как
       показано на рис. 3.1

            Рисунок 3.1  Окно программы Output.

            Для экспериментирования с различными функциями  GDI  можно
       использовать фрагмент WM_PAINT данной программы.  Информация по
       другим  функциям  GDI  приведена  в  первом  томе   Справочного
       Руководства.
                                               3.5 Заключение.                 

            В данной   главе  описывается  как  интерфейс  графических
       устройств (GDI) Windows обрабатывает вывод в окно.  Для  вывода
       GDI используют "контекст устройства". Контекст устройства - это
       структура данных,  поддерживаемая GDI,  которая содержит данные
       об используемом вами устройстве вывода.

            GDI позволяет вам использовать различные средства вывода в
       окно.

            Дополнительную информацию,  относительно вывода вы найдете
       в:

       Раздел               Руководство
       ---------------------------------------------------------------
       Работа с растровыми  Руководство программиста, глава 11, "Раст-
       картами              ровые карты"

                            "Tools": Глава 4, "Создание образов:
                            SDKPaint"

       Работа со шрифтами   Руководство программиста, глава 18, "Шриф-
                            ты"

                            "Tools": Глава 6, "Создание шрифтов:
                            Font Editor"

.
      Windows 3.0/pg/1#3                                        = 74 =

       Функции окна и соб-  Справочное руководство, том 1, глава 1,
       ственный контекст    "Функции интерфейса с устройством управ-
       устройства           ления окнами"

       Функции вывода       Справочное руководство, том 1, глава 2,
                            "Функции интерфейса графических устройств",
                            глава 4, "Список функций".

       Сообщение WM_PAINT   Справочное руководство, том 1, глава 6,
       WM_CREATE,           "Список сообщений"
       WM_DESTROY

       Типы данных и струк- Справочное руководство, том 2, глава 7,
       туры                 "Типы и структуры данных"



.
      Windows 3.0/pg/1#3                                        = 75 =

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

            В данной главе описываются следующие разделы:

            - Сообщения ввода,  посылаемые  Windows  вашей  прикладной
              программе.

            - Реакция  на сообщения ввода,  переданные вашей программе
              Windows.

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

             При любом  нажатии клавиши,  перемещении мыши или нажатии
       клавиши  мыши,  Windows  посылает  соответствующей   прикладной
       программе сообщения   ввода.   Кроме  этого,  Windows  посылает
       сообщения ввода в ответ на ввод от таймера.

            Поддерживаются следующие типы сообщений ввода:

            Сообщение        Описание
            ----------------------------------------------------------
            Клавиатура       Ввод с клавиатуры.

            Символ           Ввод с клавиатуры, оттранслированный
                             в коды символов.

            Мышь             Ввод информации с помощью мыши.

            Меню             Ввод информации  с помощью меню окна
                             и мыши.

            Строка прокрутки Ввод  с  помощью строки прокрутки окна и
                             мыши.

            Таймер           Ввод от системного таймера.
            ----------------------------------------------------------

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

            Сообщения о вводе символа,  от меню или  строки  прокрутки
       создаются  в  ответ  на  действия с клавиатурой или "мышью" вне
.
      Windows 3.0/pg/1#3                                        = 76 =

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

            Сообщения ввода имеют два формата в зависимости  от  того,
       как прикладная программа получает эти сообщения:

            - Те сообщения,  которые Windows помещает в очередь, имеют
              структуру MSG.

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

            - Второй  формат  сообщения  ввода,  передаваемый  функции
              окна,  содержит 4 аргумента,  соответствующие параметрам
              hWnd, wParam, lParam и самому сообщению.

            Единственное отличие заключается в том,  что структура MSG
       включает поле для указания положения мыши и системного  времени
       при генерации  сообщения.  Windows  не  посылает эту инофрмацию
       функции окна.
                                        4.1.2 Ввод с клавиатуры.               

            Большую часть информации пользователь вводит с клавиатуры.
       Когда  пользователь  нажимает  или  отпускает клавишу,  Windows
       посылает  в  программу  сообщение  ввода  с  клавиатуры.   Ниже
       приводится перечень сообщений ввода с клавиатуры и события,  их
       вызывающие:

            Сообщение       Событие
            ----------------------------------------------------------
            WM_KEYDOWN      Пользователь нажал клавишу;

            WM_KEYUP        Пользователь отпустил клавишу;

            WM_SYSKEYDOWN   Пользователь нажал системную клавишу;

            WM_SYSKEYUP     Пользователь отпустил системную клавишу.
            ----------------------------------------------------------

            Параметр wParam определяет виртуальный код данной клавиши.
       Виртуальный  код  клавиши  -  это  независимое  от   устройства
       значение  клавиши.  Windows  использует виртуальные коды клавиш
       для того, чтобы не зависить от используемой персональной ЭВМ.

            Параметр lParam  содержит  фактический   код   клавиши   и
       дополнительную  информацию  о  клавиатуре такую,  как состояние
       клавиши Shift, и была ли нажата текущая клавиша.
.
      Windows 3.0/pg/1#3                                        = 77 =


            Для системных клавиш  Windows  генерирует  соответствующие
       сообщения WM_SYSKEYUP и WM_SYSKEYDOWN.  Это специальные клавиши
       такие,  например, как Alt и F10, которые принадлежат интерфейсу
       пользователя  и  не  могут использоваться прикладной программой
       другим способом.

            Прикладная программа получает сообщения клавиатуры  только
       тогда,   когда   она   захватила   ввод.  Прикладная  программа
       захватывает ввод,  когда она становится  активной,  т.е.  когда
       пользователь  выбрал  окно программы.  Можно также использовать
       функцию SetFocus для явного указания  на  захват  данным  окном
       ввода  и  функцию  GetFocus  для  определения того,  какое окно
       захватило ввод.
                                                                               
                            4.1.3 Ввод символа.

            Прикладная программа,  которая читает символы,  вводимые с
       клавиатуры,  должна  использовать  функцию  TranslateMessage  в
       своем  цикле  обработки  сообщений.  Эта  функция   преобразует
       сообщение  ввода с клавиатуры в соответствующее сообщение ввода
       символа в коде ANSI - WM_CHAR  или  WM_SYSCHAR.  Эти  сообщения
       содержат  ANSI-коды  символа  для  данной  клавиши  в параметре
       wParam. Параметр lParam аналогичен таковому в сообщении ввода с
       клавиатуры.
                                      4.1.4 Ввод с помощью мыши.               

            При вводе  с  помощью  "мыши"  Windows посылает прикладной
       программе сообщение от "мыши",  когда  пользователь  перемещает
       курсор "мыши" (указатель) в/через окно или нажимает/освобождает
       кнопку "мыши",  находясь в окне.  В табл. 3 приводится перечень
       сообщений от "мыши" и события, их вызывающие.

            Сообщение        Описание
            ----------------------------------------------------------
            WM_MOUSEMOVE     Пользователь перемещает курсор мыши
                             в/через окно.

            WM_LBUTTONDOWN   Пользователь нажимает левую кнопку.

            WM_LBUTTONUP     Пользователь отпускает левую кнопку.

            WM_LBUTTONDBLCLK Пользователь  нажимает,  отпускает  и
                             вновь нажимает левую кнопку (в рамках
                             отпущенного системой времени).

            WM_MBUTTONDOWN   Пользователь нажимает среднюю кнопку.

            WM_MBUTTONUP     Пользователь отпускает среднюю кнопку.

            WM_MBUTTONDBLCLK Пользователь  нажимает,  отпускает  и
                             вновь нажимает среднюю кнопку(в рамках
.
      Windows 3.0/pg/1#3                                        = 78 =

                             отпущенного системой времени).

            WM_RBUTTONDOWN   Пользователь нажимает правую кнопку.

            WM_RBUTTONUP     Пользователь отпускает правую кнопку.

            WM_RBUTTONDBLCLK Пользователь  нажимает,  отпускает  и
                             вновь  нажимает правую кнопку (в рам-
                             ках отпущенного системой времени).
            ----------------------------------------------------------

            Параметр wParam   каждой   кнопки   включает   маску  бит,
       определяющую текущее состояние клавиатуры и кнопок мыши  такое,
       например, как  нажаты  ли кнопки мыши,  клавиша Shift и клавиша
       Ctrl. Параметр lParam содержит координаты x и y курсора мыши.

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

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

            Windows посылает функции окна сообщение о двойном  нажатии
       на кнопку мыши только в том случае, когда соответствующий класс
       окна имеет тип CS_DBLCLKS.  Этот тип необходимо установить  при
       регистрации класса окна. Сообщение о двойном нажатии на клавишу
       всегда является третьим по счету в серии из четырех  сообщений.
       Первые  два сообщения - о первом нажатии и освобождении кнопки.
       Последнее сообщение - это второе освобождение кнопки. Напомним,
       что сообщение о двойном нажатии фиксируется только тогда, когда
       первое и  второе  нажатия  произошли  в  рамках  установленного
       системой  временного  интервала.  Можно  узнать  этот интервал,
       использовав  функцию  GetDoubleClickTime.  Временной   интервал
       можно  установить с помощью функции SetDoubleClickTime,  однако
       надо помнить,  что временной интервал устанавливается для  всех
       прикладных программ.
                                         4.1.5 Ввод от таймера.                

            Windows посылает  сообщение  ввода  от  таймера прикладной
       программе  каждый  раз,  когда  установленное  для  него  время
       исчерпано. Для получения такого сообщения необходимо установить
       значение таймера с помощью функции SetTimer.
.
      Windows 3.0/pg/1#3                                        = 79 =


            Информация от таймера поступает двумя способами:

            - в  виде  сообщения  WM_TIMER  через  очередь  прикладной
              программы.

            - от  функции  многократного вызова,  которая определяется
              при вызове функции SetTimer.

            Ниже показано,  как установить ввод от таймера,  используя
       сообщение WM_TIMER, на пятисекундный интервал:

            idTimer = SetTimer(hWnd, 1, 5000, (FARPROC) NULL);

            В примере  интервал  таймера  устанавливается  равным 5000
       миллисекунд.  Это  означает,  что  таймер  будет   генерировать
       сообщение каждые  5 сек.  Второй аргумент,  если он не равен 0,
       используется  вашей  программой  для   идентификации   таймера.
       Последний   аргумент   равный   NULL   означает,   что  функция
       многократного   вызова   для   обработки   ввода   от   таймера
       отсутствует,  так  что Windows посылает сообщение ввода таймера
       через очередь прикладной программы.

            Функция SetTimer  возвращает  уникальное  целое,   которое
       идентифицирует   таймер.   Этот   же  самый  ID  таймера  можно
       использовать в функции KillTimer для его отключения.
                                   4.1.6 Ввод из строки прокрутки.             

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

            Для того, чтобы получить указанную возможность, необходимо
       сформировать  строки  прокрутки в окне.  Для этого при создании
       окна  необходимо  определить  его  тип   как   WS_HSCROLL   или
       WS_VSCROLL.   Это   заставит   функцию   CreateWindow   создать
       горизонтальную и вертикальную строку  прокрутки  в  окне.  Ниже
       приводится соответствующий пример:

       hWnd = CreatWindow("Input",     /* класс окна */
           "Пример программы Input",   /* имя окна               */
            WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
            CW_USERDEFAULT,            /* позиция по оси x       */
            CW_USERDEFAULT,            /* позиция по оси y       */
.
      Windows 3.0/pg/1#3                                        = 80 =

            CW_USERDEFAULT,            /* ширина                 */
            CW_USERDEFAULT,            /* высота                 */
            NULL,                      /* ID меню или дочернего
                                          окна                   */
            NULL,                      /* дескриптор родительского
                                          окна                   */
            hInstance,                 /* экземпляр              */
            NULL);                     /* дополнительная информа-
                                          ция                    */

            Windows индицирует строки прокрутки при отображении  окна.
       Система  автоматически  управляет строками прокрутки и посылает
       сообщения строк прокрутки функции окна при перемещении  бегунка
       на строке прокрутки.

            При посылке  сообщения строки прокрутки Windows помещает в
       wParam значение,  определяющее тип  прокрутки.  Например,  если
       пользователь   нажимает   кнопку,  находясь  на  стрелке  вверх
       вертикальной строки прокрутки,  ПОЛИФЕЙС устанавливает параметр
       wParam в значение SB_LINEUP.  В зависимости от собылия, Windows
       заносит в wParam следующие значения:

            Тип прокрутки    Описание
            ----------------------------------------------------------
            SB_LINEUP        Пользователь нажимает кнопку, находясь
                             на левой или верхней стрелке.

            SB_LINEDOWN      Пользователь нажимает кнопку, находясь
                             на нижней или правой стрелке.

            SB_PAGEUP        Пользователь нажимает кнопку, находясь
                             между панелью прокрутки и верхней или
                             левой стрелкой.

            SB_PAGEDOWN      Пользователь нажимает кнопку, находясь
                             между панелью  прокрутки и нижней  или
                             правой стрелкой.

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

            SB_THUMBTRACK    Пользователь перемещает панель прокрут-
                             ки с помощью мыши.
            ----------------------------------------------------------
                                                                               
                            4.1.7 Ввод из меню.

            При выборе  пользователем  элемента  меню Windows посылает
       окну сообщения ввода из меню.

            Имеются два типа таких сообщений:
.
      Windows 3.0/pg/1#3                                        = 81 =


            - WM_COMMAND,  которое указывает,  что пользователь выбрал
              команду из меню окна прикладной программы.

            - WM_SYSCOMMAND,  которое  указывает,   что   пользователь
              выбрал   команду из системного меню.

            Поскольку ввод  из меню часто является основным источником
       ввода для прикладных  программ,  и  его  обработка  может  быть
       достаточно сложна,  она  описана  подробно  в главе 7,  "Меню",
       данного руководства.
                             4.2 Пример прикладной программы Input.            

            Эта прикладная   программа  иллюстрирует,  как  обработать
       сообщения ввода с клавиатуры,  мыши, таймера и строк прокрутки.
       Прикладная  программа  Input  индицирует  текущее или последнее
       состояние  каждого  из  указанных   устройств.   Для   создания
       прикладной  программы  Input скопируйте и переименуйте исходные
       файлы прикладной программы Generic,  а затем сделайте следующие
       модификации:

             1) добавьте новые переменные;

             2) установите тип класса окна;

             3) модифицируйте функцию CreateWindow;

             4) определите прямоугольник для текста;

             5) добавьте фрагмент WM_CREATE;

             6) измените фрагмент WM_DESTROY;

             7) добавьте фрагменты WM_KEYUP и WM_KEYDOWN;

             8) добавьте фрагмент WM_CHAR;

             9) добавьте фрагмент WM_MOUSEMOVE;

             10) добавьте фрагменты WM_LBUTTONUP и WM_RBUTTONUP;

             11) добавьте фрагмент WM_LBUTTONDBLCLK;

             12) добавьте фрагмент WM_TIMER;

             13) добавьте фрагменты WM_HSCROLL и WM_VSCROLL;

             14) добавьте фрагмент WM_PAINT;

             15) оттранслируйте и скомпонуйте.

            Хотя Windows и не требует устройства манипулирования,  для
.
      Windows 3.0/pg/1#3                                        = 82 =

       данного примера необходима мышь или другое подобное устройство.
       В противном  случае  программа  не  получит  сообщений ввода от
       мыши.

             Примечание: Вместо   того,    чтобы    вводить    тексты,
       приведенные в следующих разделах,  возможно,  вам будет удобнее
       просто переписать исходные тексты из SDK.

                        4.2.1 Как программа Input осуществляет вывод.          

            Программа Input  в ответ на сообщения ввода выводит текст,
       который  определяет  тип  сообщения   ввода.   Для   вывода   и
       форматирования текста она использует простые функции.

            Для создания  отформатированной строки используйте функцию
       wsprintf,  которая является версией функции исполняющей системы
       С  sprintf  для  Windows.  Функция  Windows  wsprintf  копирует
       отформатированную строку в  буфер.  Вы  затем  можете  передать
       адрес буфера функции TextOut.  В программах, использующих малую
       модель  памяти,  как  все  программы  из  данного  руководства,
       необходимо   использовать  функцию  wsprintf  с  осторожностью:
       передаваемый ей буфер должен быть определен в  сегменте  данных
       или стека программы.  Ниже приведен пример,  показывающий,  как
       создать отформатированную строку:

            char MouseText[48];
                .
                .
                .
            wsprintf(MouseText, "WM_MOUSEMOVE: %x, %d, %d", wParam,
                LOWORD (lParam), HIWORD(lParam));

            В данном  примере  отформатированная  строка  копируется в
       массив MouseText.  Массив объявлен как локальная переменная,  и
       таким образом он может быть передан функции wsprintf.
                                4.2.2 Добавление новых переменных.             

            Необходимо иметь несколько новых глобальных переменных. Их
       нужно объявить в начале исходного С-файла:

       char MouseText[48];            /* состояние мыши          */
       char ButtonText[48];           /* состояние кнопки мыши  */
       char KeyboardText[48];         /* состояние клавиатуры    */
       char CharacterText[48];        /* последний символ        */
       char ScroolText[48];           /* состояние прокрутки     */
       char TimerText[48];            /* состояние таймера       */
       RECT rectMouse;
       RECT rectButton;
       RECT rectKeyboard;
       RECT rectCharacter;
       RECT rectScroll;
.
      Windows 3.0/pg/1#3                                        = 83 =

       RECT rectTimer;
       int IdTimer;                   /* ID таймера              */
       int nTimerCount = 0;           /* текущий счетчик таймера */

            Cимвольные массивы   содержат  строки,  которые  описывают
       текущее состояние клавиатуры,  мыши и  таймера.  Прямоугольники
       определяют  положение строк на экране;  они используют технику,
       которая  описана  в  разделе  4.2.15,   "Добавление   фрагмента
       WM_PAINT".

            Необходимы также   некоторые   локальные   переменные  для
       функции окна.  В начале функции окна  надо  объявить  следующие
       переменные:

            HDC hDC;         /* переменная контекста отображения */
            PAINTSTRUCT ps;  /* структура отображения            */
            char HorzOrVertText[12];
            char ScrollTypeText[20];
            RECT rect;

            Необходимо также  добавить  следующие переменные к функции
       InitInstance:

            HDC             hDC;
            TEXTMETRIC      textmetric;
            RECT            rect;
            int             nLineHeight;
                                                                               
                     4.2.3 Установка типа класса окна.

            Необходимо установить   тип  класса  окна  CS_DBLCLKS  для
       возможности обработки двойного нажатия на кнопку.  Найдем  этот
       оператор в функции инициализации:

            wc.style=NULL;

            Изменим его следующим образом:

            wc.style=CS_DBLCLKS;

            Это дает   возможность  обрабатывать  двойное  нажатие  на
       кнопку при работе с окнами, прнадлежащими данному классу.
                                                                               
                  4.2.4 Модификация функции CreateWindow.

            Необходимо модифицировать вызов функции  CreateWindow  для
       того,  чтобы  создать  окно  с  горизонтальными и вертикальными
       строками  прокрутки.  Измените  вызов  функции  CreateWindow  в
       WinMain так, чтобы он выглядел следующим образом:

            hWnd = CreateWindow("InputWClass",
                "Пример программы Input",
                WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
.
      Windows 3.0/pg/1#3                                        = 84 =

                CW_USERDEFAULT,
                CW_USERDEFAULT,
                CW_USERDEFAULT,
                CW_USERDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL);
                        4.2.5 Определение прямоугольников для текста.          

            В функцию   InitInstance   необходимо  добавить  следующие
       операторы для    определения    прямоугольников    в    области
       пользователя, в которых отображаются различные сообщения:

            hDC = GetDC(hWnd);
            GetTextMetrics(hDC, &textmetric);
            ReleaseDC(hWnd, hDC);
            nLineHeight = textmetric.tmExternalLeading + textmetric.tmHeight;

            rect.left   = GetDeviceCaps(hDC, LOGPIXELSX) / 4;   /* 1/4 inch */
            rect.right  = GetDeviceCaps(hDC, HORZRES);
            rect.top    = GetDeviceCaps(hDC, LOGPIXELSY) / 4;   /* 1/4 inch */
            rect.bottom = rect.top + nLineHeight;
            rectMouse   = rect;

            rect.top += nLineHeight;
            rect.bottom += nLineHeight;
            rectButton = rect;

            rect.top += nLineHeight;
            rect.bottom += nLineHeight;
            rectKeyboard = rect;

            rect.top += nLineHeight;
            rect.bottom += nLineHeight;
            rectCharacter = rect;

            rect.top += nLineHeight;
            rect.bottom += nLineHeight;
            rectScroll = rect;

            rect.top += nLineHeight;
            rect.bottom += nLineHeight;
            rectTimer = rect;
                                                                               
                   4.2.6  Добавление элемента WM_CREATE.

            Необходимо установить таймер с помощью  функции  SetTimer.
       Это  можно  сделать  в фрагменте WM_CREATE.  Добавьте следующий
       опереатор:

            case WM_CREATE:
.
      Windows 3.0/pg/1#3                                        = 85 =

                  /* Установить таймер на интервал, равный 5 сек. */
                  idTimer =  SetTimer(hWnd, NULL, 5000, (FARPROC) NULL);
                  break;
                                                                               
                  4.2.7 Модификация фрагмента WM_DESTROY.

            Кроме того, необходимо остановить таймер перед завершением
       выполнения программы. Это можно сделать в фрагменте WM_DESTROY.
       Добавьте следующий оператор:

            KillTimer(hWnd, idTimer);
                                                                               
           4.2.8 Добавление фрагментов WM_KEYUP и WM_KEYDOWN.

            Необходимо добавить  фрагменты  WM_KEYUP  и WM_KEYDOWN для
       обработки нажатий на клавиши.  Добавьте следующие  операторы  к
       функции окна:

              case WM_KEYDOWN:
                  wsprintf(KeyboardText, "WM_KEYDOWN: %x, %x, %x",
                      wParam, LOWORD(lParam), HIWORD(lParam));
                  InvalidateRect(hWnd, &rectKeyboard, TRUE);
                  break;

              case WM_KEYUP:
                  wsprintf(KeyboardText, "WM_KEYUP: %x, %x, %x",
                      wParam, LOWORD(lParam), HIWORD(lParam));
                  InvalidateRect(hWnd, &rectKeyboard, TRUE);
                  break;
                                                                               
                    4.2.9 Добавление фрагмента WM_CHAR.

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

              case WM_CHAR:
                  wsprintf(CharacterText, "WM_CHAR: %c, %x, %x",
                      wParam, LOWORD(lParam), HIWORD(lParam));
                  InvalidateRect(hWnd, &rectCharacter, TRUE);
                  break;
                                                                               
                 4.2.10 Добавление фрагмента WM_MOUSEMOVE.

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

              case WM_MOUSEMOVE:
                  wsprintf(MouseText, "WM_MOUSEMOVE: %x, %d, %d",
                      wParam, LOWORD(lParam), HIWORD(lParam));
                  InvalidateRect(hWnd, &rectMouse, TRUE);
                  break;
.
      Windows 3.0/pg/1#3                                        = 86 =

                                                                               
        4.2.11 Добавление фрагментов WM_LBUTTONUP и WM_LBUTTONDOWN.

            Необходимо добавить      фрагменты      WM_LBUTTONUP     и
       WM_LBUTTONDOWN для  обработки  сообщений об изменении состояния
       кнопок мыши. Добавьте следующие операторы к функции окна:

              case WM_LBUTTONDOWN:
                  wsprintf(ButtonText, "WM_LBUTTONDOWN: %x, %d, %d",
                      wParam, LOWORD(lParam), HIWORD(lParam));
                  InvalidateRect(hWnd, &rectButton, TRUE);
                  break;

              case WM_LBUTTONUP:
                  wsprintf(ButtonText, "WM_LBUTTONUP: %x, %d, %d",
                      wParam, LOWORD(lParam), HIWORD(lParam));
                  InvalidateRect(hWnd, &rectButton, TRUE);
                  break;
                                                                               
               4.2.12 Добавление фрагмента WM_LBUTTONDBLCLK.

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

              case WM_LBUTTONDBLCLK:
                  wsprintf(ButtonText, "WM_LBUTTONDBLCLK: %x, %d, %d",
                      wParam, LOWORD(lParam), HIWORD(lParam));
                  InvalidateRect(hWnd, &rectButton, TRUE);
                  break;
                                                                               
                   4.2.13 Добавление фрагмента WM_TIMER.

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

              case WM_TIMER:
                  wsprintf(TimerText, "WM_TIMER: %d seconds",
                      nTimerCount += 5);
                  InvalidateRect(hWnd, &rectTimer, TRUE);
                  break;
                  4.2.14 Добавление фрагментов WM_HSCROLL и WM_VSCROLL.        

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

              case WM_HSCROLL:
              case WM_VSCROLL:
                  strcpy(HorzOrVertText,
                      (message == WM_HSCROLL) ? "WM_HSCROLL" : "WM_VSCROLL");
                  strcpy(ScrollTypeText,
.
      Windows 3.0/pg/1#3                                        = 87 =

                      (wParam == SB_LINEUP) ? "SB_LINEUP" :
                      (wParam == SB_LINEDOWN) ? "SB_LINEDOWN" :
                      (wParam == SB_PAGEUP) ? "SB_PAGEUP" :
                      (wParam == SB_PAGEDOWN) ? "SB_PAGEDOWN" :
                      (wParam == SB_THUMBPOSITION) ? "SB_THUMBPOSITION" :
                      (wParam == SB_THUMBTRACK) ? "SB_THUMBTRACK" :
                      (wParam ==   SB_ENDSCROLL)  ?  "SB_ENDSCROLL":"unknown");
                  wsprintf(ScrollText, "%s: %s, %x, %x",
                      (LPSTR)HorzOrVertText,
                      (LPSTR)ScrollTypeText,
                      LOWORD(lParam),
                      HIWORD(lParam));
                  InvalidateRect(hWnd, &rectScroll, TRUE);
                  break;
                              4.2.15 Добавление фрагмента WM_PAINT.            

            Необходимо индицировать текущие состояния мыши, клавиатуры
       и таймера.  Наиболее удобный способ это сделать -  использовать
       сообщение  WM_PAINT для индицирования этих состояний.  Добавьте
       следующие операторы к функции окна:

              case WM_PAINT:
                  hDC = BeginPaint (hWnd, &ps);

                  if (IntersectRect(&rect, &rectMouse, &ps.rcPaint))
                      TextOut(hDC, rectMouse.left, rectMouse.top,
                              MouseText, strlen(MouseText));
                  if (IntersectRect(&rect, &rectButton, &ps.rcPaint))
                      TextOut(hDC, rectButton.left, rectButton.top,
                              ButtonText, strlen(ButtonText));
                  if (IntersectRect(&rect, &rectKeyboard, &ps.rcPaint))
                      TextOut(hDC, rectKeyboard.left, rectKeyboard.top,
                              KeyboardText, strlen(KeyboardText));
                  if (IntersectRect(&rect, &rectCharacter, &ps.rcPaint))
                      TextOut(hDC, rectCharacter.left, rectCharacter.top,
                              CharacterText, strlen(CharacterText));
                  if (IntersectRect(&rect, &rectTimer, &ps.rcPaint))
                      TextOut(hDC, rectTimer.left, rectTimer.top,
                              TimerText, strlen(TimerText));
                  if (IntersectRect(&rect, &rectScroll, &ps.rcPaint))
                      TextOut(hDC, rectScroll.left, rectScroll.top,
                              ScrollText, strlen(ScrollText));

                  EndPaint(hWnd, &ps);
                  break;
                                                                               
                      4.2.16 Трансляция и компоновка.

            Можно транслировать  и  компоновать  прикладную  программу
       Input   без  изменения  файла  make.  По  окончании  компиляции
       запустите Windows и прикладную программу  Input.  Для  проверки
       работы программы нажмите клавиши на клавиатуре,  нажмите кнопку
.
      Windows 3.0/pg/1#3                                        = 88 =

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

            Рисунок 4.1.  Окно программы Input.
            1. Программа Input выводит текст при  получении  сообщений
               от мыши, клавиатуры или таймера.
                                               4.3 Заключение.                 

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

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

            Дополнительную информацию,  относительно ввода вы  найдете
      в:

       Раздел               Руководство
       ---------------------------------------------------------------
       Программная модель   Руководство программиста, глава 1, "Обзор
       Windows              среды Windows"

       Использование курсо- Руководство программиста, глава 6, "Курсор,
       ра для ввода от мыши мышь и клавиатура"
       и клавиатуры

       Меню и ввод от меню  Руководство программиста, глава 7, "Меню"

       Строки прокрутки     Руководство программиста, глава 8, "Блоки
                            управления"

       Функции ввода        Справочное руководство, том 1, глава 1,
                            "Функции интерфейса управления окнами",
                            глава 4, "Список функций".

       Сообщения ввода      Справочное руководство, том 1, глава 5,
                            "Обзор сообщений", глава 6, "Список сооб-
                            щений".


.
      Windows 3.0/pg/1#3                                        = 89 =

                                                                               
                              Глава 5. Иконы.
      ----------------------------------------------------------------
            Стандартные программы  Windows используют для собственного
       представления при минимизации окна иконы.

            В данной главе описываются следующие темы:

            - Что такое икона.

            - Создание    и    использование     ваших     собственных
              предопределенных икон.

            - Определение иконы класса окон прикладной программы.

            - Изменение  иконы вашей программы во время выполнения (на
              лету).

            - Вывод иконы в панели диалога.

            В данной  главе  описано  также,   как   создать   простую
       программу  Icon,  которая  иллюстрирует использование многих из
       перечисленных тем.
                                          5.1  Что такое икона.                

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

            Для прикладной  программы икона - это тип ресурсов.  Перед
       компиляцией ресурсов  каждая  икона  содержится  в  собственном
       файле в  виде  набора  растровых карт.  Эти растровые карты при
       выводе могут  быть  одинаковыми,   однако   предназначены   для
       различных типов   устройств   отображения.   Когда   прикладная
       программа собирается использовать  икону,  она  просто  требует
       этот ресурс  по  имени.  При загрузке иконы Windows определяет,
       какой из этих образов больше подходит для конкретного  дисплея.
       Поскольку Windows  выбирает  их  автоматически,  то  прикладной
       программе нет необходимости проверять тип дисплея и  определять
       какой  из  образов для него подходит.  Рисунок 5.1 иллюстрирует
       процесс запроса пользователем ресурса иконы.

            Рисунок 5.1  Использование икон.
            1. Прикладной   программе   требуется   ресурс   с  именем
               "MyIcon".
            2. Windows ищет ресурс с именем "MyIcon" и определяет, что
               он содержит четыре образа для четырех  различных  типов
               дисплеев.
            3. Windows выводит икону,  которая наиболее  соответствует
               дисплею.
.
      Windows 3.0/pg/1#3                                        = 90 =

            4. Диcплей EGA.
            5. Дисплей VGA.
            6. Монохромный дисплей.
            7. Заказной дисплей.
                                                                               
                   5.1.1  Использование встроенных икон.

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

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

            hHandIcon= LoadIcon(NULL, IDI_EXCLAMATION);

            После загрузки  встроенной  иконы  ваша  программа   может
       использовать ее. Например, ваша программа может определить ее в
       качестве иконы класса для определенного класса окон.  Или может
       включить икону   в  панель  сообщений.  Подробное  описание  вы
       найдете в разделах 5.3,  "Определение  иконы  класса",  и  5.4,
       "Вывод ваших собственных икон".
                                                                               
                   5.2. Использование собственных икон.

            При использовании икон необходимо выполнить три шага:

            1. Создать файл иконы с помощью инструментального средства
               SDKPaint.

            2. Определить ресурс иконы  с  помощью  оператора  ICON  в
               файле описания ресурсов прикладной программы.

            3. При  необходимости  загрузить  ресурс  иконы  с помощью
               функции LoadIcon.

            После загрузки иконы  ее  можено  использовать.  Ее  можно
       определить, например, в качестве иконы класса.

            Следующие разделы описывают этот процесс более детально.
                                                                               
                       5.2.1  Создание файла иконы.

            Файл иконы  содержит  одно или несколько изображений.  Для
       рисования и сохранения в файле  иконы  вы  можете  использовать
       SDKPаint.

            Следуйте указаниям, данным в описании SDKPaint по созданию
       и сохранению  в  файле  икон.  Для  файлов  икон  рекомендуется
       использовать расширение .ICO.
.
      Windows 3.0/pg/1#3                                        = 91 =

                                                                               
                     5.2.2  Определение ресурса иконы.

            После того,  как вы создали икону, вы должны описать икону
       в файле описания ресурсов вашей прикладной программы (.RC).

            Для описания  ресурса  иконы  добавьте  в  файл   описания
       ресурсов оператор  ICON.  Оператор  ICON определяет имя иконы и
       файл, в котором она хранится.  Например, ниже приведен оператор
       ICON, который  добавляет  к ресурсам вашей прикладной программы
       икону с именем "MyIcon":

            MyIcon ICON "MYICON.ICO"

            Имя файла "MYICON.ICO" определяет файл, в котором хранится
       икона с  именем  MyIcon.  При  компиляции  файла ресурсов икона
       будет скопирована из файла в файл ресурсов.
                                                                               
                      5.2.3  Загрузка ресурса иконы.

            После создания иконы и определения ее в файле  определения
       ресурсов ваша программа может загрузить его.

            Для загрузки  иконы из ресурсов нужно использовать функцию
       LoadIcon, которая получает дескриптор  экземпляра  программы  и
       имя иконы, и которая возвращает дескриптор иконы. Ниже приведен
       пример, в котором загружается икона "MyIcon"  и  ее  дескриптор
       запоминается в переменной hMyIcon.

            hMyIcon = LoadIcon(hInstance,"MyIcon");

            После загрузки ее можно выводить.
                                            5.3 Иконы классов.                 

            Икона класса   -   это  икона,  которая  используется  для
       конкретного класса окон  каждый  раз,  когда  окно  это  класса
       преобразуется  в  икону.  Установка иконы класса осуществляется
       присваиванием дескриптора иконы  полю  hIcon  структуры  класса
       окна  перед  регистрацией класса.  После установки иконы класса
       при уменьшении размера окна этого класса до размеров иконы, она
       будет   соответствовать   этому   классу.

            Ниже показан  пример  определения класса wc до регистрации
       класса. В этом определении полю hIcon присваивается  дескриптор
       иконы, который возвращает функция LoadIcon:

          wc.style = NULL;
          wc.lpfnWndProc = MainWndProc;
          wc.cbClsExtra = 0;
          wc.cbWndExtra = 0;
          wc.hInstance = hInstance;
       (1)   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
.
      Windows 3.0/pg/1#3                                        = 92 =

          wc.hCursor = LoadCursor(NULL, IDC_ARROW);
          wc.hbrBackground = GetStockObject(WHITE_BRUSH);
          wc.lpszMenuName =  NULL;
          wc.lpszClassName = "Generic";

       1)   Функция LoadIcon  возвращает  дескриптор встроенной иконы,
            определяемой IDI_APPLICATION.  Если  вы минимизируете окно
            этого класса,  то вы увидите белый прямоугольник с  черной
            рамкой. Это встроенная икона прикладных программ.
                                5.4  Отображение собственных икон.             

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

            Однако, иногда    вашей    прикладной    программе   может
       понадобиться выводить икону самостоятельно,  вместо того, чтобы
       это  делали  Windows  для  предопределенной  иконы класса.  Это
       нужно,  если вы хотите,  чтобы икона вашей прикладной программы
       была  динамичной,  как икона программы Clock.  (Программа Clock
       продолжает показывать  время  даже  после  того,  как   вы   ее
       минимизировали).  Windows  позволяет  пользователю  выводить  в
       окне,  когда оно находится в состоянии иконы, так, что он может
       рисовать свои собственные иконы.

            Если вы  хотите,  чтобы ваша прикладная программа выводила
       собственную икону, то:

            1. В структуре класса окна установите икону класса в  NULL
               перед  регистрацией класса окна.  Используйте для этого
               следующий оператор:

                 wc.hIcon = NULL;

               Этот шаг нужен,  чтобы  сообщить  Windows  о  том,  что
               необходимо  продолжать  посылать функции окна сообщение
               WM_PAINT  даже   в   том   случае,   если   окно   было
               минимизировано.

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

               PAINTSTRUCT ps;
               HDC hDC;
                  .
                  .
                  .
.
      Windows 3.0/pg/1#3                                        = 93 =

               case WM_PAINT:
                  hDC = BeginPaint(hWnd,&ps);
                  if (isIconic(hWnd))
                  {
                      /* вывод в состоянии иконы */
                  }
                  else
                  {
                      /* вывод в обычном состоянии */
                  }
                  EndPaint(hWnd,&ps);
                  break;

            Прикладная программа должна определить,  в каком состоянии
       находится окно (т.е.  в виде иконы или нет),  поскольку вывод в
       иконе  может  отличаться  от  вывода в обычное окно.  Если окно
       находится в  состоянии  иконы,  функция   IsIconic   возвращает
       значение TRUE.

            Функция BeginPaint   возвращает    дескриптор    контекста
       отображения области  пользователя  иконы.  BeginPaint  получает
       дескриптор окна и дальний адрес структуры параметров  рисования
       ps. BeginPaint  заполняет  структуру информацией об области,  в
       которой будет производится вывод.  Как и при  обычных  функциях
       вывода, каждому     вызову     функции     BeginPaint    должен
       соответствовать вызов  функции  EndPaint.  EndPaint освобождает
       ресурсы,  полученные  BeginnPaint,  и  сообщает  Windows,   что
       прикладная     программа    завершила    перерисовку    области
       пользователя.

            Получить размер области пользователя иконы можно с помощью
       поля rcPaint   структуры  рисования.  Например,  для  рисования
       эллипса,  который  заполнит  икону,  вы   можете   использовать
       следующий оператор:

            Ellipse(hDC, ps.rcPaint.left, ps.rcPaint.top,
                         ps.rcPaint.right, ps.rcPaint.bottom);

            Для рисования в иконе вы можете использовать любые функции
       GDI,   включая  TextOut.  Единственным  ограничением  выступает
       размер иконы,  который различается на различных типах дисплеев,
       поэтому  убедитесь,  что вы используете средства рисования,  не
       зависяцие от размеров иконы.
                            5.5 Использование икон в панели диалога.           

            Можно поместить  икону  в  панель   диалога,   использовав
       управляющий  оператор  ICON в операторе DIALOG.  Уже приводился
       пример оператора DIALOG панели  диалога  About,  описанной  для
       прикладной программы Generic.  Оператор диалога для этой панели
       выглядит так:

       AboutBox DIALOG 22, 17, 144, 75
.
      Windows 3.0/pg/1#3                                        = 94 =

       STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
       CAPTION "About Icon"
       BEGIN
           CTEXT "Microsoft Windows"     -1, 0, 5, 144, 8
           CTEXT "Icon Application"      -1, 0, 14, 144, 8
           CTEXT "Version 3.0"           -1, 0, 34, 144, 8
           DEFPUSHBUTTON "OK"             IDOK, 53, 59, 32, 14, WS_GROUP
       END

            Можно добавить  икону к панели диалога,  вставив указанный
       ниже   оператор   ICON    непосредственно    после    оператора
       DEFPUSHBUTTON:

            ICON  "MyIcon",  -1, 25, 14,  16, 21

            Когда икона появляется в панели  диалога,  она  трактуется
       как   и   любой   другой  блок  управления.  Она  должна  иметь
       идентификатор,  положение ее верхнего  левого  угла,  ширину  и
       высоту.  В  данном  примере -1 - это ее идентификатор,  25 и 14
       определяют положение  ее  левого  верхнего  угла,  а  16  и  21
       определяют  ее  высоту  и ширину соответсвенно.  Однако Windows
       игнорирует ее  высоту  и  ширину,  устанавливая  размеры  иконы
       автоматически.

            Имя "MyIcon"   идентифицирует  используемую  икону.  Икона
       должна быть определена в операторе ICON  в  любом  месте  файла
       описания ресурсов. Например, можно добавить следующий оператор:

            MyIcon ICON myicon.ico
                              5.6 Пример прикладной программы Icon.            

            Эта прикладная программа показывает, как использовать ико-
       ну в прикладной программе, в частности, как выполнить следующие
       действия:

            - использовать заказную икону в качестве иконы класса;

            - использовать икону в панели диалога About.

            Для создания прикладной программы Icon скопируйте и переи-
       менуйте исходные файлы прикладной программы  Generic,  а  затем
       сделайте следующие модификации:

            1) включите оператор ICON в файл описания ресурса;

            2) включите управляющий оператор ICON в оператор DIALOG
               файла описания ресурсов;

            3) загрузить заказную икону и использовать ее в функции
               инициализации для установки иконы класса;

            4) измените   make-файл  программы  таким  образом,  чтобы
.
      Windows 3.0/pg/1#3                                        = 95 =

               компилятор ресурсов добавил икону в выполняемый файл;

            5) откомпилируйте и скомпонуйте программу.

            Подразумевается, что икона создана с  помощью  SDKPaint  и
      сохранена в файле с именем MYICON.ICO.

            Вместо того, чтобы вводить тексты, приведенные в следующих
       разделах, возможно вам будет удобнее просто переписать исходные
       тексты из SDK.
                                                                               
                      5.6.1 Включение оператора ICON.

            Необходимо включить   оператор   ICON   в   файл  описания
       ресурсов. Вставьте  указанную  ниже  строку  в   начало   файла
       описания ресурсов сразу после директив #include:

            MyIcon ICON myicon.ico
                                                                               
               5.6.2 Включение управляющего оператора ICON.

            Необходимо включить  управляющий  оператор ICON в оператор
       DIALOG.  Вставьте указанную ниже строку  непосредственно  после
       оператора DEFPUSHBUTTON:

            ICON  "MyIcon",  -1, 25, 14,  16, 21
                                                                               
                       5.6.3 Установка иконы класса.

            Можно установить  икону  класса,  добавив приведенный ниже
       оператор к функции инициализации исходного С-файла:

          wc.hIcon = LoadIcon(hInstance, "MyIcon");   /* loads icon */
                                                                               
                 5.6.4 Добавление MYICON.ICO в MAKE-файл.

            В MAKE-файле добавьте файл MYICON.ICO к списку файлов,  от
       которых зависит  ICON.RES.  Соответствующие  строки  MAKE-файла
       должны выглядеть следующим образом:

            icon.res: icon.rc icon.h myicon.ico
                rc -r icon.rc

            Этим вы   добиваетесь   того,   что  при  изменении  файла
       MYICON.ICO файл ICON.RES будет перекомпилирован.

            Никаких других изменений не требуется.
                                                                               
                      5.6.5  Трансляция и компоновка.

            Оттранслируйте и  перекомпонуйте  программу  Icon.   После
       перетрансляции  запустите  Windows и прикладную программу Icon.
       Теперь,  если выбрана команда  About,  панель  диалога  About
       будет содержать икону.
.
      Windows 3.0/pg/1#3                                        = 96 =

                                              5.7  Заключение.                 

            В данной главе описывается, как создавать и использовать в
       прикладных программах иконы.  Икона - это маленький графический
       образ, который   представляет   прикладную   программу  при  ее
       минимизации.  Вы  можете  использовать  одну  из  встроенных  в
       Windows   икон   или   воспользоваться  SDKPaint  для  создания
       собственной.  Вы можете указать икону  при  регистрации  класса
       окна,   тогда   Windows   автоматически   отобразит  икону  при
       минимизации  окна  прикладной  программы.  Кроме   этого   ваша
       программа   может   сама   рисовать  икону,  используя  функции
       BeginPaint и EndPaint.

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

       Раздел               Руководство
       ---------------------------------------------------------------
       Функции LoadIcon,    Справочное руководство, том 1, глава 4,
       IsIconic, BeginPaint "Список функций".
       и TextOut

       Операторы описания   Справочное руководство, том 2, глава 8,
       ресурсов             "Операторы описания ресурсов".

       Использование        "Tools", глава 4, "Создание изображений".
       SDKPaint

       Использование редак- "Tools", глава 5, "Создание панелей
       тора диалога для до- диалога: DialogEditor".
       бавления иконы к
       блоку диалога


.
      Windows 3.0/pg/1#3                                        = 97 =

                                                                               
                    Глава 6. Курсор, мышь и клавиатура.
      ----------------------------------------------------------------
            Курсор -   это   растровая   карта,   которая   показывает
       пользователю,  где происходит действие,  инициированное  мышью.
       Большинство  программ  Windows  использует курсор с мышью или с
       клавиатурой  для  того,  чтобы  дать  возможность  пользователю
       делать выборки, указывать команды и выполнять другие действия.

            В данной главе описаны следующие разделы:

            - Управление изображением курсора.

            - Отображение курсора.

            - Выбор информации пользователем с помощью мыши.

            - Перемещение курсора с помощью клавиатуры.

            Кроме этого,  в  данной главе описывается процесс создания
       простой программы Cursor,  которая  иллюстрирует  некоторые  из
       этих концепций.
                                                                               
                      6.1. Управление формой курсора.

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

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

            Программа управляет формой курсора двумя методами:

            - Можно использовать встроенные в Windows курсоры.

            - Можно использовать собственные курсоры.

            Ниже описываются оба метода.
                           6.1.1. Использование встроенных курсоров.           


            Windows предоставляет несколько встроенных  форм  курсора.
       Это стрелка,  песочные  часы,  I-образный курсор и перекрестье.
       Большинство встроенных  курсоров  используются  в   специальных
       случаях. Например,    I-образный    курсор   используется   при
       редактировании текста,  а  курсор   в   виде   песочных   часов
       используется при  выполнении  длительных  операций,  таких  как
       чтение файлов.

.
      Windows 3.0/pg/1#3                                        = 98 =

            Для использования встроенного курсора необходимо с помощью
       функции LoadCursor  получить  его  дескриптор.  Первый аргумент
       должен быть NULL (указывает,  что требуется встроенный курсор),
       а  второй  аргумент  должен специфицировать загружаемый курсор.
       Например, ниже  в  переменную  hCursor   заносится   дескриптор
       I-образного курсора,  который обычно используется для просмотра
       и редактирования   текста,    который    определяется    вторым
       аргументом, равным IDC_IBEAM:

            hCursor = LoadCursor(NULL, IDC_IBEAM);

            Курсор можно  использовать  после загрузки.  Например,  вы
       можете использовать I-образный курсор для  указания  того,  что
       происходит редактирование текста.  В разделе 6.2 описаны методы
       отображения курсоров.
                          6.1.2  Использование собственных курсоров.           

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

            - Создайте курсор с помощью SDKPaint.

            - Укажите  ресурс  курсора  в  файле  описания  ресурсов с
              помощью оператора CURSOR.

            - Загрузите курсор с помощью функции LoadCursor.

            - Выведите курсор,  используя один из методов, описанных в
              разделе 6.2 "Отображение курсоров".

            Ниже эти шаги описаны более детально.

                       Создание собственного курсора.

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

             После создания  курсора  надо  сохранить  его   в   файле,
       используя рекомендованное расширение имени файла .cur.

            Использование SDKPaint описано в "Tools".

               Добавление курсора к ресурсам вашей программы.

            Затем необходимо добавить оператор CURSOR к файлу описания
       ресурсов.  Оператор CURSOR специфицирует файл, который содержит
       курсор и имя,  которое будет использовано прикладной программой
       при его загрузке:

            bullseye CURSOR bullseye.cur
.
      Windows 3.0/pg/1#3                                        = 99 =


            В этом примере имя курсора -  bullseye,  а  имя  файла,  в
       котором он содержится, - bullseye.cur.

                          Загрузка ресурса курсора.

            В прикладной   программе  необходимо  получить  дескриптор
       курсора с  помощью  функции  LoadCursor.  Например,  в   данном
       операторе производится   загрузка   ресурса  "bullseye"  и  его
       дескриптор заносится в переменную hCursor:

            hCursor=LoadCursor(hInstance,(LPSTR) "bullseye");

            Функция LoadCursor загружает курсор из ресурсов прикладной
       программы. Дескриптор   экземпляра   hInstance   идентифицирует
       ресурсы прикладной  программы.  Имя  "bullseye"  идентифицирует
       курсор. Это  то  же самое имя,  которое задано в файле описания
       ресурсов.
                                                                               
                         6.2  Отображение курсора.

            После загрузки курсора,  вы можете вывести его,  используя
       один из двух методов:

            - Определив  его  как  курсор класса для всех окон данного
              класса.

            - Явно установив курсор при перемещении курсора по области
              пользователя определенного окна.

            Ниже эти методы описаны более подробно.
                                                                               
                           6.2.1 Курсор класса.

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

            wc.hCursor=LoadCursor(NULL, IDC_ARROW);

            Для каждого  окна этого класса будет появляться встроенный
       курсор стрелки, когда пользователь перемещает курсор в окно.
                           6.2.2 Индицирование собственного курсора.           

            Прикладная программа может и не определять курсор  класса.
       Вместо  этого  программа  должна установить поле hCursor в NULL
       для указания того,  что курсора класса нет.  Если окно не имеет
       курсора  класса,  Windows не будет автоматически изменять форму
.
      Windows 3.0/pg/1#3                                       = 100 =

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

            Для индицирования  курсора,  независимо от того встроенный
       он или заказной,  необходимо его загрузить.  В  данном  примере
       дескриптор   загружаемого   курсора   присваивается  переменной
       hMyCursor.

            static HCURSOR hMyCursor;   /* статическая переменная */
            hMyCursor = LoadCursor(hInstance,(LPSTR)"MyCursor");

            Затем, для изменения формы курсора необходимо использовать
       функцию SetCursor, чтобы устанавливать форму курсора при каждом
       перемещении в область пользователя.  Поскольку Windows посылает
       окну при каждом перемещении курсора сообщение WM_MOUSEMOVE,  то
       им можно управлять, добавив следующие операторы к функции окна:

            case WM_MOUSEMOVE:
                 SetCursor (hMyCursor);
                 break;

            Примечание. Если необходимо индицировать свой  собственный
       курсор,   необходимо   убедиться,   что   поле  курсора  класса
       установлено в NULL.  В противном случае Windows будет  пытаться
       изменить  форму курсора.  В результате это приведет к заметному
       мельканию при перемещении курсора по экрану.
               6.2.3 Пример: Использование песочных часов при длительных       
                                 операциях.

            Каждый раз, когда прикладная программа начинает длительную
       операцию по считыванию/записи больших блоков данных из/в  файл,
       необходимо изменить форму курсора на песочные часы.  Это укажет
       пользователю на то,  что началась длительная операция, и что он
       должен ожидать ее завершения,  не пытаясь продолжить работу. По
       завершении  операции  необходимо  восстановить  курсор  в   его
       первоначальную форму.

            Можно изменить   форму   курсора,   использовав  следующие
       операторы:

       (1)  HCURSOR hSaveCursor;
            HCURSOR hHourGlass;
                .
                .
                .
            hHourGlass = LoadCursor(hInstance, IDC_WAIT);
                .
                .
                .
       (2)  SetCapture(hWnd);
       (3)  hSaveCursor = SetCursor(hHourGlass);

.
      Windows 3.0/pg/1#3                                       = 101 =

                  /* длительная операция */

       (4)  SetCursor(hSaveCursor);
       (5)  ReleaseCapture();
                .
                .
                .

            В этом примере:

       1)   Прикладная программа определяет переменные,  которые будут
            использоваться для  сохранения  дескриптора  курсора.  Обе
            переменные имеют тип HCURSOR.

       2)   Прикладная программ  вначале  захватывает  ввод  от  мыши,
            используя функцию     SetCapture.     Это     предохраняет
            пользователя от    попытки    использовать   мышь   другой
            прикладной  программой  во  время  выполнения   длительной
            операции. После захвата ввода мыши, Windows направляет его
            в указанное окно вне зависимости  от  того,  находится  ли
            курсор мыши  в  этом  окне или нет.  После этого программа
            может соответсвующим образом обрабатывать сообщения.

       3)   Затем устанавливается  форма  курсора  с  помощью  функции
            SetCursor. Прежняя форма, возвращаемая функцией SetCursor,
            сохраняется, так что по завершении операции она может быть
            восстановлена с  помощью  SetCursor.  Прикладная программа
            сохраняет дескриптор в переменной hSaveCursor.

       4)   После завершения длительной операции прикладная программа
            восстанавливает форму курсора.

       5)   Функция ReleaseCapture освобождает ввод от мыши.
                    6.3  Выбор пользователем инофрмации с помощью мыши.        

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

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

            - Начало обработки выборки.
.
      Windows 3.0/pg/1#3                                       = 102 =


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

            - Выполнить визуальное отображение процесса выборки.

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

            - Завершение выборки.

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

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



            Примечание: Мышь - это одно из многих возможных  системных
       устройств манипулирования.  Другие устройства  манипулирования,
       такие,  как  графические планшеты,  джойстики и световые перья,
       могут работать  по-разному,   но   должны   обеспечивать   ввод
       аналогичный  мыши.  Приводимые  ниже  примеры  также могут быть
       использованы и с этими устройствами. Помните, что когда имеется
       устройство  манипулирования,  Windows  автоматически  управляет
       местоположением и формой курсора.
                                   6.3.1  Начало выборки графики.              

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

            В данном  разделе  описывается,  как  использовать   метод
       "резинового    прямоугольника",    используемый   для   выборки
       графического изображения.  Для  создания  прямоугольника  можно
       использовать    сообщения    WM_LBUTTONDOWN,   WM_LBUTTONUP   и
       WM_MOUSEMOVE.  Это  дает   возможность   пользователю   создать
.
      Windows 3.0/pg/1#3                                       = 103 =

       выборку,  указав  точку,  нажав левую кнопку,  переместившись в
       другую точку и  отпустив  кнопку.  Во  время  перемещения  мыши
       прикладная   программа  может  обеспечить  мгновенную  обратную
       связь, инвертируя окантовку прямоугольника, заданного начальной
       и текущей точками.
            Таким способом  выборка начинается при получении сообщения
       WM_LBUTTONDOWN.  Необходимо сделать три шага: захватить ввод от
       мыши, сохранить начальную точку и сохранить текущую точку:

            BOOL bTrack = False;
            int OrgX = 0, OrgY = 0;
            int PrevX = 0, PrevY = 0;
            int X = 0, Y = 0;
                .
                .
                .
       (1)  case WM_LBUTTONDOWN:
                bTrack = TRUE;
                OrgX = LOWORD(lParam);
                OrgY = HIWORD(lParam);
                PrewX = LOWORD(lParam);
                PrevY = HIWORD(lParam);
       (2)      InvalidateRect(hWnd,NULL,TRUE);
                UpdateWindow(hWnd);

                /* захватить весь ввод от мыши */

       (3)      SetCapture(hWnd);
                break;

       1)   Когда программа    получает    сообщение   WM_LBUTTONDOWN,
            переменная bTrack  устанавливается  в  TRUE  для  указания
            того,  что выборка началась.  Как и для  любого  сообщения
            мыши параметр lParam содержит в младших и старших разрядах
            слова текущие   координаты   мыши   по   осям   x   и    y
            соответственно.  Они  запоминаются  как начальные значения
            OrgX и OrgY,  а также  как  предыдущие  значения  PrevX  и
            PrevY.  Переменные  PrevX  и  PrevY будут корректироваться
            сразу же при получении следующего сообщения  WM_MOUSEMOVE.
            Переменные  OrgX  и  OrgY  остаются  без изменения и будут
            использованы для определения начала  копируемой  растровой
            карты.

       2)   Для отображения    реакции    на    получение    сообщения
            WM_LBUTTONDOWN прикладная программа сообщает функции окна,
            что необходима перерисовка. Это делается с помощью функций
            InvalidateRect и UpdateWindow.

       3)   Функция SetCapture направляет  весь  последующий  ввод  от
            мыши  в  окно,  даже  если  курсор мыши и перемещается вне
            окна.  Это делается для уверенности  в  том,  что  процесс
            выборки  не прерывается.

.
      Windows 3.0/pg/1#3                                       = 104 =

            В ответ  на  получение сообщения WM_PAINT программа должна
            перерисовать помеченную для перерисовки область окна:

              case WM_PAINT:
                  {
                      PAINTSTRUCT     ps;
                      HDC hDC;

                      hDC = BeginPaint (hWnd, &ps);
                      if (OrgX != PrevX || OrgY != PrevY) {
                          MoveTo(hDC, OrgX, OrgY);
                          LineTo(hDC, OrgX, PrevY);
                          LineTo(hDC, PrevX, PrevY);
                          LineTo(hDC, PrevX, OrgY);
                          LineTo(hDC, OrgX, OrgY);
                      }
                      EndPaint (hWnd, &ps);
                  }
                  break;

            В некоторых  прикладных  программах  возможно  понадобится
       расширить существующую выборку.  Один из способов сделать это -
       удерживать   клавишу  Shift  при  создании  выборки.  Поскольку
       параметр wParam содержит  флаг,  который  определяет,  была  ли
       клавиша   Shift   нажата,  то  это  легко  проконтролировать  и
       расширить выборку  в  случае  необходимости.  Тогда  расширение
       выборки означает сохранение предыдущих значений OrgX и OrgY при
       ее начале.  Для этого  измените  фрагмент  WM_LBUTTONDOWN  так,
       чтобы он выглядел следующим образом:

              case WM_LBUTTONDOWN:
                  bTrack = TRUE;
                  PrevX = LOWORD(lParam);
                  PrevY = HIWORD(lParam);
                  if (!(wParam & MK_SHIFT)) {       /* Если не нажата
                                                       клавиша shift */
                      OrgX = LOWORD(lParam);
                      OrgY = HIWORD(lParam);
                  }
                  InvalidateRect (hWnd, NULL, TRUE);
                  UpdateWindow (hWnd);

                  /* Захватить  весь  ввод  от  мыши,  даже  если  она
                     находится вне окна */

                  SetCapture(hWnd);
                  break;
                                    6.3.2  Индицирование выборки.              

            В процессе  выборки  необходимо обеспечить обратную связь.
       Это можно сделать,  рисуя  окантовку  вокруг  прямоугольника  с
       помощью функции LineTo при каждом новом сообщении WM_MOUSEMOVE.
.
      Windows 3.0/pg/1#3                                       = 105 =

       Для предотвращения потери информации,  находящейся на  дисплее,
       надо рисовать линию,  инвертирующую точки экрана, а не рисующую
       по ним.  Это можно сделать с помощью функции SetROP2, установив
       двоичный   растровый   режим   R2_NOT.  Эту  функцию  выполняют
       приведенные ниже операторы:

      case WM_MOUSEMOVE:
          {
              RECT        rectClient;
              int         NextX;
              int         NextY;

              if (bTrack) {
                  NextX = LOWORD(lParam);
                  NextY = HIWORD(lParam);

                  /* Не рисовать вне области пользователя окна */

                  GetClientRect (hWnd, &rectClient);
                  if (NextX < rectClient.left) {
                      NextX = rectClient.left;
                  } else if (NextX >= rectClient.right) {
                      NextX = rectClient.right - 1;
                  }
                  if (NextY < rectClient.top) {
                      NextY = rectClient.top;
                  } else if (NextY >= rectClient.bottom) {
                      NextY = rectClient.bottom - 1;
                  }

                  /* Если позиция мыши измениласть, то стереть старый  */
                  /* и рисовать новый прямоугольник                    */

                  if ((NextX != PrevX) || (NextY != PrevY)) {
                      hDC = GetDC(hWnd);
                      SetROP2(hDC, R2_NOT);   /* Очистить старый
                                                 прямоугольник */
                      MoveTo(hDC, OrgX, OrgY);
                      LineTo(hDC, OrgX, PrevY);
                      LineTo(hDC, PrevX, PrevY);
                      LineTo(hDC, PrevX, OrgY);
                      LineTo(hDC, OrgX, OrgY);

                      /* Получить текущую позицию курсора */

                      PrevX = NextX;
                      PrevY = NextY;
                      MoveTo(hDC, OrgX,  OrgY);  /* Нарисовать
                                           новый прямоугольник */
                      LineTo(hDC, OrgX, PrevY);
                      LineTo(hDC, PrevX, PrevY);
                      LineTo(hDC, PrevX, OrgY);
                      LineTo(hDC, OrgX, OrgY);
.
      Windows 3.0/pg/1#3                                       = 106 =

                      ReleaseDC(hWnd, hDC);
                  }
              }
          }
          break;

            Сообщение WM_MOUSEMOVE обрабатывается только в том случае,
       если bTrack равен TRUE (т.е.  если  идет  выборка).  Назначение
       обработки WM_MOUSEMOVE состоит в удалении окантовки предыдущего
       прямоугольника   и    рисовании    новой    окантовки    вокруг
       прямоугольника,   который   описывается   начальной  и  текущей
       позициями.   Поскольку   окантовка   -   это    инвертированное
       изображение того,  что было на экране, повторное инвертирование
       полностью восстанавливает экран.  Первые четыре функции  LineTo
       удаляют  предыдущую  окантовку.  Следующие  четыре рисуют новую
       окантовку.  Перед тем, как нарисовать новую окантовку, значения
       PrevX   и   PrevY   корректируются  (им  присваиваются  текущие
       значения, содержащиеся в параметре lParam).
                                       6.3.3  Окончание выборки.               

            Когда пользователь освобождает  левую  кнопку,  необходимо
       сохранить   конечную   точку  и  сигнализировать  об  окончании
       процесса  выборки.  Выборка  завершается  с  помощью  следующих
       операторов:

            case WM_LBUTTONUP:
                bTrack = FALSE;    /* Завершение выборки         */
                ReleaseCapture();  /* освободить   мышь          */
                X = LOWORD(lParam);/* сохранить текущее значение */
                Y = HIWORD(lParam);
                break;

            Когда прикладная     программа     получает      сообщение
       WM_LBUTTONUP,  она  сразу  же  устанавливает значение параметра
       bTrack  в  FALSE  для  указания  того,  что  обработка  выборки
       закончена. Программа   также   освобождает   мышь  от  захвата,
       используя функцию ReleaseCapture,  а затем,  сохраняет  текущее
       положение  мыши  в переменных X и Y.  Это вместе с информацией,
       сохраненной в начале выборки,  составляет информацию о выборке.
       Теперь   прикладная  программа  может  выполнять  над  выборкой
       необходимые операции.

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

            Поскольку была вызвана функция  SetCapture,  то  требуется
       использовать  соответствующую  функцию  ReleaseCapture.  Вообще
       говоря,  необходимо освободить мышь немедленно,  как только она
       не будет больше нужна.
.
      Windows 3.0/pg/1#3                                       = 107 =

                                                                               
                 6.4  Использование курсора с клавиатурой.

            Windows не  требует обязательного использования устройства
       манипулирования,  так что многие прикладные программы дублируют
       действия, которые обычно выполняются (и более удобно) с помощью
       мыши, используя  клавиатуру.  Прикладные   программы,   которые
       применяют    для    управления   курсором   клавиатуру,   могут
       использовать  функции  SetCursorPos,  SetCursor,  GetCursorPos,
       ClipCursor   и   ShowCursor   для   перемещения   курсора   при
       индицировании.
                6.4.1  Использование клавиатуры для перемещения курсора.       

            Можно использовать функцию  SetCursorPos  для  перемещения
       курсора   непосредственно  из  программы.  Эта  функция  обычно
       используется для перемещения курсора с помощью клавиатуры.

            Для перемещения курсора используйте сообщение WM_KEYDOWN и
       отфильтруйте  значения  виртуальных  клавиш  стрелок:  VK_LEFT,
       VK_RIGHT,  VK_UP и  VK_DOWN.  Можно  скорректировать  положение
       курсора при каждом нажатии на клавишу. Ниже показано, как можно
       преобразовать позицию курсора в координаты области пользователя
       окна:


            POINT ptCursor; /* глобальные переменные */
            int repiat=1;
            RECT Rect;
                .
                .
                .
            case WM_KEYDOWN:
       (1)      if (wParam != VK_LEFT && wParam != VK_RIGHT &&
                    wParam != VK_UP && wParam !=VK_DOWN)
                    break;

       (2)      GetCursorPos(&ptCursor);

                /* преобразовать координаты экрана в координаты области
                   пользователя */

       (3)      ScreenToClient(hWnd, &ptCursor);
       (4)      repeat++;      /* увеличить счетчик повторений */

                switch (wParam) {

                     /* изменить позицию курсора в соответствии с на-
                        жатой клавишей. Ускорить перемещение, добавляя
                        счетчик повторений к позиции курсора. */

                   case VK_LEFT:
                       ptCursor.x -=repeat;
.
      Windows 3.0/pg/1#3                                       = 108 =

                       break;
                   case VK_RIGHT:
                       ptCursor.x +=repeat;
                       break;
                   case VK_UP:
                       ptCursor.y -=repeat;
                       break;
                   case VK_DOWN:
                       ptCursor.y +=repeat;
                       break;
                   default:
                       return(NULL);
                }

                  /* Убедиться, что курсор не вышел за пределы области
                     пользователя окна */

       (5)        GetClientRect(hWnd, &Rect);

       (6)        if (ptCursor.x >= Rect.right)
                      ptCursor.x = Rect.right - 1;
                  else if (ptCursor.x < Rect.left)
                      ptCursor.x = Rect.left;
                  if (ptCursor.y >= Rect.bottom)
                      ptCursor.y = Rect.bottom - 1;
                  else if (ptCursor.y < Rect.top)
                      ptCursor.y = Rect.top;

       (7)        ClientToScreen(hWnd, &ptCursor);
       (8)        SetCursorPos(ptCursor.x, ptCursor.y);
                  break;

              case WM_KEYUP:
       (9)        repeat = 1;           /* Очистить счетчик. */
                  break;

       1)   Первый оператор if фильтрует значения  виртуальных  клавиш
            для клавиш VK_LEFT, VK_RIGHT, VK_UP и VK_DOWN.

       2)   Можно получить   текущее  положение  курсора,  использовав
            функцию GetCursorPos. Поскольку пользователь в любое время
            может переместить курсор с помощью мыши,  то нет гарантии,
            что позиция, сохраненная при последнем нажатии на клавишу,
            будет правильной.

       3)   Функция ScreenToClient   преобразует   позицию  курсора  в
            координаты области пользователя.  Это необходимо  по  двум
            причинам: сообщения   мыши   дают   координаты  в  области
            пользователя, и   координаты   области   пользователя   не
            изменяются при перемещении окна.  Другими, словами удобнее
            пользоваться координатами области  пользователя,  т.к.  их
            использует  система и т.к.  они требуют меньше внимания от
            прикладной программы.
.
      Windows 3.0/pg/1#3                                       = 109 =


       4)   Переменная repeat  предоставляет  возможность  ускоренного
            перемещения   курсора.   Если   пользователю    необходимо
            переместиться  на  другой  конец  экрана,  то  перемещение
            курсора на один элемент за одно нажатие на  клавишу  может
            показаться для него утомительным.  Можно ускорить движение
            курсора,  увеличив  число  элементов,  на  которое  курсор
            перемещается, когда пользователь держит клавишу нажатой. В
            этом случае Windows посылает  серию  сообщений  WM_KEYDOWN
            без  соответствующих  сообщений  WM_KEYUP.  Для  ускорения
            движения  курсора  необходимо   просто   увеличить   число
            элементов,  на  которое  делается  продвижение  по каждому
            сообщению WM_KEYDOWN.

       5)   Также необходимо    контролировать,   чтобы   курсор   при
            перемещении оставался в пределах области пользователя. Для
            этого    имеется   простой   способ:   используя   функцию
            GetClientRect, определить     текущий    размер    области
            пользователя.

       6)   Этот оператор if проверяет текущую позицию курсора,  чтобы
            убедиться, что   она   находится   в   пределах    области
            пользователя. При необходимости она изменяется.

       7)   Функция SetCursorPos перемещает курсор в заданную позицию.
            Заметим,  что эта функция в  качестве  параметров  требует
            координаты  экрана,  а  не  координаты  пользователя.  Это
            означает, что необходимо преобразовать координаты  области
            пользователя, хранящиеся   в   структуре  ptCursor,  перед
            вызовом функции  в координаты  экрана,  используя  функцию
            ClientToScreen.

       8)   Функция SetCursorPos перемещает курсор в заданную позицию.

       9)   Когда пользователь  освобождает  клавишу,  то   необходимо
            восстановить  первоначальное  значение переменной повтора.
            Это можно сделать, использовав сообщение WM_KEYUP.
                       6.4.2 Использование курсора при отсутствии мыши.        

            При отсутствии   мыши   программа  должна  индицировать  и
       перемещать  курсор  в  ответ  на  действия  клавиатуры.   Чтобы
       определить   наличие   "мыши",   можно   использовать   функцию
       GetSystemMetrics с параметром SM_MOUSEPRESENT:

            GetSystemMetric (SM_MOUSEPRESENT);

            Эта функция  возвращает  TRUE,   если   мышь   в   системе
       установлена.

            При активировании программы необходимо индицировать курсор
       и скорректировать   его   положение,    а    когда    программа
       деактивируется   -   сделать   курсор   невидимым.  Это  делает
.
      Windows 3.0/pg/1#3                                       = 110 =

       приведенный ниже пример:

            case WM_ACTIVATE:
                if (!GetSystemMetrics(SM_MOUSEPRESENT)) {
                    if (!HIWORD(lParam)) {
                        if (wParam) {
                            SetCursor(hMyCursor);
                            ClientToScreen(hWnd, &ptCursor);
                            SetCursorPos(ptCursor.x, ptCursor.y);
                        }
                        ShowCursor(wParam);
                    }
                }
                break;

            Функции курсора  вызываются  только  в  том  случае,  если
       система не имеет  мыши  (т.е.,  если  функция  GetSystemMetrics
       возвращает  FALSE).  Это необходимо потому,  что если в системе
       имеется мышь,  Windows  позиционирует  и  корректирует   курсор
       автоматически,  а  при выполнении функций курсора эта обработка
       будет нарушена.

            Следующий шаг  -  определить,  является  ли  окно  иконой.
       Курсор не должен индицироваться или корректироваться, если окно
       - в виде иконы.  В этом случае в сообщении WM_ACTIVATE  старшее
       слово не равно нулю.

            Последний шаг   -   проверить   параметр   wParam,   чтобы
       определить, активировано или деактивировано окно. Этот параметр
       не равен нулю, если окно активировано. Когда окно активировано,
       функция  SetCursor  устанавливает  форму  курсора,  а   функция
       SetCursorPos позиционирует    его.    Функция    ClientToScreen
       преобразует координаты положения курсора в  координаты  экрана,
       как   этого  требует  функция  SetCursorPos.  Наконец,  функция
       ShowCursor индицирует или делает невидимым курсор в зависимости
       от значения параметра wParam.

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

            В данном  примере  показывается,  как  включить  курсор  в
       программу,  как  использовать  мышь  и  клавиатуру в прикладной
       программе. Прикладная программа Cursor иллюстрирует:
.
      Windows 3.0/pg/1#3                                       = 111 =


            - как использовать  заказной  курсор  в  качестве  курсора
              класса;

            - как  индицировать  курсор в виде песочных часов во время
              длительных операций;

            - как  использовать  мышь   для   выбора   части   области
              пользователя;

            - как использовать клавиатуру для перемещения курсора.

            Для создания  прикладной  программы  Cursor  скопируйте  и
       переименуйте исходные  файлы   программы   Generic,   а   затем
       выполните следующие модификации:

            1. Добавьте оператор CURSOR к файлу описания ресурсов.

            2. Добавьте новые переменные.

            3. Загрузите   заказной   курсор  и  используйте  его  для
               установки курсора класса в функции инициализации.

            4. Подготовьте курсор в виде песочных часов.

            5. Добавьте  длительную  операцию  к  функции  окна   (для
               простоты используйте  клавишу  Enter  для  переключения
               операции).

            6. Добавьте  фрагменты  WM_LBUTTONDOWN,   WM_MOUSEMOVE   и
               WM_LBUTTONUP к функции окна для поддержки выборки.

            7. Добавьте   фрагмент   WM_KEYDOWN  к  функции  окна  для
               поддержки управляемого клавиатурой перемещения курсора.

            8. Добавьте  фрагмент  WM_PAINT   к   функции   окна   для
               перерисовки помеченного    прямоугольника   в   области
               пользователя.

            9. Добавьте BULLSEYE.CUR к MAKE-файлу.

            10. Откомпилируйте и скомпонуйте программу.

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

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

.
      Windows 3.0/pg/1#3                                       = 112 =

                                                                               
                    6.5.1  Добавление оператора CURSOR.

            Для использования собственного курсора необходимо  создать
       файл курсора,  используя SDKPaint,  и дать ему имя в  операторе
       CURSOR  файла описания ресурсов.  Добавьте следующий оператор к
       файлу описания ресурсов:

            bullsey CURSOR bullseye.cur

            Необходимо быть  уверенным  в  том,   что   файл   курсора
       bullseye.cur содержит курсор.
                            6.5.2. Добавление новых переменных                 

            Для данной    программы    необходимы    несколько   новых
       переменных.  Поместите  приведенные  ниже  операторы  в  начало
       исходной С-программы:

       char str[255]              /* строковый буфер общего назна-
                                     чения                       */
       HCURSOR hSaveCursor;       /* дескриптор текущего курсора */
       HCURSOR hHourGlass;        /* дескриптор курсора "песочные
                                     часы"                       */
       BOOL bTrack = FALSE;       /* TRUE, если нажата левая
                                     кнопка                      */
       int OrgX = 0, OrgY = 0;    /* начальная позиция курсора   */
       int PrevX = 0, PrevY = 0;  /* текущая позиция курсора     */
       int X = 0, Y = 0;          /* конечная позиция курсора    */
       RECT Rect;                 /* прямоугольник выборки       */
       POINT ptCursor;            /* координаты курсора по осям
                                     x и y                       */
       int repeat = 1;            /* счетчик повторения нажатий
                                     на клавиши                  */

            Переменные hSaveCursor  и  hHourGlass содержат дескрипторы
       курсора,  которые будут использоваться в длительных  операциях.
       Параметр   bTrack   содержит   булевский   флаг,   указывающий,
       выполняется ли выборка.  Переменные OrgX,  OrgY,  PrevX и PrevY
       содержат начальную   и   текущую   позиции  мыши  при  выборке.
       Переменные OrgX,  OrgY,  X и Y содержат  начальную  и  конечную
       координаты   выборки  при  ее  завершении.  Структура  ptCursor
       содержит текущую позицию курсора в  области  пользователя.  Она
       корректируется,  когда  пользователь  нажимает  одну  из клавиш
       стрелок.  Структура  Rect  содержит  текущий   размер   области
       пользователя  и используется для уверенности в том,  что курсор
       остается в области  пользователя.  Переменная  repeat  содержит
       текущее значение счетчика повтора при работе с клавиатурой.
                                                                               
                     6.5.3  Установка курсора класса.

            Для  того,  чтобы  установить курсор класса, необходимо
       модифицировать оператор  в  функции  инициализации.  Другими
       словами,   необходимо   присвоить  дескриптор  курсора  полю
       hCursor структуры класса окна. Необходимо внести изменения в
.
      Windows 3.0/pg/1#3                                       = 113 =

       исходном С-файле. Найдите строку:

            wc.hCursor=LoadCursor(NULL, IDC_ARROW);

            Измените ее:

            wc.hCursor=LoadCursor(hInstance, "bullseye");
                                                                               
             6.5.4  Подготовка курсора в виде песочных часов.

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

            hHourGlass=LoadCursor(NULL, IDC_WAIT);

            Это сделает песочные часы доступными при необходимости.
                             6.5.5  Добавление длительной операции.            

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

      case WM_CHAR:
          if (wParam == '\r') {
              SetCapture(hWnd);

              hSaveCursor = SetCursor(hHourGlass);
                strcpy (str, "Вычисление простых чисел ...");
                InvalidateRect (hWnd, NULL, TRUE);
                UpdateWindow (hWnd);
                wsprintf(str, "Вычислено  %d чисел.        ", sieve());
                InvalidateRect (hWnd, NULL, TRUE);
                UpdateWindow (hWnd);

                SetCursor(hSaveCursor); /*  Восстановить  старый
                                            курсор */
                ReleaseCapture();
            }
            break;

            При нажатии клавиши  Enter  Windows  генерирует  сообщение
       WM_CHAR,  параметр  wParam  которого  содержит  значение в коде
       ANSI,  представляющее код возврата каретки.  Когда функция окна
       получает сообщение WM_CHAR, она контролирует наличие этого кода
       и выполняет  длительную  операцию (функцию sieve).  Эта функция
       названа "Решето Эратосфена" и была приведена в "Byte", номер за
       Январь, 1983 года:

.
      Windows 3.0/pg/1#3                                       = 114 =

            #define NITER 20
            #define SIZE 8190

            char flags[SIZE+1] = { 0};
            sieve() {
                int i,k;
                int iter, count;

                for (iter = 1; iter <= NITER; iter++) {
                     count = 0;
                     for (i = 0; i <= SIZE; i++)
                         flags[i] = TRUE;

                    for (i = 2; i <= SIZE; i++) {
                        if (flags[i] ) {
                            for (k = i + i; k <= SIZE; k += i)
                                flags[k] = FALSE;
                              count++;
                        }
                    }
                }
                return (count);
            }
              6.5.6 Добавление фрагментов WM_LBUTTONDOWN, WM_MOUSEMOVE и       
                                WM_LBUTTONUP

            Для выполнения  выборки можно добавить операторы,  как это
       описано в подразделе  6.3.  "Выборка  с  использованием  мыши".
       Добавьте следующие операторы к функции окна:

      case WM_LBUTTONDOWN:
          bTrack = TRUE;
          PrevX = LOWORD(lParam);
          PrevY = HIWORD(lParam);
          if (!(wParam & MK_SHIFT)) {       /* Если не нажата
                                               клавиша shift */
              OrgX = LOWORD(lParam);
              OrgY = HIWORD(lParam);
          }
          InvalidateRect (hWnd, NULL, TRUE);
          UpdateWindow (hWnd);

          /* Захватить  весь  ввод  от  мыши,  даже  если  она
             находится вне окна */

          SetCapture(hWnd);
          break;

      case WM_MOUSEMOVE:
          {
              RECT        rectClient;
              int         NextX;
.
      Windows 3.0/pg/1#3                                       = 115 =

              int         NextY;

              if (bTrack) {
                  NextX = LOWORD(lParam);
                  NextY = HIWORD(lParam);

                  /* Не рисовать вне области пользователя окна */

                  GetClientRect (hWnd, &rectClient);
                  if (NextX < rectClient.left) {
                      NextX = rectClient.left;
                  } else if (NextX >= rectClient.right) {
                      NextX = rectClient.right - 1;
                  }
                  if (NextY < rectClient.top) {
                      NextY = rectClient.top;
                  } else if (NextY >= rectClient.bottom) {
                      NextY = rectClient.bottom - 1;
                  }

                  /* Если позиция мыши измениласть, то стереть старый  */
                  /* и рисовать новый прямоугольник                    */

                  if ((NextX != PrevX) || (NextY != PrevY)) {
                      hDC = GetDC(hWnd);
                      SetROP2(hDC, R2_NOT);   /* Очистить старый
                                                 прямоугольник */
                      MoveTo(hDC, OrgX, OrgY);
                      LineTo(hDC, OrgX, PrevY);
                      LineTo(hDC, PrevX, PrevY);
                      LineTo(hDC, PrevX, OrgY);
                      LineTo(hDC, OrgX, OrgY);

                      /* Получить текущую позицию курсора */

                      PrevX = NextX;
                      PrevY = NextY;
                      MoveTo(hDC, OrgX,  OrgY);  /* Нарисовать
                                           новый прямоугольник */
                      LineTo(hDC, OrgX, PrevY);
                      LineTo(hDC, PrevX, PrevY);
                      LineTo(hDC, PrevX, OrgY);
                      LineTo(hDC, OrgX, OrgY);
                      ReleaseDC(hWnd, hDC);
                  }
              }
          }
          break;

            case WM_LBUTTONUP:
                bTrack = FALSE;    /* Завершение выборки         */
                ReleaseCapture();  /* освободить   мышь          */
                X = LOWORD(lParam);/* сохранить текущее значение */
.
      Windows 3.0/pg/1#3                                       = 116 =

                Y = HIWORD(lParam);
                break;
                    6.5.7  Добавление фрагмента WM_KEYDOWN и WM_KEYUP.         

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

            Операторы этого  фрагмента должны получить текущую позицию
       курсора и  скорректировать  ее  при  нажатии  одной  из  клавиш
       стрелок. Добавьте следующие операторы к функции окна:

            case WM_KEYDOWN:
                GetCursorPos(&ptCursor);
                if (wParam != VK_LEFT && wParam != VK_RIGHT &&
                    wParam != VK_UP && wParam !=VK_DOWN)
                    break;

                /* преобразовать координаты экрана в координаты области
                   пользователя */

                ScreenToClient(hWnd, &ptCursor);
                repeat++;      /* увеличить счетчик повторений */

                switch (wParam) {

                     /* изменить позицию курсора в соответствии с на-
                        жатой клавишей. Ускорить перемещение, добавляя
                        счетчик повторений к позиции курсора. */

                   case VK_LEFT:
                       ptCursor.x -=repeat;
                       break;
                   case VK_RIGHT:
                       ptCursor.x +=repeat;
                       break;
                   case VK_UP:
                       ptCursor.y -=repeat;
                       break;
                   case VK_DOWN:
                       ptCursor.y +=repeat;
                       break;
                   default:
                       return(NULL);
                }

                  /* Убедиться, что курсор не вышел за пределы области
                     пользователя окна */

                  GetClientRect(hWnd, &Rect);

                  if (ptCursor.x >= Rect.right)
.
      Windows 3.0/pg/1#3                                       = 117 =

                      ptCursor.x = Rect.right - 1;
                  else if (ptCursor.x < Rect.left)
                      ptCursor.x = Rect.left;
                  if (ptCursor.y >= Rect.bottom)
                      ptCursor.y = Rect.bottom - 1;
                  else if (ptCursor.y < Rect.top)
                      ptCursor.y = Rect.top;

                  ClientToScreen(hWnd, &ptCursor);
                  SetCursorPos(ptCursor.x, ptCursor.y);
                  break;

            Функция GetCursorPos  возвращает   положение   курсора   в
       координатах экрана.  Для контроля того,  что курсор находится в
       области пользователя, эти координаты преобразуются в координаты
       пользователя с помощью функции ScreenToClient.  Оператор switch
       контролирует  клавиши  стрелок  и  добавляет  содержимое   поля
       счетчика повторения параметра lParam к текущей позиции.

            Новая позиция  проверяется  на  принадлежность  к  области
       пользователя,    используя   функцию   GetClientRect,   которая
       возвращает  размеры  области  пользователя.  Если   необходимо,
       положение корректируется. Наконец, функция ClientToScreen вновь
       преобразует координаты положения курсора в координаты экрана, а
       функция SetCursorPos устанавливает новую позицию.

            Фрагмент WM_KEYUP    восстанавливает   исходное   значение
       счетчика в тот момент,  когда пользователь  отпускает  клавишу.
       Это делается следующим образом:

              case WM_KEYUP:
                  repeat = 1;           /* Очистить счетчик. */
                  break;

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

              case WM_PAINT:
                  {
                      PAINTSTRUCT     ps;

                      hDC = BeginPaint (hWnd, &ps);
                      if (OrgX != PrevX || OrgY != PrevY) {
                          MoveTo(hDC, OrgX, OrgY);
                          LineTo(hDC, OrgX, PrevY);
                          LineTo(hDC, PrevX, PrevY);
                          LineTo(hDC, PrevX, OrgY);
                          LineTo(hDC, OrgX, OrgY);
                      }
                      TextOut (hDC, 1, 1, str, strlen (str));
                      EndPaint (hWnd, &ps);
.
      Windows 3.0/pg/1#3                                       = 118 =

                  }
                  break;
                                                                               
              6.5.8  Добавьте файл BULLSEYE.CUR к MAKE-файлу.

            В MAKE-файле  добавьте  файл BULLSEYE.CUR к списку файлов,
       от которых зависит  CURSOR.RES.  Соответствующие  строки  будут
       выглядеть следующим образом:

            CURSOR.RES: CURSOR.RC CURSOR.H BULLSEYE.CUR
                 RC -r CURSOR.RC

            Тогда при  изменении  файла  BULLSEYE.CUR  файл CURSOR.RES
       будет перекомпилирован.
                                                                               
                     6.5.9  Трансляция и компоновка.

            Перекомпилируйте и  скомпонуйте  программу  Cursor.  Затем
       запустите Windows и программу Cursor. Когда курсор переместится
       в область пользователя, он примет вид мишени.

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

            Рисунок 6.1.  Выборка в программе Cursor.
            1. Начальная точка.
            2. Конечная точка.

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

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

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

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

            Дополнительную информацию относительно курсоров вы найдете
       в:
.
      Windows 3.0/pg/1#3                                       = 119 =


       Раздел               Руководство
       ---------------------------------------------------------------
       Ввод с использова-   Руководство программиста, Глава 4, "Ввод с
       нием мыши и клавиа-  использованием мыши и клавиатуры"
       туры

       Функции курсора      Справочное руководство, том 1, глава 1,
                            "Функции интерфейса управления окнами",
                            глава 4, "Список функций".

       Сообщения ввода и    Справочное руководство, том 1, глава 5,
       сообщения управле-   "Обзор сообщений", глава 6, "Список сооб-
       ния окнами.          щений".

       Операторы описания   Справочное руководство, том 2, глава 8,
       ресурсов             "Операторы описания ресурсов".

       Использование        "Tools", глава 4, "Создание изображений".
       SDKPaint


.
      Windows 3.0/pg/1#3                                       = 120 =

                                                                               
                              Глава 7.  Меню.
      ----------------------------------------------------------------
            Большинство прикладных  программ  Windows  используют меню
       для того,  чтобы  пользователи  могли   выбрать   команды   или
       действия.

            В данной главе описаны следующие темы:

            - Что такое меню.

            - Определение меню.

            - Включение меню в прикладную программу.

            - Обработка ввода от меню.

            - Модификация существующего меню.

            - Работа со специальными возможностями меню.

            В данной  главе описан процесс создания простой программы,
       EditMenu, которая использует и обрабатывает ввод от меню.
                                           7.1  Что такое меню.                

           Меню - это перечень элементов,  называемых элементами меню,
       которые являются именами или растровыми картами, представляющи-
       ми действия,  которые  может  выполнять  прикладная  программа.
       Пользователь может  заставить программу выполнить команду или с
       помощью "мыши" или с помощью клавиатуры, выбрав соответствующий
       элемент  меню.  Когда  пользователь  выбирает команду,  Windows
       посылает сообщение прикладной программе,  определяя,  какая ко-
       манда была выбрана.

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

            1. Описать  меню  в  файле  описания  ресурсов  прикладной
              программы.

            2. Определить  меню  в  тексте  прикладной программы.  Это
               можно сделать двумя способами:

               - При регистрации класса окна  указать  меню  как  меню
                 класса для всех окон данного класса.

               - Указать  меню  при  создании окна (только для данного
                 окна).

            3. Произвести инициализацию меню, если она требуется.

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

.
      Windows 3.0/pg/1#3                                       = 121 =

            - Пользователь может выбрать команды в меню.

              Когда пользователь  выбирает  команду  (элемент   меню),
              Windows посылает   вашей   программе   сообщение  ввода,
              которое включает идентификатор элемента меню.

            - Ваша прикладная программа может добавлять,  заменять или
              изменять элементы меню или даже все меню, если возникнет
              необходимость.
                                         7.2  Определение меню.                

            Первым шагом при использовании меню необходимо  определить
       меню в  файле  описания  ресурсов  (.RC) прикладной программы с
       помощью оператора MENU. Оператор MENU определяет:

            - Имя меню.

            - Элементы меню.

            - Идентификаторы каждого элемента меню.

            - Текст или растровую карту каждого элемента меню.

            - Специальные атрибуты каждого элемента меню.

            Оператор MENU состоит из имени меню,  ключевого слова MENU
       и пары ключевых слов BEGIN и END, которые заключают между собой
       один или несколько операторов, которые могут быть следующими:

            - Оператор MENUITEM определяет элемент  меню,  его  вид  и
              идентификатор.

              Когда пользователь   выбирает   элементы  меню,  Windows
              сообщает программе о выбранном элементе.

            - Оператор POPUP определяет  накладываемое  меню,  которое
              содержит список элементов накладываемого меню.

              Когда пользователь выбирает накладываемое меню,  Windows
              выводит список  элементов.  Затем   пользователь   может
              выбрать элемент  в  накладываемом  меню.  Затем  Windows
              сообщает программе о выбранном элементе.

            Например следующий оператор MENU определяет меню с  именем
       "SampleMenu":

       (1)  SampleMenu MENU
               BEGIN
       (2)        MENUITEM "Exit!", IDM_EXIT
                  MENUITEM "Recalculate!", IDM_RECALC
       (3)        POPUP "Options"
                     BEGIN
.
      Windows 3.0/pg/1#3                                       = 122 =

       (4)              MENUITEM "Scylla", IDM_SCYLLA
                        MENUITEM "Charybdis", IDM_CHERRYBDIS
                     END
               END

            В данном примере:

       1)   Эта строка  сообщает компилятору ресурсов,  что это начало
            определения меню  с  именем  "SampleMenu".  Оператор  MENU
            состоит из  имени  меню,  ключевого  слова  MENU,  и  пары
            ключевых  слов  BEGIN  и END,  которые заключают операторы
            определения элементов меню.

       2)   Этот оператор  MENUITEM  определяет первый элемент в меню.
            Текст "Exit!" будет первым элементом в  строке  меню.  При
            выборе пользователем  команды  "Exit!"  Windows   посылает
            прикладной   программе   сообщение   WM_COMMAND,   которое
            содержит идентификатор элемента меню в параметре сообщения
            wParam (IDM_EXIT). Следующий оператор MENUITEM аналогичным
            образом определяет элемент "Recalculate!".

       3)   Оператор POPUP  определяет  накладываемое  меню.  В строке
            меню будет присутствовать  строка  "Options".  При  выборе
            пользователем команды    "Options"     Windows     выведет
            накладываемое меню,  в котором пользователь может выбирать
            между командой "Scylla" и "Charybdis".

       4)   Внутри оператора  POPUP  содержатся  определения элементов
            накладываемого меню.  Для  меню "Options" это два элемента
            каждый со своим идентификатором и текстовой строкой.

            При выборе  пользователем  одного  из  элементов  "Exit!",
       "Recalculate!",  "Scylla"  и  "Charybdis",  Windows сообщает об
       этом   прикладной   программе,   передавая   ей   идентификатор
       соответствующего   элемента   меню.  Заметим,  что  Windows  не
       сообщает программе о выборе пользователем  элемента  "Options".
       Вместо этого Windows просто отображает накладываемое меню.

            Дополнительную информацию  об операторах MENU,  MENUITEM и
       POPUP вы найдете во втором томе Справочного руководства.
                                                                               
                        7.2.1  Идентификаторы меню.

            Каждый элемент меню имеет уникальный идентификатор, обычно
       называемый  идентификатором  меню.  Когда пользователь выбирает
       элемент   меню,   Windows   передает    прикладной    программе
       идентификатор  этого  элемента.  Идентификатор меню должен быть
       уникальной константой.  Вы можете определить все идентификаторы
       как  константы  с  помощью  директивы  #define в файле описания
       ресурсов или во включаемом файле. Например:

            #define IDM_EXIT        111
            #define IDM_RECALC      112
.
      Windows 3.0/pg/1#3                                       = 123 =

            #define IDM_SCYLLA      113
            #define IDM_CHARYBDIS   114
            Идентификаторы элементов меню используются для направления
       обработки  команды  в  зависимости  от  идентификатора.   Более
       подробную  информацию  об  обработке ввода от меню вы найдете в
       разделе 7.4 "Обработка ввода от меню".
                                                                               
               7.3  Подключение меню к прикладной программе.

            После того,  как  вы  определили  меню  в  файле  описания
       ресурсов прикладной  программы,  вы  можете включить его в саму
       программу. Вы указываете меню,  связывая  его  с  окном.  Любое
       перекрывающееся или   накладываемое   окно  может  иметь  меню:
       дочернее окно не может  иметь  никакого  меню,  за  исключением
       системного.

            Для подключения  меню  к  прикладной программе имеется два
       метода:

            - Указать меню в  качестве  меню  класса  при  регистрации
              класса окна.  Все  окна этого класса в этом случае будут
              иметь это меню.

            - Указать меню при создании меню.  Это  окно  затем  будет
              иметь меню.

            Ниже описаны оба эти метода.
                                                                               
              7.3.1 Определение меню в качестве меню класса.

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

           wc.lpszMenuName = "SampleMenu";

           В этом  примере  поле  lpszMenuName  -  это часть структуры
       данных wc типа WNDCLASS.  Имя  меню  "SampleMenu"  -  это  имя,
       присвоенное меню в файле описания ресурсов.

           После регистрации  меню  класса  каждое  окно  этого класса
       будет иметь меню класса,  если только это значение по умолчанию
       не будет изменено с помощью явного определения дескриптора меню
       при создании окна данного класса.
                                      7.3.2  Установка меню окна.              

           Окно не  обязано  использовать  меню  класса.  Меню  класса
       используется только по умолчанию.  Для того, чтобы использовать
.
      Windows 3.0/pg/1#3                                       = 124 =

       в окне другое меню, его нужно указать при создании окна.

            Для указания меню окна нужно сделать следующее:

            - Загрузить  меню  из  ресурсов  прикладной  программы   с
              помощью функции   LoadMenu.   Эта   функция   возвращает
              дескриптор меню.

            - При  вызове  функции  CreateWindow  передайте  ей   этот
              дескриптор в качестве параметра hMenu.


            Приведенный ниже  пример  показывает,  как   загрузить   и
       специфицировать меню, используя функцию CreateWindow:

            HWND hWnd;    /* инициализируйте переменную и поместите в
                             нее дескриптор текущего окна.  */
            HMENU hMenu;  /* инициализируйте переменную и поместите в
                             дескриптор меню */
               .
               .
               .
       (1)  hMenu = LoadMenu(hInstance, "SampleMenu");

       (2)  hWnd = CreateWindow("SampleWindow",
                       "SampleWindow",
                       WS_OVERLAPPEDWINDOW,
                       CW_USERDEFAULT,
                       CW_USERDEFAULT,
                       CW_USERDEFAULT,
                       CW_USERDEFAULT,
                       (HWND) NULL,
       (3)             hMenu,
                       hInstance,
                       (LPSTR) NULL);

            В данном примере:

       1)   Функция LoadMenu загружает  меню  с  именем  "SampleMenu".
            Переменная hInstance специфицирует, что ресурс должен быть
            загружен из  ресурсов   прикладной   программы.   LoadMenu
            возвращает дескриптор    меню,    который   помещается   в
            переменную hMenu.

       2)   Программа затем вызывает функцию CreateWindow для создания
            окна с именем SampleWindow.

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

.
      Windows 3.0/pg/1#3                                       = 125 =

                                     7.4  Обработка ввода от меню.             

            При выборе  пользователем  команды в меню Windows посылает
       сообщение WM_COMMAND соответствующей  функции  окна  прикладной
       программы.  Сообщение содержит в параметре wParam идентификатор
       выбранного элемента меню.

            Функция окна  отвечает  за   выполнение   всех   действий,
       связанных с   данной   командой.  Например,  если  пользователь
       выбирает команду "Open", то функция окна запрашивает имя файла,
       открывает его и выводит содержимое в области пользователя окна.

            Чаще всего  ввод из меню обрабатывается в операторе switch
       в функции окна.  Обычно оператор  switch  направляет  обработку
       ввода из меню в зависимости от содержимого wParam.  Каждый case
       обрабатывает свою команду по ее идентификатору.

            Например:

            case WM_COMMAND:
       (1)     switch (wParam)
               {
       (2)     case IDM_NEW:
               /* выполнение операций по созданию нового файла */
               break;
               case IDM_OPEN:
               /* выполнение операций по открытию файла */
               break;
               case IDM_SAVE:
               /* выполнение операций по сохранению файла */
               break;
               case IDM_SAVEAS:
               /* выполнение операций по сохранению файла */
               break;
               case IDM_EXIT:
               /* выполнение операций по выходу из прикладной программы */
               break;
               }
            break;

            В данном примере:

       (1)  Параметр wParam    содержит    идентификатор    выбранного
            пользователем элемента меню.

       (2)  Для каждого  элемента  меню  прикладная  программа  должна
            выполнить соответствующие действия.
                          7.5  Работа с меню из прикладной программы.          

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

.
      Windows 3.0/pg/1#3                                       = 126 =

            - Как разрешить или запретить выбор элемента меню.

            - Как пометить и снять контрольную отметку.

            - Как добавить, изменить или удалить элемент меню.

            - Как использовать в  качестве  элементов  меню  растровые
              карты.

            - Как заменить меню.

            - Как   создать  и  инициализировать  меню  из  прикладной
              программы.

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

            Замечание: При изменении элементов в строке меню вы должны
       вызвать функцию DrawMenuBar для отображения на экране сделанных
       изменений.
                      7.5.1  Доступные и недоступные элементы меню.            

           Обычно все    элементы   меню   доступны;   они   выводятся
       стандартным шрифтом   и   пользователь   может   их    выбрать.
       Недоступный элемент меню отображается нормальным образом, но не
       отвечает на нажатие курсором мыши и клавиатуры.  Элемент  меню,
       выведенный серым цветом,  также не отвечает на нажатие курсором
       мыши и клавиатуры.  Обычно вы делаете элемент  недоступным  или
       выводите  его  серым  цветом,  когда  действие,  за  которое он
       отвечает, неразрешено.  Например,  вы  можете   сделать   серым
       элемент "Print" в меню "File", если принтер не подключен.

                  Установка исходного состояния элементов.

            Можно специфицировать начальное состояние меню или команд,
       использовав параметры INACTIVE и GRAYED с оператором MENUITEM в
       файле  описания ресурсов.  Например,  приведенный ниже оператор
       устанавливает начальное состояние команды Печать как "серое":

            MENUITEM "Print", IDM_PRINT, GRAYED

            Этот параметр применяется только  к  начальному  состоянию
       меню.    Можно    изменить   состояние,   использовав   функцию
       EnableMenuItem в  исходном  С-файле.   Функция   EnableMenuItem
       позволяет сделать элемент доступным, недоступным или серым.

                    Как сделать недоступным элемент меню.

            Недоступный элемент меню выглядит обычным образом,  однако
       не реагирует на "клик" мыши или на выбор с помощью  клавиатуры.
.
      Windows 3.0/pg/1#3                                       = 127 =

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

            EnableMenuItem(hMenu, IDM_SAVE, MF_DISABLED);
            В данном   примере   делается  недоступным  элемент  меню,
       определяемого параметром    hMenu.    Идентификатор    элемента
       IDM_SAVE.  Константа  MF_DISABLED сообщает Windows,  что данный
       элемент должен быть сделан недоступным.

                  Как сделать элемент недоступным и серым.

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

            Чтобы сделать  элемент недоступным и серым надо в качестве
       параметра функции EnableMenuItem указать  константу  MF_GRAYED.
       Например:

            EnableMenuItem(hMenu, IDM_PRINT, MF_GRAYED);

            В данном   примере   делается  недоступной  команда  меню,
       которое определяется параметром hMenu.  Идентификатор  элемента
       меню  IDM_PRINT.  Константа  MF_GRAYED  сообщает  Windows,  что
       данный элемент должен быть сделан недоступным и  выведен  серым
       цветом.

                       Как сделать элемент доступным.

            Чтобы сделать    доступным    недоступный   элемент   меню
       необходимо указать в вызове  функции  EnableMenuItem  константу
       MF_ENABLED.

            В данном примере делается доступным элемент IDM_EXIT:

            EnableMenuItem(hMenu, IDM_EXIT, MF_ENABLED);
                                   7.5.2  Контроль элементов меню.             

            Можно поместить    или    удалить   контрольную   отметку,
       располагающуюся рядом с указанным элементом меню.  Элемент меню
       обычно  контролируется,  когда  он  принадлежит  группе команд,
       взаимно исключающих друг друга.  Контрольная отметка  указывает
       последний выбор пользователя.  Например, в группе, состоящей из
       элементов Left,  Right и Center,  вы  можете  пометить  элемент
       Left, чтобы показать, что он был выбран последним.

                   Установка исходной контрольной отметки.

            Можно поместить  начальную  контрольную  отметку  рядом  с
       командой, используя параметр CHECKED в операторе MENUITEM файла
.
      Windows 3.0/pg/1#3                                       = 128 =

       описания ресурсов.  В данном примере отметка помещается рядом с
       элементом Left:

            MENUITEM "Left", IDM_LEFT, CHECKED

                       Установка контрольной отметки.

            Информация из файла описания ресурсов отражается только на
       исходном состоянии   меню.  Вы  можете  поместить  или  удалить
       контрольную отметку   элемента   меню   во   время   выполнения
       программы, используя функцию CheckMenuItem.

            В приведенном  ниже примере контрольная отметка помещается
       рядом с элементом, ID которого равен IDM_LEFT:

            CheckMenuItem(hMenu, IDM_LEFT, MF_CHECKED);

                        Удаление контрольной отметки.

            Для удаления контрольной  отметки  элемента  вы  вызываете
       функцию  CheckMenuItem и передаете ей значение MF_UNCHECKED.  В
       последующем примере контрольная отметка элемента,  ID  которого
       IDM_RIGHT, удаляется (если она есть):

            CheckMenuItem(hMenu, IDM_RIGHT, MF_UNCHECKED);

            Если изменился  элемент  меню  в  меню-строке,  необходимо
       вызвать функцию DrawMenuBar для индикации изменений.
                                7.5.3  Добавление элементов к меню.            

            Вы можете добавить новые элементы меню в  конец  меню  или
       вставить после определенного элемента.

                          Добавление элемента меню.

            Для добавления  элемента  в  конец  существующего  меню вы
       используете функцию AppendMenu.  Эта  функция  добавляет  новый
       элемент к указанному меню и позволяет вам определить, должен ли
       этот элемент быть доступным,  недоступным, серым и должен ли он
       иметь контрольную отметку.

            Ниже приведен   пример,   в   котором   к   меню  "Fruits"
       добавляется элемент  "Raspberries".  Причем,  если  сейчас   не
       сезон, то данный элемент делается серым и недоступным.

            if (!RaspberriesInSeason)
               AppendMenu(hFruitMenu,
                          MF_GRAYED,
                          IDM_RASPBERRIES,
                          "Raspberries");
            else
               AppendMenu(hFruitMenu,
.
      Windows 3.0/pg/1#3                                       = 129 =

                          MF_ENABLED,
                          IDM_RASPBERRIES,
                          "Raspberries");

                           Вставка элемента меню.

            Для вставки  элемента  в  существующее  меню  используется
       функция InsertMenu.  Эта  функция вставляет указанный элемент в
       указанную позицию и перемещает  последующие  элементы  вниз,  в
       соответствии  с  новым  элементом.  Как  и AppendMenu,  функция
       InsertMenu позволяет вам указать состояние нового элемента.

            В данном примере производится вставка элемента  "Kumquats"
       перед существующим  элементом  "Melons".  Причем  новый элемент
       делается серым и недоступным.

            InsertMenu(hFruitMenu,
                       IDM_MELONS,
                       MF_BYCOMMAND | MF_GRAYED,
                       IDM_KUMQUATS,
                       "Kumquats");

            Вы можете также вставить элемент в определенную позицию, а
       не перед каким-либо элементом.  Ниже приведен пример, в котором
       вставляется элемент "Bananas" таким образом,  что он становится
       третьим элементом в меню "Fruits". (Первый элемент находится на
       позиции 0, второй - 1 и т.д.).

            InsertMenu(hFruitMenu,
                       2,
                       MF_BYCOMMAND | MF_GRAYED,
                       IDM_BANANAS,
                       "Bananas");

                             7.5.4  Модификация существующего меню.            

            Существующее меню  и его элементы можно изменить с помощью
       функции ModifyMenu.  Например,   вы   можете   изменить   текст
       элемента. ModifyMenu позволяет указать и состояние элемента.

            Ниже приведен   пример,  в  котором  текст  элемента  меню
       "Water" меняется  на  "Wine".  Кроме   этого   изменяется   его
       идентификатор.

            ModifyMenu(hMenu,
                       IDM_WATER,
                       MF_BYCOMMAND,
                       IDM_WINE,
                       "Wine");

            При использовании функции ModifyMenu вы сообщаете Windows,
       что необходимо заменить элемент меню новым. Третий, четвертый и
.
      Windows 3.0/pg/1#3                                       = 130 =

       пятый параметры  функции  ModifyMenu определяют атрибуты нового
       элемента.

            Например, ниже  приведен  пример,  в  котором   изменяется
       только текст  элемента  "Wine" на "Cabernet".  Но независимо от
       этого, вы должны заново определить  все  атрибуты  элемента  (в
       данном случае идентификатор элемента).

            ModifyMenu(hMenu,
                       IDM_WINE,
                       MF_BYCOMMAND,
                       IDM_WINE,
                       "Cabernet");

                Выполнение нескольких изменений одновременно.

            При использовании   функции   ModifyMenu   для   изменения
       элемента вы можете  также  поместить  или  удалить  контрольную
       отметку и сделать элемент доступным, недоступным или серым.

            Ниже, в  примере  элемент  "Water"  заменяется  на элемент
       "Wine",  он делается доступным (если он был недоступным), рядом
       с   ним   помещается   контрольная  отметка  и  изменяется  его
       идентификатор.

            ModifyMenu(hMenu,
                       IDM_WATER,
                       MF_BYCOMMAND | MF_ENABLED | MF_CHECKED,
                       IDM_WINE,
                       "Wine");

                                   7.5.5  Удаление элемента меню.              

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

            DeleteMenu(hFruitMenu,    /* дескриптор меню */
                       1,             /* удалить второй элемент */
                       MF_BYPOSITION); /* элемент определяется по его
                                          позиции в меню. */

            В данном примере производится  удаление  второго  элемента
       меню "Fruit".  Все следующие элементы Windows перемещает вверх,
       чтобы заполнить образовавшуюся дыру.

            В следующем  примере  удаляется  тот  же  элемент,  но  он
       определяется не позицией, а его идентификатором:

            DeleteMenu(hFruitMenu,    /* дескриптор меню */
.
      Windows 3.0/pg/1#3                                       = 131 =

                       IDM_ORANGES,   /* удалить элемент "Oranges" */
                       MF_BYCOMMAND); /* элемент определяется по его
                                          идентификатору. */
            7.5.6 Использование в качестве элементов меню растровых карт.      

            Windows позволяет в качестве элементов  меню  использовать
       растровые карты. Это можно сделать двумя способами:

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

            - С помощью функции ModifyMenu изменить элемент так, чтобы
              он отображался в виде растровой карты.

            Вы не можете указать элемент меню в виде растровой карты в
       файле описания ресурсов (.RC).

            В следующем  примере загружается растровая карта "Apples",
       и затем  функция  ModifyMenu  используется  для  замены  текста
       команды "Apple" на растровую карту с изображением яблока.

            HMENU   hMenu;
            HBITMAP hBitmap;
               .
               .
               .
       (1)  hBitmap = LoadBitmap(hInstabce, "Apples");

       (2)  hMenu = GetMenu(hWnd);
            ModifyMenu(hMenu,
       (3)             IDM_APPLES,         /* заменяемый элемент */
       (4)             MF_BYCOMMAND | MF_BITMAP,
       (5)             IDM_APPLES,   /* идентификатор нового элемента */
       (6)             (LPSTR) MAKELONG (hBitmap,0));

            В данном примере:

       1)   Функция LoadBitmap загружает растровую карту  из  файла  и
            возвращает   дескриптор  растровой  карты,  сохраняемый  в
            переменной hBitMap.

       2)   Функция GetMenu получает дескриптор меню текущего  окна  и
            помещает его  в  переменную  hMenu.  Эта  переменная затем
            используется как  первый   параметр   в   вызове   функции
            ModifyMenu, который определяет изменяемое меню.

       3)   Второй параметр   функции   ModifyMenu,  в  данном  случае
            IDM_APPLES, который определяет изменяемый элемент меню.

       4)   Третий параметр   определяет,  как   должны    выполняться
            изменения. MF_BYCOMMAND сообщает Windows,  что  изменяемый
.
      Windows 3.0/pg/1#3                                       = 132 =

            элемент определяется   идентификатором,   а   не  номером.
            MF_BITMAP сообщает,  что новый элемент должен выводиться в
            виде растровой карты а не текста.

       5)   Четвертый параметр  функции  ModifyMenu  определяет  новый
            идентификатор элемента,   IDM_APPLES.   В   данном  случае
            идентификатор не изменяется.

       6)   Дескриптор растровой  карты  посылается  в  старшем  слове
            пятого параметра функции ModifyMenu. MAKELONG создает 32-х
            разрядное значение,  комбинируя  16-разрядный дескриптор и
            16-разрядную константу.  Преобразование этого числа к типу
            LPSTR предотвращает выдачу предупреждения, т.к. компилятор
            подразумевает, что в данном параметре передается строка.
                                             7.5.7  Замена меню.               

           Можно заменить  меню  окна  с помощью функции SetMenu.  Эта
       функция  обычно  используется,   когда   прикладная   программа
       изменяет режимы и  для  нее  необходим  полностью  новый  набор
       команд.  Например,  прикладная  программа  может  заменить меню
       электронной  таблицы  на  меню  графики,   когда   пользователь
       переключает режим на графику.

           В приведенном  ниже  примере  функция  GetMenu   возвращает
       дескриптор меню   электронной  таблицы  из  указанного  окна  и
       сохраняет его для последующего восстановления.  Функция SetMenu
       заменяет его  на  меню   графики,   загружаемое   из   ресурсов
       прикладной программы.

            HMENU hMenu;
            HMENU hSpreadsheetMenu;
               .
               .
               .
            hOldMenu = GetMenu(hWnd);
            hMenu = LoadMenu(hInstance, "ChartMenu");
            SetMenu(hWnd, hMenu);
                .
                .
                .

           Меню может также загружаться из ресурсов,  не принадлежащих
       данной прикладной   программе  (с  помощью  дескриптора  модуля
       библиотеки).
                                     7.5.8  Создание нового  меню.             

            Вы можете создать новое меню во время выполнения программы
       с помощью функции CreateMenu. Функция CreateMenu создает новое,
       пустое меню.  Вы  можете  затем  добавить  элементы,  используя
       функции AppendMenu и InsertMenu.

.
      Windows 3.0/pg/1#3                                       = 133 =

            Следующий пример   создает  пустое  накладываемое  меню  и
       добавляет его к меню окна.  Затем к  данному  меню  добавляются
       элементы.

            HMENU hWinMenu;
            HMENU hVeggieMenu;
               .
               .
               .
            hVeggieMenu = CreateMenu();

            AppendMenu(hWinMenu,
                       MFPOPUP | MF_ENABLED,
                       hVeggieMenu,
                       "Veggies");

            AppendMenu(hVeggieMenu,
                       MF_ENABLED,
                       IDM_CELERY,
                       "Celery");

            AppendMenu(hVeggieMenu,
                       MF_ENABLED,
                       IDM_LETTUCE,
                       "Lettuce");

            AppendMenu(hVeggieMenu,
                       MF_ENABLED,
                       IDM_PEAS,
                       "Peas");
                                      7.5.9  Инициализация меню.               

             Если нужно,    ваша    прикладная     программа     может
       инициализировать меню  перед  тем,  как  Windows отобразит его.
       Хотя вы определяете исходное состояние элементов меню  в  файле
       описания ресурсов прикладной программы,  это не помогает,  если
       исходное состояние   должно  быть  другим.  Например,  если  вы
       хотите,  чтобы команда "Print"  делалась  недоступной,  если  в
       системе нет принтера, то это необходимо сделать только во время
       инициализации меню.  (Делать  это  в  файле  описания  ресурсов
       прикладной программы бессмысленно,  т.к. вы не знаете, будет ли
       подключен принтер к системе в тот момент,  когда будет работать
       ваша программа.)

             Windows посылает  сообщение  WM_INITMENU  функции   окна,
       обладающего  меню,  сразу перед индикацией меню.  Это позволяет
       функции окна проверить  и  изменить  состояние  элементов  меню
       перед  его индикацией.  В приведенном ниже примере функция окна
       обрабатывает  сообщение  WM_INITMENU,  устанавливая   состояние
       команды,  основываясь  на  значении  переменной wChecked:

            WORD wChecked;
.
      Windows 3.0/pg/1#3                                       = 134 =

                .
                .
                .
       (1)  case WM_INITMENU:
       (2)      if (GetMenu(hWnd) != wParam)
                    break;
                CheckMenuitem(wParam, IDM_LEFT,
                    IDM_LEFT == wChecked ? MF_CHECKED : MF_UNCHECKED);
                CheckMenuitem(wParam, IDM_CENTER,
                    IDM_CENTER == wChecked ? MF_CHECKED : MF_UNCHECKED);
                CheckMenuitem(wParam, IDM_RIGHT,
                    IDM_RIGHT == wChecked ? MF_CHECKED : MF_UNCHECKED);
                break;

       1)   Сообщение WM_INITMENU передает  заданный  дескриптор  меню
            параметру wParam.

       2)   Для того,  чтобы  быть уверенным,  что индицируемое меню -
            это действительно меню окна,  функция  GetMenu  возвращает
            дескриптор  текущего меню,  который сравнивается с wParam.
            Если  они   не   равны,   меню   окна   не   должно   быть
            инициализировано.  В  противном  случае можно использовать
            функцию CheckMenuItem для инициализации команд меню.
                                  7.6  Специальные возможности меню.           

            До сих пор мы обсуждали стандартные меню, которые выпадают
       из строки меню и содержат элементы,  которые пользователь может
       выбирать, используя  мышь  или  клавиатуру.  Однако  кроме этих
       возможностей Windows предоставляет дополнительные:

            - Клавиши-ускорители,   которые   позволяют   с    помощью
              клавиатуры ускорить выбор элементов меню.

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

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

            - Собственные  контрольные  пометки,  что  позволяет   вам
              определить собственные  растровые  карты,  которые будут
              использоваться в  качестве  контрольных  пометок  вместо
              стандартных.

            Оставшаяся часть    данного    раздела   будет   посвящена
       обсуждению этих возможностей.
                                     7.6.1  Клавиши - ускорители.              

            Клавиши-ускорители -  это   клавиши,   которые   позволяют
       выбрать в  меню  команду,  используя  единственное  нажатие  на
.
      Windows 3.0/pg/1#3                                       = 135 =

       клавишу.  Например,  в прикладной программе для выбора  команды
       "Delete"  можно  использовать  просто  нажатие  на клавишу DEL.
       Клавиши-ускорители  являются  частью  файла  описания  ресурсов
       прикладной  программы  и  помещаются  в программу в ее исходный
       текст.

            Для использования клавиш-ускорителей  в  вашей  прикладной
       программе вам нужно:

            1. В файле описания ресурсов прикладной программы, указать
               клавиши ускорители в операторах MENUITEM.

            2. В  файле  описания  ресурсов  прикладной  программы  вы
               должны указать таблицу ускорителей. Таблица ускорителей
               содержит клавиши-ускорители   и   соответствующие    им
               идентификаторы элементов меню. Вы создаете ее с помощью
               оператора ACCELERATORS.

            3. В  тексте  программы   необходимо   загрузить   таблицу
               ускорителей с помощью функции LoadAccelerators.

            4. Изменить  цикл обработки сообщений прикладной программы
               так, чтобы    в     нем     производилась     обработка
               клавиш-ускорителей.

            Ниже это все описано в деталях.

               Добавление ускорителей к тексту элементов меню.

            В тексте   элемента  меню  необходимо  указать  ускоритель
       данной команды   для   того,   чтобы   пользователь   мог   его
       использовать. Добавьте  их  названия  к тексту элементов меню в
       операторах MENUITEM  в  файле  описания   ресурсов   прикладной
       программы (.RC).

            Например, предположим,  что  в  вашей прикладной программе
       определено следующее накладываемое меню:

            GroceryMenu MENU
               POPUP             "&Meats"
               BEGIN
                   MENUITEM      "&Beef\tF9",           IDM_BEEF
                   MENUITEM      "&Chicken\tShift+F9",  IDM_CHICKEN
                   MENUITEM      "&Lamb\tCtrl+F9",      IDM_LAMB
                   MENUITEM      "&Pork\tAlt+F9",       IDM_PORK
               END
            END

            Накладываемое меню  "Meats"  содержит   четыре   элемента:
       Beefs,  Chicken,  Lamb и Pork.  Текст каждого элемента содержит
       мнемонику,   выделяемую    амперсандом    (&),    и    название
       клавиши-ускорителя,  отделенное  символом табуляции (\t).  Если
       команда имеет клавишу-ускоритель,  то она  должна  иметь  такой
.
      Windows 3.0/pg/1#3                                       = 136 =

       вид.  В  данном  примере  используются клавиши-ускорители:  F9,
       SHIFT-F9, CTRL-F9 и ALT-F9.

                        Создание таблицы ускорителей.

            Для использования  клавиш-ускорителей  добавьте   в   файл
       описания  ресурсов  прикладной  программы  таблицу ускорителей,
       используя  оператор  ACCELERATORS.  Этот  оператор   определяет
       список  клавиш-ускорителей и соответствующих им идентификаторов
       элементов меню.  В  операторе  ACCELERATORS,  как  и  в  других
       операторах   определения   ресурсов,  BEGIN  определяет  начало
       описания, а END его конец. Например:

            GroceryMenu ACCELERATORS
               BEGIN
                  VK_F9,     IDM_BEEF,    VIRTKEY
                  VK_F9,     IDM_CHICKEN, VIRTKEY, SHIFT
                  VK_F9,     IDM_LAMB,    VIRTKEY, CONTROL
                  VK_F9,     IDM_PORK,    VIRTKEY, ALT
               END

            В данном примере определены четыре клавиши-ускорителя,  по
       одному для  каждой  команды.  Первая  клавиша-ускоритель  - это
       ппросто клавиша F9,  остальные - это комбинации этой клавиши  и
       клавиш SHIFT, ALT и CONTROL.

            Клавиши-ускорители определяются   с   помощью  виртуальных
       кодов клавиш Windows,  что указывается ключевым словом VIRTKEY.
       Виртуальные коды   клавиш   -   это  независимые  от  устройств
       значения, которые Windows преобразует для  каждого  компьютера.
       Это позволяет  гарантировать,  что  на  всех  компьютерах будут
       использоваться те же клавиши,  не зависимо от их действительных
       кодов. Однако   вы   можете   использовать   коды   ASCII,  что
       указывается ключевым словом ASCII.

            Оператор ACCELERATORS    присваивает    клавишу-ускоритель
       каждому идентификатору элемента меню. В нашем примере константы
       IDM_BEEF, IDM_CHICKEN,    IDM_LAMB    и    IDM_PORK    являются
       идентификаторами элементов  меню  Grocery.  Когда  пользователь
       нажимает клавишу-ускоритель,   идентификатор   элемента    меню
       посылается функции окна.

                        Загрузка таблицы ускорителей.

            Как и любой другой ресурс,  таблицу ускорителей необходимо
       загрузить до  того,  как  ее  можно  будет  использовать.   Для
       загрузки таблицы      ускорителей      используется     функция
       LoadAccelerators. Эта  функция  получает  дескриптор   текущего
       экземпляра  прикладной  программы  и  имя  таблицы  ускорителей
       (определяется в файле описания ресурсов прикладной программы
       .RC). Она возвращает дескриптор таблицы ускорителей для данного
       меню. Обычно  таблица  ускорителей  для  меню  загружается  при
       создании окна,  содержащего  данное  меню,  т.е.  при обработке
.
      Windows 3.0/pg/1#3                                       = 137 =

       сообщения WM_CREATE  в функции окна:

            HANDLE hInstance;     /* дескриптор текущего экземпляра */
            HANDLE hAccTable;     /* дескриптор таблицы ускорителей */
               .
               .
               .
            case WM_CREATE:
       (1)    hAccTable = LoadAccelerators(hInstance,"GroceryMenu);
              break;

            В данном примере:

       1)   Этот оператор  загружает  таблицу  ускорителей  для   меню
            GroceryMenu в   память.   Ее   дескриптор   помещается   в
            переменную hAccTable.   Переменная   hInstance    содержит
            дескриптор текущего экземпляра программы.


         Изменение цикла обработки  сообщений  для  обработки  кла-
                              виш-ускорителей.

            Для обработки  таблицы  ускорителей  вы  должны добавить в
       цикл обработки сообщений  функцию  TranslateAccelerator.  Когда
       цикл   обработки   сообщений   получает  сообщение  о  вводе  с
       клавиатуры, содержащее           клавишу           ускорителей,
       TranslateAccelerator   преобразует   сообщение   в    сообщение
       WM_COMMAND,  содержащее  идентификатор элемента меню для данной
       клавиши-ускорителя, и посылает это сообщение WM_COMMAND функции
       окна.

            Цикл обработки сообщений должен проверять каждое сообщение
       на клавишу-ускоритель.  Если она  есть,  то  и  цикл  обработки
       сообщений  должен  преобразовать и передать сообщение с помощью
       функции  TranslateAccelerator.  Если  сообщение   не   содержит
       клавишу   ускоритель,   то   сообщение  обрабатывается  обычным
       способом.

            Замечание: Функция TranslateAccelerator также  преобразует
       ускорители для  команд  системного  меню.  В  этих  случаях эти
       сообщения преобразуются к типу WM_SYSCOMMAND.

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

            while(GetMessage(&msg, NULL, NULL, NULL)) {
       (1)     if(!TranslateAccelerator(hWnd,hAccTable,&msg))
               {
       (2)        TranstateMessage(&msg);
                  DispatchMessage(&msg);
               }
            }

.
      Windows 3.0/pg/1#3                                       = 138 =

       1)   Этот оператор  выполняет  проверку  на клавишу-ускоритель.
            Дескриптор окна, hWnd, определяет окно, сообщения которого
            транслируются. Этот  дескриптор  должен  определять  окно,
            содержащее меню   с   ускорителями.   Дескриптор   таблицы
            ускорителей, hAccTable,  определяет  таблицу  ускорителей,
            используемую для трансляции.

            Если сообщение генерируется с использованием  ускорителей,
            функция TranslateAccelerator  преобразует  нажатие клавиши
            в сообщение   WM_COMMAND,    содержащее    соответствующий
            идентификатор элемента   меню,   и   затем   посылает  это
            сообщение функции окна.

       2)   Если сообщение  не  содержит  ускорители,  то   прикладная
            программа обрабатывает   его   обычным   путем,  используя
            функции TranslateMessage и DispatchMessage.
                                7.6.2  Использование каскадных меню.           

            Windows позволяет иметь больше одного уровня накладываемых
       меню. Такие   многоуровневые   накладываемые   меню  называются
       каскадными. Такая структура меню позволяет минимизировать число
       команд в отдельном накладываемом меню без использования панелей
       диалога.

            Рисунок 7.1  Пример каскадного меню.

            В данном примере пользователь выбирает меню  "Software"  и
       затем выбирает  в нем команду "Languages".  В этой точке справа
       от  курсора  возникает  меню  "Languages".  Затем  пользователь
       перемещает  курсор  по  этому  меню и выбирает "C".  Появляется
       накладываемое меню "C",  в котором пользователь  может  выбрать
       или "C версии 5.1", или "Quick C".

            Каскадное меню  - это просто вложенные накладываемые меню.
       Описание меню для примера на  рисунке  7.1  выглядит  следующим
       образом:

            MenuMenu MENU
            BEGIN
               .
               .
               .
               POPUP "&Software"
               BEGIN

                  POPUP "&Word Processing"
                  BEGIN
                     MENUITEM "&Word 5.0", IDM_WORD
                     MENUITEM "W&rite", IDM_WRITE
                  END

                  POPUP "&Spreadsheet"
.
      Windows 3.0/pg/1#3                                       = 139 =

                  BEGIN
                     MENUITEM "&Microsoft Excel", IDM_EXCEL
                     MENUITEM "&1+2=4", IDM_124
                  END

                  POPUP "&Languages"
                  BEGIN
                     POPUP "&C"
                     BEGIN
                        MENUITEM "C &5.1", IDM_C51
                        MENUITEM "&Quick C", IDM_QUICKC
                     END
                     MENUITEM "Quick &Basic", IDM_QUICKBASIC
                     MENUITEM "&Pascal", IDM_PASCAL
                  END
               END
               .
               .
               .
            END

            Замечание: Каскадное   накладываемое   меню   имеет   свой
       собственный дескриптор.  Поэтому для работы  с  его  элементами
       необходимо вначале  получить  его  дескриптор с помощью функции
       GetSubMenu.
                    7.6.3  Использование плавающих накладываемых меню.         

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

            Для работы  с   плавающими   меню   используются   функции
       CreatePopupMenu и   TrackPopupMenu.   Если   вы  хотите,  чтобы
       плавающее меню появлялось при нажатии пользователем клавиши  на
       клавиатуре или  мыши,  то  создайте  накладываемое  меню внутри
       фрагмента, обрабатывающего данное событие.

            Ниже приведен пример,  в  котором  отображение  плавающего
       меню происходит,  когда  пользователь  нажимает  правую  кнопку
       мыши:

            POINT CurrentPoint;
               .
               .
               .
            case WM_RBUTTONDOWN:
               {
                  HWND hWnd;        /* дескриптор текущего окна */
                  HMENU hFloatingPopup;  /* дескриптор плавающего меню */
       (1)        CurrentPoint = MAKEPOINT (lParam);
.
      Windows 3.0/pg/1#3                                       = 140 =

                       /* точка, в которой пользователь нажал на правую
                          кнопку мыши */
                    .
                    .
                    .
       (2)        hFloatingPopup = GreatePopupMenu();

       (3)        AppendMenu(hFloatingPopup,
                             MF_ENABLED,
                             IDM_CALC,
                             "Calculator");

                  AppendMenu(hFloatingPopup,
                             MF_ENABLED,
                             IDM_CARDFILE,
                             "Cardfile");

                  AppendMenu(hFloatingPopup,
                             MF_ENABLED,
                             IDM_NOTEPAD,
                             "Notepad");

       (4)        ClientToScreen(hWnd,(LPPOINT)&CurrentPoint);

       (5)        TrackPopupMenu(hFloatingPoint,
                                 NULL,
       (6)                       CurrentPoint.x,
                                 CurrentPoint.y,
                                 NULL,
                                 hWnd,
                                 NULL);

       (7)        DestroyMenu(hFloatingPopup);

                  break;
               }

            В данном примере:

       1)   Параметр lParam сообщения WM_RBUTTONDOWN содержит  текущую
            позицию курсора   мыши.   Функция   MAKEPOINT  преобразует
            длинное целое значение в структуру,  содержащую координаты
            точки, в данном случае CurrentPoint.

       2)   Функция CreatePopupMenu создает пустое накладываемое меню
            и возвращает   дескриптор   этого  меню.  Этот  дескриптор
            помещается в переменную hFloatingPopup.

       3)   После создания   пустого   меню   прикладная    программа
            добавляет к нему три элемента:  "Calculator", "CardFile" и
            "Notepad".

       4)   Функция ClientToScreen  преобразует   текущие   координаты
.
      Windows 3.0/pg/1#3                                       = 141 =

            курсора таким образом,  чтобы они вычислялись относительно
            левого верхнего угла экрана.  (В начале координаты курсора
            вычисляются  относительно  левого  верхнего  угла  области
            пользователя).

       5)   После того,  как меню подготовлено,  программа  отображает
            его на экране с помощью функции TrackPopupMenu.

       6)   Поля x  и  y  структуры  CurrentPoint  содержат координаты
            курсора относительно начала экрана.

       7)   После того,  как  пользователь  произвел  выбор  в   меню,
            прикладная программа  разрушает  меню  и  очищает  память,
            которую  оно  использовало.  Прикладная  программа создает
            данное меню заново при каждом нажатии пользователем правой
            кнопки мыши.
                      7.6.4  Создание собственных контрольных отметок.         

            Обычно, после того,  как вы выбрали элемент меню,  Windows
       отображает после текста  этого  элемента  контрольную  отметку.
       Элемент   меню,   который   не   помечается,  вообще  не  имеет
       контрольной отметки.

            Однако вы можете указать растровую  карту,  которая  будет
       использоваться вместо  стандартной контрольной отметки Windows.
       Вы можете  указать  также  растровую   карту,   которой   будет
       помечаться невыбранный элемент.

            Собственные контрольные  отметки могут помочь пользователю
       различать команды  меню,  выполняющие  некоторые  действия,   и
       команды, которые  могут быть отмечены,  но не отмечены в данный
       момент.  Некоторые  прикладные  программы  Windows   используют
       следующие соглашения:

.
      Windows 3.0/pg/1#3                                       = 142 =


       Тип элемента меню        Соглашение
       ---------------------------------------------------------------
       Элемент меню, выполняю-  Не отображает контрольную отметку для
       щий некоторые действия   таких элементов
       (например, отображает
       другое меню или панель
       диалога).

       Отмеченный в настоящий   Отображает или стандартную отметку
       момент элемент меню      Windows, или собственную контрольную
                                отметку. Когда пользователь еще раз
                                выбирает этот элемент, удаляет конт-
                                рольную отметку.

       Элемент, который может   Отображает собственную контрольную
       быть помечен, но в нас-  отметку. Когда пользователь отмечает
       тоящий момент не отме-   или удаляет контрольную отметку, вы-
       чен.                     водит или стандартную контрольную от-
                                метку Windows, или другую собственную
                                контрольную отметку.
       ---------------------------------------------------------------

            Чтобы создать собственную контрольную отметку:

            1. С  помощью  SDKPaint создайте растровую карту,  которая
               будет использоваться как контрольная отметка.

               Windows требует,  чтобы такая контрольная отметка имела
               ту же  размерность,  что  и стандартная.  Хотя во время
               выполнения  программа  может  растягивать   и   сжимать
               растровую   карту   до  нужного  размера,  лучше  всего
               начинать  с  точного   размера.   (Размер   стандартной
               контрольной отметки  зависит  от  типа  дисплея и может
               быть       получен       с       помощью        функции
               GetMenuCheckMarkDimensions.)

               Кроме этого, вы можете создать растровую карту вручную,
               как это описано в главе 11 "Растровые карты".

            2. В файле описания ресурсов прикладной программы объявите
               каждую растровую карту с  помощью  оператора  BITMAP  и
               файла, содержащего саму растровую карту. Например:

               BitmapChecked BITMAP CHECK.BMP
               BitmapNotChecked BITMAP NOCHECK.BMP

            3. В  программе  загрузите  растровые  карты  из  ресурсов
               прикладной программы с помощью функции LoadBitmap.

            4. Используя  функцию  GetMenuCheckMarkDimensions получите
               размер стандартной  контрольной  отметки  для   данного
               дисплея.
.
      Windows 3.0/pg/1#3                                       = 143 =


            5. При необходимости растяните или сожмите растровые карты
               до нужного размера с помощью функции StreckBlt.

            6. Для  указания  для  каждого  элемента  меню контрольной
               отметки используйте функцию SetMenuItemBitmap.

            7. Перед завершением вашей программы необходимо  разрушить
               растровые карты,  чтобы  освободить память,  занимаемую
               ими.

            Следующий пример демонстрирует,  как  указать  собственную
       контрольную отметку для элемента меню:

            SetMenuItemBitmaps  (hMenu,         /* дескриптор меню */
                                 0,             /* позиция эл-та меню */
                                 MF_BYPOSITION,
                                 hbmCheckOff,   /* для не отмеченного */
                                 hbmCheckOn);   /* для отмеченного */
                      7.6.5  Использование меню, рисуемых владельцем.          

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

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

            Вы не  можете  описать  меню,  рисуемое владельцем в файле
       описания ресурсов прикладной программы (.RC).  Вместо этого  вы
       должны создать новое меню или модифицировать старое,  используя
       флаг  MF_OWNERDRAW.  Для  указания  элементов  меню,   рисуемых
       владельцем, вы можете использовать следующие функции:

            - AppendMenu

            - InsertMenu

            - ModifyMenu

            При вызове   любой   из   этих  функций  вы  передаете  ей
       32-битовое значение  в  качестве   параметра   lpNewItem.   Это
       32-битовое   значение   может  представлять  любую  инофрмацию,
       необходимую для рисования элемента вашей программой, и доступно
       вашей  программе  при рисовании элемента.  Например,  оно может
       содержать указатель на структуру  данных.  Структура  данных  в
       свою  очередь  может  содержать строку и дескриптор логического
.
      Windows 3.0/pg/1#3                                       = 144 =

       шрифта,  который  должен  использоваться  для  вывода   данного
       элемента.

            Перед первым отображением такого элемента Windows посылает
       окну, которому    принадлежит    данное     меню,     сообщение
       WM_MEASHUREITEM. Это  сообщение  в  параметре  lParam  содержит
       указатель на  структуру  MEASUREITEMSTRUCT,  которая  описывает
       элемент меню  и содержит необязательное 32-битовое значение для
       данного элемента.  При получении данного  сообщения  прикладная
       программа   должна   перед  возвратом  из  обработки  сообщения
       заполнить  поля  itemWidth  и   itemHeight   структуры   данных
       MEASUREITEMSTRUCT. Windows  использует  данную  информацию  для
       определения прямоугольника,  в котором программа будет рисовать
       данный   элемент,   а   также  для  определения  взаимодействия
       пользователя с элементом.

            При возникновении  необходимости  вывести  данный  элемент
       (например, когда    он    отображается   впервые,   или   когда
       пользователь выбирает данный элемент),  Windows посылает  окну,
       которому принадлежит   данное   меню,   сообщение  WM_DRAWITEM.
       Параметр lParam этого сообщения содержит указатель на структуру
       данных  DRAWITEMSTRUCT.  Как  и  структура  MEASHUREITEMSTRUCT,
       DRAWITEMSTRUCT содержит  информацию,  идентифицирующую  элемент
       меню и  его  необязательное  32-битовое значение.  Кроме этого,
       структура  DRAWITEMSTRUCT  содержит  флаг,  который  определяет
       состояние  элемента  (такое как серый или отмеченный),  а также
       ограничивающий  его  прямоугольник  и  контекст  устройства,  с
       помощью  которого  ваша  прикладная  программа  будет  рисовать
       данный элемент.

            При получении  сообщения   WM_DRAWITEM   перед   возвратом
       управления ваша программа должна выполнить следующие действия:

            1. Определить тип рисования, которое необходимо выполнить.
               Для этого  протестируйте  поле   itemAction   структуры
               DRAWITEMSTRUCT.

            2. Нарисуйте   соответствующий   элемент  меню,  используя
               прямоугольник и  контекст   устройства   из   структуры
               DRAWITEMSTRUCT. Ваша  программа  может  рисовать только
               внутри этого   прямоугольника.   Чтобы   не    ухудшать
               характеристики, Windows    не   обращает   изображение,
               выходящее за пределы прямоугольника.

            3. Восстановите все объекты GDI,  выбранные для  контекста
               устройства элемента меню.

            Например, если  выбран  элемент меню,  Windows присваивает
       полю itemActions  структуры  данных   DRAWITEMSTRUCT   значение
       ODA_SELECT и  устанавливает  бит  ODS_SELECTED  поля itemState.
       Таким образом ваша программа должна перерисовать элемент, чтобы
       показать, что он выбран.

.
      Windows 3.0/pg/1#3                                       = 145 =

                          7.7  Пример прикладной программы: EditMenu.          

            Программа EditMenu  иллюстрирует  использование  следующих
       элементов:

            - Двух часто используемых меню: Edit и File.

            - Клавиш-ускорителей.

            Замечание: Ускорители,  показанные   в   данном   примере,
       специально  зарезервированы  для  использования  в  меню  Edit.
       Стандартные   ускорители   описаны   в    System    Application
       Architecture,  Common  User  Access:  Advanced Interface Design
       Guide.

            Для создания программы EditMenu скопируйте и  переименуйте
       файлы с программой Generic. Затем выполните следующее:

            - Добавьте  меню  Edit  и  File  к файлу описания ресурсов
              прикладной программы.

            - Добавьте описания во включаемый файл.

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

            - Добавьте новые переменные.

            - Загрузите таблицу ускорителей.

            - Модифицируйте цикл обработки сообщений.

            - Модифицируйте фрагмент WM_COMMAND.

            - Откомпилируйте и скомпонуйте программу.

            EditMenu не показывает,  как работать с системным буфером.
       Эта задача описана в главе 13, "Системный буфер".

            Вместо того, чтобы вводить тексты, приведенные в следующих
       разделах, возможно вам будет удобнее просто переписать исходные
       тексты из SDK.
                7.7.1  Добавление новых меню к файлу описания ресуросов.       

            Вам необходимо добавить к оператору MENU  следующие  меню:
       File и  Edit.  Оператор  MENU  будет теперь выглядеть следующим
       образом:

       EditMenuMenu MENU
       BEGIN
          POPUP        "&File"
          BEGIN
.
      Windows 3.0/pg/1#3                                       = 146 =

              MENUITEM   "&New",                IDM_NEW
              MENUITEM   "&Open...",            IDM_OPEN
              MENUITEM   "&Save",               IDM_SAVE
              MENUITEM   "Save &As...",         IDM_SAVEAS
              MENUITEM   "&Print",              IDM_PRINT
              MENUITEM   SEPARATOR
              MENUITEM   "E&xit",               IDM_EXIT
              MENUITEM   SEPARATOR
              MENUITEM   "&About EditMenu...",  IDM_ABOUT
          END

          POPUP        "&Edit"
          BEGIN
              MENUITEM    "&Undo\tAlt+BkSp",    IDM_UNDO   ,GRAYED
              MENUITEM    SEPARATOR
              MENUITEM    "Cu&t\tShift+Del",    IDM_CUT
              MENUITEM    "&Copy\tCtrl+Ins",    IDM_COPY
              MENUITEM    "&Paste\tShift+Ins",  IDM_PASTE  ,GRAYED
              MENUITEM    "&Delete\tDel",       IDM_CLEAR  ,GRAYED
          END
      END

            Меню "File" содержит семь команд и два разделителя. Каждая
       команда имеет мнемонику,  которая выделяется символом амперсанд
       ("&").

            Меню "Edit" содержит пять  команд  и  разделитель.  Каждая
       команда имеет  и мнемонику,  и ускоритель,  отделенный от имени
       команды символом табуляции (\t). Если команда имеет ускоритель,
       она должна отображаться таким образом. В меню Edit используются
       ускорители:     ALT+BACKSPACE,     DELETE,      CONTROL+INSERT,
       SHIFT+INSERT, SHIFT+DELETE.    Разделитель    помещает    между
       командами "Undu" и "Cut"  горизонтальную  черту.  Рекомендуется
       использовать  разделитель  между  командами,  которые  не имеют
       ничего  общего.  Например,  "Undo"  влияет  на  всю  прикладную
       программу, в  то  время  как  все  остальные  команды влияют на
       системный буфер.

            Примечание: Назначение и содержимое меню "Edit"  и  "File"
       описаны в "System Application Architecture, Common User Access:
       Advanced Interface Design Guide.
                     7.7.2  Добавление определений во включаемый файл.         

            Вы должны объявить во включаемом файле идентификаторы всех
       элементов меню.  Эти  константы  будут использоваться в файле с
       исходным текстом программы  на  языке  С  и  в  файле  описания
       ресурсов прикладной программы.

            Идентификатором элемента   меню  может  быть  любое  целое
       значение. Единственное ограничение заключается в том,  что  это
       число должно быть уникальным в данном меню: не должно быть двух
       команд меню с одинаковыми идентификаторами.
.
      Windows 3.0/pg/1#3                                       = 147 =


            Добавьте следующее во включаемый файл:

            #define IDM_ABOUT 100

            /* идентификаторы элементов меню File */

            #define     IDM_NEW      101
            #define     IDM_OPEN     102
            #define     IDM_SAVE     103
            #define     IDM_SAVEAS   104
            #define     IDM_PRINT    105
            #define     IDM_EXIT     106

            /* идентификаторы элементов меню Edit */

            #define     IDM_UNDO     200
            #define     IDM_CUT      201
            #define     IDM_COPY     202
            #define     IDM_PASTE    203
            #define     IDM_CLEAR    204
              7.7.3 Добавление   к   файлу   описания  ресурсов  таблицы       
                                ускорителей.

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

            EditMenuAcc ACCELERATORS
            BEGIN
                VK_BACK,   IDM_UNDO,  VIRTKEY, ALT
                VK_DELETE, IDM_CUT,   VIRTKEY, SHIFT
                VK_INSERT, IDM_COPY,  VIRTKEY, CONTROL
                VK_INSERT, IDM_PASTE, VIRTKEY, SHIFT
                VK_DELETE, IDM_CLEAR, VIRTKEY
            END

            Этот оператор  определяет  клавиши-ускорители  для  каждой
       команды.  Четыре  ускорителя  используют  комбинации  клавиши с
       клавишами ALT, SHIFT, CONTROL.

            Оператор ACCELERATORS  позволяет   связать   идентификатор
       элемента меню   с  ускорителем.  Константы  IDM_UNDU,  IDM_CUT,
       IDM_COPY, IDM_PASTE  и  IDM_CLEAR   являются   идентификаторами
       элементов меню  "Edit".  Когда  пользователь  нажимает  клавишу
       ускоритель, функции  окна  посылается  идентификатор   элемента
       меню, связанного с этим ускорителем.
                                                                               
                    7.7.4  Добавление новых переменных.

            Добавьте в начало С-файла следующий оператор:

            HANDLE  hAccTable;     /* дескриптор таблицы ускорителей */
.
      Windows 3.0/pg/1#3                                       = 148 =


            Переменная hAccTable     содержит    дескриптор    таблицы
       ускорителей. В нее заносится  значение,  возвращаемое  функцией
       LoadAccelerators, и      оно     используется     в     функции
       TranslateAccelerators для  идентификации  используемой  таблицы
       ускорителей.
                                                                               
                   7.7.5  Загрузка таблицы ускорителей.

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

            hAccTable = LoadAccelerators(hInst, "EditMeruAcc");

            Этот оператор  загружает  в  память  таблицу ускорителей и
       присваивает ее  дескриптор  переменной  hAccTAble.   Переменная
       hInstance идентифицирует файл ресурсов прикладной программы,  а
       "EditMenuAcc" это  имя  таблицы  ускорителей.  После   загрузки
       таблица может использоваться в функции TranslateAccelerators.
                                                                               
               7.7.6  Модификация цикла обработки сообщений.

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

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

              if (!TranslateAccelerator(hwnd, hAccTable, &msg)) {
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
              }
          }
                            7.7.7  Модификация фрагмента WM_COMMAND.           

            В прикладной  программе  необходимо  обрабатывать  команды
       меню. В  данной  прикладной  программе  при  выборе  команд  не
       выполняется никакой   работы,  вместо  этого  выводится  панель
       сообщения "Command not implemented" (команда  не  реализована).
       Замените фрагмент WM_COMMAND следующими операторами:

          switch (message) {
              case WM_COMMAND:
                  switch (wParam) {
                      case IDM_ABOUT:
                          lpProcAbout = MakeProcInstance(About, hInst);
                          DialogBox(hInst, "AboutBox", hWnd, lpProcAbout);
                          FreeProcInstance(lpProcAbout);
                          break;

                      /* Команды меню File */
.
      Windows 3.0/pg/1#3                                       = 149 =


                      case IDM_NEW:
                      case IDM_OPEN:
                      case IDM_SAVE:
                      case IDM_SAVEAS:
                      case IDM_PRINT:
                          MessageBox (
                                GetFocus(),
                                "Command not implemented",
                                "EditMenu Sample Application",
                                MB_ICONASTERISK | MB_OK);
                          break;

                      case IDM_EXIT:
                          DestroyWindow(hWnd);
                          break;

                      /* Команды меню Edit */

                      case IDM_UNDO:
                      case IDM_CUT:
                      case IDM_COPY:
                      case IDM_PASTE:
                      case IDM_CLEAR:
                          MessageBox (
                                GetFocus(),
                                "Command not implemented",
                                "EditMenu Sample Application",
                                MB_ICONASTERISK | MB_OK);
                          break;
                  }
                  break;
                                                                               
                      7.7.8  Компиляция и компоновка.

            Для компиляции  и   компоновки   программы   EditMenu   не
       требуется никаких  изменений  в MAKE-файле.  Запустите Windows,
       затем EditMenu,  и  не  открывая  накладываемые  меню   нажмите
       клавиши-ускорители. Вы увидите панель с сообщением "Command not
       Implemented".
                                              7.8  Заключение.                 

            В данной главе описано, как использовать меню в прикладной
       программе.  Меню  предоставляет  список  команд,  которые может
       выбрать пользователь.  Windows обрабатывает большинство функций
       меню  автоматически,  например,  когда  пользователь выбирает в
       строке меню   команду,   Windows    автоматически    отображает
       накладываемое   меню,   связанное   с  данной  командой.  Когда
       пользователь  выбирает  команду  в   меню,   Windows   посылает
       прикладной    программе    сообщение   WM_COMMAND,   содержащее
       идентификатор  выбранного  элемента  меню.   Затем   прикладная
       программа может  выполнить  действия в соответствии с выбранной
.
      Windows 3.0/pg/1#3                                       = 150 =

       командой.

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

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

       Раздел               Руководство
       ---------------------------------------------------------------
       Ввод с использова-   Руководство программиста, Глава 4, "Ввод с
       нием мыши и клавиа-  использованием мыши и клавиатуры"
       туры

       Растровые карты      Руководство программиста, Глава 11, "Раст-
                            ровые карты"

                            "Tools", глава 4, "Создание изображений".

       Функции меню         Справочное руководство, том 1, глава 1,
                            "Функции интерфейса управления окнами",
                            глава 4, "Список функций".

       Операторы описания   Справочное руководство, том 2, глава 8,
       ресурсов             "Операторы описания ресурсов".

       Демонстрационная     Диск "SDK Sample Source Code Disk"
       программа MENU.EXE,
       иллюстрирует исполь-
       зование каскадных
       меню, меню, рисуемых
       владельцем и конт-
       рольных отметок, ри-
       суемых владельцем.

.


Delphi  |  JBuilder
::Главная ->Литература ->Руководство по программированию в Windows
C++ Builder
Реклама - двигатель сами понимаете чего...
Russian LinkExchange Banner Network
(c) 2000 by AlmigoR
Сайт управляется системой uCoz