Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции -Процедурное программирование в Windows.doc
Скачиваний:
12
Добавлен:
13.09.2019
Размер:
742.91 Кб
Скачать

МИНИСТЕРСТВО ОБРАЗОВАНИЯ и НАУКИ

РОССИЙСКОЙ ФЕДЕРАЦИИ

ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ

ТАГАНРОГСКИЙ ГОСУДАРСТВЕННЫЙ РАДИОТЕХНИЧЕКИЙ УНИВЕРСИТЕТ

Процедурное программирование

на С++ для Windows

Материалы к лекциям

по курсу

«Программирование

на языках высокого уровня»

Для студентов специальностей 220300

всех форм обучения.

Таганрог 2004

УДК 681.3.06.(07)

Составитель: В.А.Литвиненко

Процедурное программирование на С++ для Windows. Материалы к лекциям по курсу «Программирование на языках высокого уровня». Таганрог: Изд-во ТРТУ, 2004.

- с.

Рассматриваются следующие вопросы процедурного программирования на С++ для Windows: АPI, структуру программы, механизм обработки сообщений Windows, его реализацию в программах на С++, цикл обработки сообщений, функции обработки окон, структуры для создания класса окна, сообщений, основные сообщения Windows, основные органы управления Windows, основные ресурсы Windows.

Библиограф. 12 назв.

Рецензент:

В В Е Д Е Н И Е

Классификация технологий программирования:

1) процедурное программирование (ПП);

2) объектно-ориентированное программирование (ООП);

3) макетное программирование (МП);

  1. визуальное программирование (ВП).

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

1) MS-DOS - ПП, ООП;

2) Windows 98/2000/XP (WIN32) - ПП, ООП, МП, ВП;

  1. OS-2 - ПП, ООП;

  2. UNIX - ПП, ООП.

ПП для MS-DOS - это программирования на языке С с использованием библиотеки стандартных функций .

ООП для MS-DOS - это программирование на объектно-ориентированном языке С++ с использованием библиотеки стандартных функций С++ .

ПП для WIN32- это программирование на стандартном языке С с использованием библиотеки функций WIN32 - API (Application Programming Interface) и функций библиотеки стандартных функций языка С за исключением функций, предназначенных для работы с ресурсами (экраном, клавиатурой и т.д.).

ООП для WIN32 возможно двух типов:

  1. программирование на С++ проблемной части задачи с использованием функций API и библиотеки стандартных функций языка С++ за исключением функций, предназначенных для работы с ресурсами, и ПП для WIN32 интерфейса;

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

МП для WIN32 - это по существу использование ранних систем программирования, например, Borland 3.1, которые позволяют программисту создавать интерфейс на основе макетов окон и органов управления, используя для этого специальную программу - редактор

ресурсов (Resource Workshop). Поэтому МП для WIN32 также может относиться как к ПП, так и к ООП для WIN32.

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

К сожалению, разработка визуальных технологий программирования для таких мощных ОС, как OS-2 и UNIX, в настоящее время отстает от рынка визуальных технологий программирования для WIN32. Именно этим и объясняется большой интерес к программированию для WIN32.

В настоящее время, ведущее положение на рынке инструментальных систем программирования для WIN32 занимают фирмы Microsoft и Borland, при этом Microsoft является к тому же и разработчиком WIN32.

Microsoft разрабатывает и поддерживает систему программирования Visual C++, которая обеспечивает процедурное программирования для WIN32 и объектно-ориентированное программирование с помощью библиотеки классов MFC (Microsoft Foundation Classes).

Borland параллельно с Microsoft разрабатывает и поддерживает систему программирования Borland C++, которая также обеспечивает процедурное программирования для WIN32 и объектно-ориентированное программирование с помощью библиотеки классов OWL (Object Windows Library).

В настоящее время на рынке известны версии Visual C++ 6.0 c MFC 6.0 и а также система визуального программирования Borland C++ Biulder 6.0 c библиотекой визуальных компонент VCL (Visual Component Library).

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

Настоящее пособие освещает круг вопросов процедурного программирования для WIN32, так как программирование с использованием функций API является фундаментом для понимания методов создания приложений для WIN32 и процесса взаимодействия Windows с самими приложениями.

MS-DOS и Windows

Взаимодействие MS-DOS и аппаратуры IBM PC выглядит так:

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

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

Поэтому очень распространен подход программирования «в обход» MS-DOS. При этом это довольно просто ввиду открытости IBM PC. Это привело к очень большим срокам разработки программ.

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

Разработчик программы под MS-DOS должен был пройти следующие этапы:

  1. постановка задачи;

  2. разработка интерфейса;

  3. разработка собственной или выбор универсальной графической библиотеки;

  4. программирование внешних устройств;

  5. оптимизация использования памяти - создание оверлейных структур;

  6. реализовать проект с учетом совместимости с ранее разработанными библиотеками.

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

Windows - операционная оболочка

На рис.2 приведена функциональная схема взаимодействия Windows 3.1, MS-DOS и аппаратного обеспечения IBM PC.

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

Аппаратура IBM PC при этом обслуживается как MS-DOS, так и Windows. MS-DOS управляет файловой системой. Все остальное делает Windows. В MS-DOS программа самостоятельно управляла практически всеми ресурсами IBM PC.

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

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

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

Контекст устройства - объединяет в себе драйвер устройства, само устройство и порт связи.

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

Основные функции Windows выполняют три системных модуля:

kernel.exe - ядро Windows, управляет памятью, загрузкой и выполнением программ;

gdi.exe - осуществляет интерфейс с графическими устройствами;

user.exe - делает все остальное.

Модули user.exe и gdi.exe взаимодействуют с аппаратурой IBM PC через драйверы устройств Windows.

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

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

В WIN32 работа MS-DOS эмулируется самой WIN32, т.е. функции, выполняемые MS-DOS, встроены в WIN32. Это позволяет рассматривать WIN32 как самостоятельную операционную систему.

Объекты - окна Windows

Для пользователя окно - это прямоугольная часть экрана. Каждая программа занимает свое окно или несколько окон. Одно окно обязательно - «главное окно приложения».

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

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

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

Механизм сообщений

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

Управляющие данные называют сообщениями. Все сообщения имеют единый формат. В Windows модель данных, управляющих объектами, реализуется при помощи механизма сообщений.

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

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

Сообщения, которые получает объект-«окно», возникают в результате действия пользователя, которые он выполняет при работе с приложением. Например, объект-«окно» приложения может получать сообщения о нажатии или отпускании клавиш клавиатуры или кнопок мыши. Так при нажатии клавиши приложение получает сообщение WM_KEYDOWN, а при нажатии левой кнопки мыши - сообщение WM_LBUTTONDOWN.

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

Наконец приложение может направлять сообщения самому себе.

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

Взаимодействие Windows и приложения

Рассмотрим, как взаимодействуют Windows и приложение при обработке, например, нажатие клавиши:

Рис.3. Обработка нажатия клавиши.

При поступлении сигналов от мыши или клавиатуры аппаратура IBM PC формирует асинхронные прерывания, которые обрабатываются драйверами keyboard.drv и mouse.drv соответственно. При поступлении сигнала драйвер вызывает процедуру в модуле user.exe, формирующую соответствующе сообщение. Это сообщение, содержащее полную информацию о событии, помещается в системную очередь.

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

Распределение сообщений по приложениям заключается в том, что сообщения извлекаются из системной очереди, определяется, какому окну предназначено данное сообщение, и это сообщение помещается в очередь приложения, которому принадлежит окно.

Эту работу осуществляет модуль user.exe. Обработку очереди приложения осуществляет уже само приложение. Для этого существует так называемый цикл сообщений приложения, который извлекает сообщения из очереди, переводит их в сообщение ANSI (например WM_CHAR) и направляет их в соответствующую функцию окна приложения. Конкретные действия по сообщению предпринимаются уже функцией окна; например, если требуется отобразить символ в пользовательской области окна приложения, то это делает функция окна приложения при помощи функции API TextOut().

Системная очередь сообщений является, таким образом, средством распределения сообщений по приложениям.

Если заранее известно, какому приложению предназначено то или иное сообщение, то оно помещается в очередь приложения, минуя системную очередь. Так при работе с таймером мы явно указываем, какому приложению направлять сообщение по истечении определенного времени интервала. Поэтому сообщение таймера не нужно помещать в системную очередь; они передаются непосредственно в очередь приложения.

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

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

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

Рис.4 Запуск приложения Windows и вызов функции окна по приходе сообщения.

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

Таким образом, цикл сообщений (message loop) только извлекает сообщения из очереди сообщений и направляет в функцию окна. Именно она содержит команды, выполняющие реальные действия, выполнение команд меню, осуществление вывода в окно графики, текста и прочие действия, относящиеся собственно к приложению.

Завершение работы приложения

Не все сообщения попадают в функцию окна приложения через цикл обработки сообщений. Сообщения поддержки окна передаются Windows непосредственно в функцию окна приложения.

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

Рис.5 Завершение работы приложения Windows.

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

Классы сообщений

Сообщения Windows весьма многообразны; они могут быть условно разделены на классы по функциональным признакам. Так, обычно принято выделять системные сообщения (WM_SYSCOMMAND, WM_SYSCHAR и др.), сообщения управления окнами (WM_CREATE, WM_DESTROY и др.), сообщения многооконного интерфейса MDI (WM_MDIGETACTIVE, WM_MDIDESTROY и др.), сообщения мыши, клавиатуры и др. - всего около 15 разновидностей. С классами сообщений можно более подробно познакомиться, используя файл помощи системы программирования.

Благодаря многозадачности Windows можно одним приложением следить за сообщениями, которые Windows помещает в очередь другого приложения; это интересная возможность весьма полезна при отладке программ.

Фокус ввода

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

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

Управление памятью. Дескрипторы.

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

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

Кроме того для освобождения ОП используется страничная организация ОП, при которой происходит обмен страницами между ОП и МД. Также используется механизм load-on-call - «загрузка по требованию», который позволяет удалять из памяти сегменты, которые содержат коды неактивных приложений.

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

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

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

Динамическое подключение библиотек

В MS-DOS использовалось статическое подключение библиотек. При этом на этапе компиляции, т. е. до выполнения программы, осуществлялась сборка всех объектных файлов ( .obj) в один выполняемый модуль.

В многозадачной системе используется динамическое подключение библиотек. DLL - Dynamic Link Libraries.

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

Типы данных, используемые в Windows

Рассмотрим нестандартные типы данных, которые используются в Windows. Определение типов данных осуществляется при помощи оператора typedef:

typedef int BOOL;

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

Таблица

Тип

данных

Определение

Описание

BYTE

unsigned char

Однобайтовое беззнаковое целое число

WORD

unsigned short

Двухбайтовое беззнаковое целое число

LONG

signed long

Четырехбайтовое знаковое целое число

DWORD

unsigned long

Четырехбайтовое знаковое целое число

NPSTR

char *

Ближний (два байта) указатель на

текстовую строку

LPSTR

char far *

Дальний (четыре байта) указатель на текстовую строку

BOOL

int

Логическая переменная, принимающая значение TRUE (истина) и FALSE (ложь)

Из простых типов данных создаются сложные типы данных Windows. Некоторые из них приведены в таблице:

Таблица

Тип данных

Описание

HANDLE

HWND

FARPROC

MSG

WNDCLASS

PAINTSTRUCT

RECT

Двухбайтовое беззнаковое целое число, идентифицирующее объект Windows (дескриптор)

Двухбайтовое беззнаковое целое число, идентифицирующее окно (дескриптор окна)

Дальний (четыре байта) указатель на функцию

Структура, определяющая параметры сообщения, Windows

Структура, определяющая класс окна

Структура, предназначенная для подготовки графического вывода в окно

Структура, определяющая параметры прямоугольника

Венгерская нотация

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

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

Для обозначения структур используют сокращение их имен.

Например, для именования структурных переменных типа POINT, можно использовать сокращение pt: ptLowerRight, ptPrevious , для структурных переменных типа WORD - w , а типа DWORD - dw: wBufSize, dwFileSize

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

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

Таблица

Префикс

Тип

Пояснение

c

by

n

i

b

w

h

l

dw

fn

s

sz

char

BYTE

short или int

int

BOOL

WORD

HANDLE

LONG DWORD

unsigned char

десятичное целое число

unsigned int

unsigned int

long

Дескриптор

unsigned long

Двойное слово

Имя функции

Строка

Строка, оканчивающаяся нулем

Перед этими префиксами могут также указываться префиксы, говорящие о типе указателя:

Таблица

Префикс

Определение Си

Пояснение

p

lp

np

*

far *

near *

Указатель

Дальний указатель

Ближний указатель

Этапы создание приложения Windows

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

На рис.7 показан процесс создания приложения для Windows.

  1. Написание функций WinMain() и WndProc() программы на языке С.

  2. Создание текстового файла описания ресурсов (расширение .rc)- курсоров, пиктограмм, меню, диалоговых окон и прочие.

  3. Создание текстового файла описание программного модуля (расширение .def).

  4. Компиляция и компоновка всех исходных модулей на языке Си с использованием файла описания программного модуля.

  5. Компиляция файла ресурсов и включение его в готовый исполняемый модуль.

Обычно для простых приложений используется файл определение модуля по умолчанию default.def.

Файл ресурсов ( .rc) создается с помощью редактора ресурсов Resurse Workshorp и в случае необходимости производится его редактирование как обычного текстового файла.

Файл определения модуля

Для компоновки приложения Windows требуется создание файла определения модуля *.def.

Рассмотрим типичный файл определения модуля. В файл определения модуля можно включать комментарии. Комментарием считаются все символы, расположенные после точки с запятой до конца строки.

NAME test ; Имя программы

DESCRIPTION ‘Пример приложения для Windows’

CODE MOVEABLE ; Код программы можно перемещать

; При перераспределении памяти

DATA MOVEABLE MULTIPLE

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

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

HEAPSIZE 1024 ; Рекомендуемый минимум размера стека для приложения

STACKSIZE 4096

; Далее указываются «экспортируемые» функции , которые вызываются только из Windows

EXPORTS

WndProc @1 ; Имя функции главного окна

About @2 ; Имя функции окна «About»

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

Оператор DESCRIPTION это текстовая строка помещается в выполняемый файл для регистрации версии программы ими авторства.

Оператор CODE - для компоновщика 32-х разрядных приложений возможны опции:

PRELOAD - сегмент загружается в память при запуске приложения;

LOADONCALL - сегмент загружается в память только, когда происходит

обращения к некоторому его элементу;

Оператор DATA - устанавливает атрибуты сегмента данных программы.

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

Для приложений для WIN32 файл * .def обычно не используется.

Структура приложения Windows

Приложение Windows содержит обязательно две функции:

WinMain() и WndProc().

Функция WinMain() - главная функция приложения и аналогична функции main() для программы на языке С.

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

main()

{

}

Аналогичная программа для Windows сложнее:

#include <windows.h>

int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevlnstance,

LPSTR lpszCmdLine, int nCmdShow)

{

return FALSE;

}

Файл windows.h необходим при написании любых программ для Windows. В нем содержатся прототипы всех функций Windows, определены типы всех функций Windows, определены типы и структуры данных, глобальные переменные и константы.

Функция WinMain()

Функция WinMain() обязана присутствовать в каждом приложении Windows. Функции WinMain() передается управление в начальный момент загрузки приложения.

Основные действия, которые выполняет функция WinMain(), следущие:

  • Регистрация класса окна приложения и другие инициализации.

  • Создание основного окна приложения и других подчиненных окон.

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

  • Завершение работы приложения при извлечении из очереди сообщения WM_QUIT.

Заголовок функции WinMain() выглядит так:

int WINAPI WinMain ( HINSTANCE hInstance, / / дескриптор текущей копии

HINSTANCE hPrevlnstance, / / предыдущая копия

LPSTR lpszCmdLine / / указатель на командную строку

int nCmdShow) / / флаг "окно_ открыто/окно_ закрыто"

Функция WinMain() имеет четыре параметра.

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

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

lpszCmdLine - это дальний указатель на командную строку, оканчивающуюся нулем. Он позволяет приложению получать данные через командную строку.

nCmdShow - определяет, как в приложении первоначально отображается на дисплее: пиктограммой (nCmdShow == SW_ SHOWMINNOACTIVE) или в виде открытого окна (nCmdShow == SW_ SHOWNORMAL). Константы SW_ SHOWMINNOACTIVE и SW_ SHOWNORMAL определены во включаемом файле windows.h.

Дескриптор приложения

В Windows можно запустить одновременно не только несколько программ, но и несколько раз запустить одну и ту же программу. Таким образом, одно и тоже приложение может иметь несколько копий.

Для приложений для Windows 3.1 первая копия приложения имеет важное значение.

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

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

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

#include<windows.h>

int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevlnstance,

LPSTR lpszCmdLine, int nCmdShow)

{ if ( !hPrevInstance ) { . . . } }

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

if ( !hPrevInstance ) return NULL;

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

Прежде чем отобразить что либо на экране, нужно создать окно, и только в окно можно осуществить вывод.

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

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

Для того чтобы зарегистрировать класс окна, следует заполнить поля структуры типа

WNDCLASS и передать эту структуру в виде параметра функции RegisterClass().

Структура класса окна WNDCLASS определена в файле windows.h и имеет десять полей:

typedef struct tagWNDCLASS

{

UINT style; / / тип окна

WNDPROC lpfnWndProc; / / функция окна

int cbClsExtra; / / размер дополнительной памяти

int cbWndExtra; / / размер дополнительной памяти

HINSTANCE hInstance; / / дескриптор копии приложения

HICON hIcon; / / дескриптор пиктограммы

HCURSOR hCursor; / / дескриптор курсора

HBRUSH hbrBackground; / / цвет фона окна

LPCSTR lpszMenuName; / / имя меню в файле ресурсов

LPCSTR lpszClassName; / / имя класса окна

} WNDCLASS;

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

Назначение полей структуры WNDCLASS приведены следующей таблице:

Поле

Описание

lpszClassName

hInstance

lpfnWndProc

style

hBrBackground

hCursor

hIcon

l

pszMenuName

cbClsExtra

clWndExtra

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

Манипулятор копии, создающей класс окна.

Указатель на функцию поддержки окна.

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

Определяет фон окна.

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

Определяет пиктограмму (icon), которая будет отображаться при переводе окна в неактивное состояние.

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

Определяет число байт, которое необходимо дополнительно запросить у Windows под эту структуру.

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

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

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

#include<windows.h>

char szName[100]="Application";

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

. .

int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevlnstance,

LPSTR lpszCmdLine, int nCmdShow) .

{

WNDCLASS W;

if ( !hPrevInstance )

{

W.style = CS_HREDRAW | CS_VREDRAW ;

W.lpfnWndProc = WndProc ;

W.cbClsExtra = NULL ;

W.cbWndExtra = NULL ;

W.hInstance = hInstance;

W.hIcon = LoadIcon( NULL, IDI_APPLICATION );

W.hCursor = LoadCursor (NULL, IDC_ARROW) ;

W.hbrBackground = GetStockObject(WHITE_BRUSH);

W.lpszMenuName = NULL;

W.lpszClassName = szName ;

if (RegisterClass (&W)) return NULL;

}

}

Каждый класс окна имеет свое имя. Оно задается в поле lpszClassName структуры класса окна. При регистрации класса окна он сразу становится доступен всем другим приложениям Windows.

Поле lpfnWndProc.

Инициализируется указателем на функцию окна WndProc(). Тем самым указывается, что функция WndProc() является управляющей функцией данного окна.

Поле hInstance.

Должно содержать индекс копии приложения. Этот индекс передается приложению как параметр функции WinMain().

Поле lpfnWndProc.

Задает адрес функции окна. Функция окна обрабатывает все сообщения для окон данного класса. Перед присвоением полю lpfnWndProc указателя на функцию WndProc()

нужно объявить функцию WndProc().

Поле hbrBackground.

Этому полю присваивается дескриптор на системно определенную "белую кисть"

(white brush), т.е. определяется белый цвет заполнения фона окна. Дескрипторы системно определенных графических объектов определяются при помощи специальной функции GetStockObject(). Функция GetStockObject() возвращает дескрипторы на такие системно определенные графические объекты, как "кисти" (brushes), "карандаши"(pens) и "шрифты"(fonts). Вместо кисти белого цвета (WHITE_BRUSH) можно использовать кисть серого цвета (GRAY_BRUSH), светло серого (LTGRAY_BRUSH), темно-серого (DKGRAY_BRUSH), или черного (BLACK_BRUSH) цветов.

Кроме того, задать белый цвет фона можно и так (HBRUSH)(COLOR_WINDOW + 1), где COLOR_WINDOW - это серый цвет - цвет Windows.

Можно создать кисть любого цвета и структуры при помощи функции CreateSolidBrush или CreateHatchBrush RGB, а также макроопределения RGB;

// Сплошной фон:

W.hbrBackground = CreateSolidBrush ( RGB ( 225, 123, 234));

Функция CreateSolidBrush имеет единственный параметр, определяющий RGB-цвет кисти.

Макроопределение RGB, используемое в представленных выше примерах для получения величины RGB цвета кисти, имеет следующий формат:

DWORD RGB ( cRed, сGreen, сBlue)

Этот макрос возвращает величину RGB цвета, основываясь на красной, зеленой и синей составляющих цвета. Интенсивность каждой составляющей может меняться от 0 до 255. Если все три интенсивности равны нулю, то мы получаем черный цвет. Если все три интенсивности равны 255, то мы получаем белый цвет. Параметр cRed задает интенсивность красной составляющей, cGreen - зеленой, а cBlue - голубой.

Макрос RGB определен в файле windows.h следующим образом:

# define RGB ( red, green, blue ) ((DWORD)((blue) << 8 | (red))

Функция CreateSolidBrush имеет два параметра. Первый задает структуру кисти, а второй - цвет:

// Фон, имеющий структуру задаваемую первым параметром:

pWndClass>hbrBackground =

CreateHatchBrush (HS_CROSS, RGB (225, 123, 234));

Первый параметр, задающий структуру кисти, может иметь одно из следующих значений:

HS_HORISONTAL HS_VERTICAL HS_CROSS

HS_FDIAGONAL HS_BDIAGONAL HS_DIAGCROSS

Рис. 8. Кисти Windows.

Поле hCursor.

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

Идентификатор

Форма курсора

IDC_ARROW

IDC_CROSS

IDC_IBEAM

IDC_ICON

IDC_SIZE

IDC_UPARROW

IDC_WAIT

Стандартный курсор - стрелка

Курсор - перекрестие

Курсор - вертикальная черта

Курсор - вертикальная черта

Четыре стрелки, указывающие в разные стороны

Курсор в виде вертикальной стрелки

Курсор в виде песочных часов

В приведенном выше примере передаваемые этой функции параметры NULL и IDC_ARROW определяют использование стандартного курсора-стрелки.

Поле hIcon.

Полю hIcon присваивается дескриптор на встроенную пиктограмму. Для извлечения дескрипторов встроенных или определенных в приложении пиктограмм используется функция

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

IDI_APPLICATION

Рис.8. Стандартные пиктограммы Windows.

Поле style.

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

pW.style = CS_HREDRAW | CS_VREDRAW;

Флаги CS_HREDRAW и CS_VREDRAW сообщают Windows, что рабочая область окна должна обновляться при изменении ее вертикального (CS_VREDRAW) и горизонтального (CS_HREDRAW) размеров. Позже мы рассмотрим другие флаги.

Поле cbClsExtra.

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

Поле cbWndExtra.

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

Полям style, cbWndExtra, cbClsExtra могут присваиваться значения NULL, что автоматически определяет присвоение им значений по умолчанию Windows.

Поле lpszMenuName.

Следующее поле структуры класса окна - lpszMenuName задает имя меню, определенного в файле ресурсов (.rc). Если меню не используется, то поле lpszMenuName должно быть равно нулю:

W. lpszMenuName = NULL;