- Создание Windows-приложений
- Создание консольного приложения Visual Studio
- Создание оконного приложения Visual Studio
- Введение в создание оконных приложений
- Функции API для работы с консолью
- Структура оконного приложения
- Элементы управления окна
- Графика в оконных приложениях
- Введение в создание оконных приложений
- Программный интерфейс приложений
- Графический интерфейс пользователя
- Многозадачность
- Процессы и потоки
- Дескрипторы
- Контекст устройства
- Иллюстрированный самоучитель по Visual Studio .NET
- Структура Windows-приложения
- Тема: Общая структура Windows-приложения
Создание Windows-приложений
Создание консольного приложения Visual Studio
Создание оконного приложения Visual Studio
Введение в создание оконных приложений
Функции API для работы с консолью
Структура оконного приложения
Элементы управления окна
Графика в оконных приложениях
В операционной системе Windows возможны 3 типа структур программ:
- диалоговая (основное окно — диалоговое),
- консольная, или безоконная структура,
- классическая (оконная, каркасная) структура
Диалоговые приложения для Windows имеют минимальный интерфейс связи с пользователем и передают информацию пользователю посредством стандартных диалоговых окон (например, окно сообщения MessageBox() ). Работа программы происходит «вслепую».
Неоконные (консольные) приложения представляет собой программу, работающую в текстовом режиме. Работа консольного приложения напоминает работу программы MS-DOS. Но это лишь внешнее впечатление. Консольное приложение обеспечивается специальными функциями Windows. Консольные приложения представляют собой систему средств взаимодействия пользователя с компьютером, основанную на использовании текстового (буквенно-цифрового) режима дисплея или аналогичных (командная строка MS-DOS, Far). Консольные приложения очень компактны не только в откомпилированном виде, но и в текстовом варианте, и имеют такие же возможности обращаться к ресурсам Windows посредством API-функций, как и оконные приложения.
Оконные (каркасные) приложения строятся на базе специального набора функций API, составляющих графический интерфейс пользователя (GUI, Graphic User Interface). Главным элементом такого приложения является окно. Окно может содержать элементы управления: кнопки, списки, окна редактирования и др. Эти элементы, по сути, также являются окнами, но обладающими особыми свойствами. События, происходящие с этими элементами (и самим окном), приводят к приходу сообщений в процедуру окна.
Разница между оконными и консольными приложениями Windows состоит в том, с каким типом информации они работают.
Введение в создание оконных приложений
Программирование в Windows основывается на использовании функций API (Application Program Interface, т.е. интерфейс программного приложения).
Программа для Windows в значительной степени состоит из таких вызовов. Все взаимодействие с внешними устройствами и ресурсами операционной системы происходит посредством таких функций.
Программный интерфейс приложений
Windows API (Application Programming Interfaces) — общее наименование целого набора базовых функций интерфейсов программирования приложений операционных систем семейств Microsoft Windows.
Windows API в настоящее время поддерживает свыше тысячи вызовов функций, которые можно использовать в приложениях. Каждая функция Windows API имеет развернутое имя, написанное буквами как верхнего, так и нижнего регистров.
Все основные функции Windows объявляются в заголовочных файлах. Главный заголовочный файл называется WINDOWS.H, и в этом файле содержится множество ссылок на другие заголовочные файлы.
Основное отличие функций API от библиотечных функций С: код библиотечных функций связывается с кодом программы пользователя, а код функций API остается вне программы пользователя в динамически подключаемых библиотеках (DLL – Dynamic Link Library), что позволяет создавать более компактный и эффективный код приложений.
При запуске программы Windows она взаимодействует с операционной системой посредством процесса «динамического связывания». Большая часть динамических библиотек DLL расположена в каталоге WINDOWS\SYSTEM.
При компоновке программы для Windows, чтобы сделать ее исполняемой, необходимо связывать ее с «библиотеками импорта», поставляемыми в составе среды программирования (IDE – Integrated Development Environment), которой может являться, в частности, Microsoft Visual Studio. Библиотеки импорта содержат имена всех функций Windows из динамически подключаемых библиотек и ссылки на них. Компоновщик использует эту информацию для создания в исполняемом EXE-файле таблицы, которую Windows использует при загрузке программы для настройки адресов функций API.
Графический интерфейс пользователя
Графический интерфейс пользователя (Graphical User Interface, GUI) еще называют «визуальный интерфейс» или «графическая оконная среда».
GUI делает возможным использование графики на растровом экране. Графика дает лучшее восприятие элементов управления на экране, визуально богатую среду для передачи информации. В GUI экран становится устройством ввода и показывает различные графические объекты в виде картинок и конструкций для ввода информации, таких как кнопки или полосы прокрутки. Используя клавиатуру и манипулятор (мышь, тачпад), пользователь может непосредственно оперировать объектами на экране. Графические объекты можно перетаскивать, кнопки можно нажимать, полосы прокрутки можно прокручивать. Взаимодействие между пользователем и программой становится более тесным.
Пользователям не надо тратить слишком много времени на то, чтобы научиться пользоваться компьютером и составлять новые программы. Система Windows способствует этому, поскольку все программы для Windows выглядят и воспринимаются одинаково.
Любая программа для Windows имеет окно — прямоугольную область на экране, в котором приложение отображает информацию и получает реакцию от пользователя. Окно идентифицируется заголовком. Большинство функций программы запускается посредством меню. Слишком большой для экрана объем информации может быть просмотрен с помощью полос прокрутки. Некоторые пункты меню вызывают появление окон диалога, в которые пользователь вводит дополнительную информацию.
Программирование Windows-приложений тесно связано с понятиями объектно-ориентированного программирования. Главным объектом в операционной системе Windows является окно. Окно может содержать элементы управления: кнопки, списки, окна редактирования и др. Эти элементы, по сути, также являются окнами, но обладающими особыми свойствами.
Активное окно – окно, получающее реакцию от пользователя в данный момент.
Основными элементами окна являются
- 1 — строка заголовка title bar
- 2 — строка меню menu bar
- 3 — системное меню system menu
- 4 — кнопка сворачивания окна minimize box
- 5 — кнопка разворачивания окна maximize box
- 6 — рамка изменения размеров sizing border
- 7 — клиентская область client area
- 8 — горизонтальная и вертикальная полосы прокрутки scroll bars
Многозадачность
Многозадачность ( multitasking ) — свойство операционной системы обеспечивать возможность параллельной (или псевдопараллельной) обработки нескольких процессов.
Операционная система Windows является многозадачной. Если программа DOS после своего запуска должна быть постоянно активной, и если ей что-то требуется (к примеру, получить очередную порцию данных с устройства ввода-вывода), то она сама должна выполнять соответствующие запросы к операционной системе, то в Windows все наоборот. Программа пассивна, после запуска она ждет, когда ей уделит внимание операционная система. Операционная система делает это посылкой специально оформленных групп данных, называемых сообщениями . Сообщения могут быть разного типа, они функционируют в системе достаточно хаотично, и приложение не знает, какого типа сообщение придет следующим.
Логика построения Windows-приложения должна обеспечивать корректную и предсказуемую работу при поступлении сообщений любого типа. Одновременно несколько программ могут выполняться и иметь вывод на экран. Каждая программа занимает на экране прямоугольное окно. Пользователь может перемещать окна по всему экрану, менять их размер, переключаться между разными программами и передавать данные от одной программы к другой.
Операционная система не сможет реализовать многозадачность без управления памятью. Так как одни программы запускаются, а другие завершаются, память фрагментируется. Операционная система Windows имеет средства управления фрагментами памяти.
Процессы и потоки
Процессом ( process ) называется экземпляр программы, загруженной в память. Экземпляр программы может создавать потоки ( thread ), которые представляют собой последовательность инструкций на выполнение.
Выполняются не процессы, а именно потоки. Любой процесс имеет хотя бы один поток. Этот поток называется главным (основным) потоком приложения .
Потоки на самом деле выполняются не одновременно, а по очереди. Распределение процессорного времени происходит между потоками, но переключение между ними происходит так часто, что кажется будто они выполняются параллельно.
Все потоки ранжируются по приоритетам. Приоритет потока обозначается числом от 0 до 31, и определяется исходя из приоритета процесса, породившего поток, и относительного приоритета самого потока. Таким образом, достигается наибольшая гибкость, и каждый поток в идеале получает столько времени, сколько ему необходимо.
Дескрипторы
Дескриптор (описатель) объекта — служебная структура данных, представляющая собой беззнаковое целое число и служащая для идентификации различных объектов. Дескриптор представляет собой указатель на некоторую системную структуру или индекс в некоторой системной таблице.
Примеры дескрипторов, описанных в заголовочном файле windows.h
Контекст устройства
GDI – графический интерфейс устройства. Функции системной библиотеки GDI32.dll используются для вывода графики на экран.
Дескриптор контекста устройства — это паспорт конкретного окна для функций GDI. Контекст устройства фактически является структурой данных, которая внутренне поддерживается GDI. Он связан с конкретным устройством вывода информации (принтер, дисплей). Что касается дисплея, то в данном случае контекст устройства обычно связан с конкретным окном на экране.
Иллюстрированный самоучитель по Visual Studio .NET
Структура Windows-приложения
Рассмотренная модель выработки и прохождения сообщений поможет вам понять структуру, принятую для всех Windows-приложений. Последние два блока в рассмотренной схеме (рис. 3.1) определяют особенности строения любого Windows-приложения.
Простейшее из них должно состоять как минимум из двух функций:
- функции winMain, с которой начинается выполнение программы и которая «закручивает» цикл ожидания сообщений (message pump);
- оконной процедуры, которую вызывает система, направляя ей соответствующие сообщения.
Каждое приложение в системе, основанной на сообщениях, должно уметь получать и обрабатывать сообщения из своей очереди. Основу такого приложения в системе Windows представляет функция winMain, которая содержит стандартную последовательность действий. Однако обрабатывается большинство сообщений окном – объектом операционной системы Windows.
Примечание
C точки зрения пользователя, окно – это прямоугольная область экрана, соответствующая какому-то приложению или его части. Вы знаете, что приложение может управлять несколькими окнами, среди которых обычно выделяют одно главное окно-рамку (Frame Window). С точки зрения операционной системы, окно – это в большинстве случаев конечный пункт, которому направляются сообщения. С точки зрения программиста, окно – это объект, атрибуты которого (тип, размер, положение на экране, вид курсора, меню, зна-чек, заголовок) должны быть сначала сформированы, а затем зарегистрированы системой. Манипуляция окном осуществляется посредством специальной оконной функции, которая имеет вполне определенную, устоявшуюся структуру.
Функция winMain выполняется первой в любом приложении. Ее имя зарезервировано операционной системой. Она в этом смысле является аналогом функции main, с которой начинается выполнение С-программы для DOS-платформы. Имя оконной процедуры произвольно и выбирается разработчиком. Система Windows регистрирует это имя, связывая его с приложением.
Главной целью функции winMain является регистрация оконного класса, создание окна и запуск цикла ожидания сообщений.
Тема: Общая структура Windows-приложения
Программирование Windows-приложений построено на работе с окнами и обработке сообщений, что накладывает на структуру программы определенные ограничения.
Любая программа под Windows состоит минимум из двух функций — WinMain() и оконной функции.
Функция WinMain() должна выполнять следующие операции:
1. Определять класс окна
2. Регистрировать класс окна
3. Поиск уже запущенной копии приложения
4. Создавать окно данного класса
5. Отображать окно
6. Запускать цикл обработки сообщений
Оконная функция предназначена для обработки сообщений, относящихся к данному окну
Исходный текст приложения, которое создает главное окно. При нажатии левой клавишей мыши в клиентской области окна при помощи стандартной диалоговой панели сообщений выдается информация о приложении.
// — Обязательный включаемый файл
// — Прототип функции главного окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// — Объявление глобальных переменных
HINSTANCE hInst; // Дескриптор экземпляра приложения
char ClassName[]=»Window»; // Название класса окна
char AppTitle[]=»Application Win32″; // Заголовок главн окна
// — Главная функция приложения WinMain
int APIENTRY _tWinMain(HINSTANCE hInstance,
LPSTR lpCmdLine, int nCmdShow)
WNDCLASS wc; // Структура для инф-ции о классе окна
HWND hWnd; // Дескриптор главного окна приложения
MSG msg; // Структура для хранения сообщения
// — Проверяем, было ли приложение запущено ранее.
// Если прилож. было запущено ранее, активизировать
// и выдвинуть на передний план его главное окно
if(IsIconic(hWnd)) ShowWindow(hWnd, SW_RESTORE);
// Работа новой копии прекращается.
// Заполнение полей стр-ры WNDCLASS
memset(&wc, 0, sizeof(wc)); // Очистка полей структуры 0
wc.lpszClassName=ClassName; // Имя класса окон
wc.lpfnWndProc=(WNDPROC)WndProc; //Адр. окон. ф-ции
wc.style=CS_HREDRAW|CS_VREDRAW; // Стиль класса окон
wc.hInstance=hInstance; // Экземпляр приложения
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);// Пиктограмм-ма для окон
wc.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор мыши для окон
wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); // Кисть для окон
wc.lpszMenuName=NULL; // Ресурс меню окон
wc.cbClsExtra=0; // Дополнительная память
wc.cbWndExtra=0; // Дополнительная память
// Pегистрация класса окна.
// Создаем главное окно приложения.
ClassName, // Имя класса окон
AppTitle, // Заголовок окна
WS_OVERLAPPEDWINDOW, // Стиль окна
CW_USEDEFAULT, // Ширина окна
CW_USEDEFAULT, // Высота окна
NULL, // Дескриптор окна-родителя
NULL, // Дескриптор меню окна
hInst, // Дескриптор экз. приложения
NULL); // Дополнительная информация
// Окно не создано, выдается предупреждение.
MessageBox(NULL,»Window create error», AppTitle,
// Обновление содержимого клиентской области окна.
// Запуск цикла обработки очереди сообщений.
while(GetMessage(&msg, NULL, 0, 0))
// Преобразов. сообщ., получ с помощью клавиатуры
// Отправление сообщения оконной функции
return TRUE; // Завершение работы приложения
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
// Нажата левая кнопка мыши в клиентской обл. окна.
// Вывод информации о приложении с помощью
// диалоговой панели сообщений MessageBox()
MessageBox(hWnd, «Win32 aplication», «Window»,
// Пользователь удалил окно.
// Если это оконная функция главного окна, то следует
// в очередь сообщений послать сообщение WM_QUIT
// Необработанные сообщ. передаются в стандартную
// функцию обработки сообщений по умолчанию.
return DefWindowProc(hWnd, msg, wParam, lParam);
Пояснения к тексту программы
Главная функция приложения WinMain
Точкой входа для любой Windows-программы является функция WinMain, которая всегда определяется следующим образом:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE
hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
Эта функция использует последовательность вызовов APIENTRY (соглашение о передаче аргументов при вызове функций WINAPI) и, по своему завершению, возвращает операционной системе Windows целое число.
Назначение параметров функции WinMain:
· hInstance называется дескриптором экземпляра приложения. Это уникальное число, идентифицирующее программу, когда она запущена в Windows. Каждая копия одной и той же запущенной несколько раз программы имеет свое значение hInstance.
· hPrevInstance ранее использовался в Win16 и в Win32 всегда равен NULL.
· lpCmdLine является указателем на оканчивающуюся нулем строку, в которой содержаться параметры, переданные программе из командной строки.
· nCmdShow определяет, как приложение первоначально отображается на дисплее: пиктограммой (SW_SHOWMINNOACTIVE) или в виде открытого окна (SW_SHOWNORMAL).
Поиск работающей копии приложения
Для проверки того было ли приложение запущено ранее, используется функция FindWindow, которая позволяет найти окно верхнего уровня по имени класса или по заголовку окна:
HWND FindWindow(LPCTSTR lpClassName,
· lpClassName – это указатель на текстовую строку, в которой задается имя класса искомого окна. На базе одного и того же класса может быть создано несколько окон.
· lpWindowName – это указатель на текстовую строку, содержащую искомый заголовок окна. Если же подойдет любое окно, то параметр lpWindowName имеет значение NULL.
В приведенном тексте функции WinMain, проверяется, было ли ранее приложение запущено и при положительном ответе выдвигается на передний план главное окно ранее запущенной копии с помощью функции SetForegroundWindow(hWnd);
Замечание. Если необходимо, чтобы каждая копия приложения работала как отдельный процесс, то указанный фрагмент кода следует не включать в функцию WinMain.
Регистрация класса окна
Класс окна определяет общее поведение нового типа окон, включая адрес новой оконной процедуры. Новый класс окна регистрируется при вызове приложением следующей функции:
ATOM RegisterClass(const WNDCLASS *lpwc);
Параметр lpwc указывает на структуру типа WNDCLASS, описывающую тип нового окна. Возвращаемое значение является атомом Windows – 16-разрядным значением, идентифицирующим уникальную символьную строку в таблице Windows.
Затем приложение должно создать само окно с помощью функции CreateWindow, которая возвращает дескриптор созданного окна типа HWND:
HWND CreateWindow(LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, LPVOID *lpParam);
У каждого окна в Windows имеется уникальный дескриптор типа HWND. Дескриптор окна – это один из важнейших описателей, которыми оперирует программа для Windows. Для многих функций Windows требуется дескриптор окна, благодаря которому Windows знает, к какому окну применить функцию.
Параметры функции CreateWindow:
· lpClassName указывает имя класса, поведение которого наследует данное окно. Этот класс должен быть зарегистрирован с помощью фунцкии RegisterClass или может быть одним из предопределенных классов элементов управления с именами “button”, “combobox”, “listbox”, “edit”, “scrollbar” и “static”.
· lpWindowName определяет строку, которая выводится в заголовке создаваемого окна.
· dwStyle определяет стиль окна. (см. тему «Классы и стили окон»).
· x, y, nWidth и nHeight задают начальные геометрические размеры окна. Если при задании параметров x, y, nWidth и nHeight использовать константу CW_USEDEFAULT, то Windows установит расположение и размеры окна самостоятельно.
· hWndParent задает для создаваемого окна дескриптор его окна-родителя. Если окно является главным окном приложения, то этому параметру присваивается значение NULL.
· hMenu определяет для окна дескриптор меню. Значение NULL на месте дескриптора меню говорит о том, что у окна будет только меню класса, общее для всех окон этого класса.
· hInstance задает дескриптор экземпляра приложения, которое создает окно.
· lpParam используется для передачи окну дополнительных данных (если их нет, то он должен быть равен NULL).
Для отображения окна на экране используется функция:
BOOL ShowWindow(HWND hwnd, int nCmdShow);
· hwnd задает дескриптор окна.
· nCmdShow задает начальный вид окна на экране (для главного окна приложения используется величина, передаваемая в качестве параметра функции WinMain). Для всплывающих и дочерних окон nCmdShow задает, как окно первоначально отображается: пиктограммой (SW_SHOWMINNOACTIVE) или в виде открытого окна (SW_SHOWNORMAL)..
Для перерисовки рабочей области производится вызов функции:
void UpdateWindow(HWND hwnd);
Функция UpdateWindow передает функции окна сообщение WM_PAINT. Получив его, функция окна обновляет содержимое экрана.
Цикл обработки очереди сообщений
Windows поддерживает очередь сообщений (message queue) для каждой программы, работающей в данный момент в системе. Когда происходит какое-либо событие (нажатие клавиши, щелчок мыши), Windows преобразовывает его в сообщение, которое помещается в очередь сообщений приложения.
Программа извлекает сообщения из очереди сообщений, выполняя блок команд, известный как цикл обработки сообщений (message loop).
Простейший цикл обработки сообщений имеет следующий вид:
while(GetMessage(&msg, NULL, 0, 0))
// преобразование сообщений от клавиат. в символьные
// отправка сообщения окну-адресату приложения
Извлечение сообщений из очереди производится при помощи функции:
BOOL GetMessage(MSG FAR* lpmsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax);
· lpmsg является дальним указателем на структуру сообщения типа MSG (см. тему «Сообщения Windows. Типы сообщений»).
· hwnd определяет дескриптор окна – источника сообщений. Если задать этому аргументу NULL, то программа будет получать сообщения от всех окон, созданных программой.
· uMsgFilterMin и uMsgFilterMax позволяют задать диапазон значений для фильтрации сообщений, получаемых программой. Если на их месте задать 0, то программа будет получать все сообщения.
Если поле message сообщения msg, извлеченного из очереди сообщений, равно любому значению, кроме WM_QUIT, то функция GetMessage возвращает ненулевое значение. Если из очереди извлечено сообщение WM_QUIT, то GetMessage возвращает нуль, что прерывает цикл обработки сообщений.
Каждое получаемое приложением сообщение (за исключением WM_QUIT) направлено одному из окон приложения. Поскольку приложение не должно прямо вызывать функцию обработки окна, для передачи сообщения нужному окну используется функция:
LONG DispatchMessage(const MSG FAR* lpmsg);
Эта функция передает msg обратно в Windows, которая отправляет его для обработки соответствующей оконной процедуре.
Перед вызовом функции DispatchMessage помещена специальная функция, производящая преобразование кодов комбинаций некоторых клавиш в символьные сообщения:
BOOL TranslateMessage(const MSG FAR* lpmsg);
Завершение работы приложения
Приложение завершает свою работу тогда, когда функция WinMain передает управление Windows. Передать управление можно в любом месте WinMain, в том числе и до входа в цикл обработки очереди сообщений.
Однако после входа в цикл обработки очереди сообщений единственным способом завершить приложение является посылка в очередь приложения сообщения WM_QUIT. Сообщение помещается в очередь сообщений только функцией главного окна данного приложения вызовом функции PostQuitMessage.
Реальная работа приложения происходит в оконных функциях, которые определяют, что выводится в рабочую область окна и как окно реагирует на пользовательский ввод. Оконной функции можно назначать любое имя, в Windows-программе может содержаться более одной оконной функции.
Оконная функция всегда связана с определенным классом окна, который регистрируется при помощи функции RegisterClass. На основе одного и того же класса можно создать несколько окон.
Оконная функция определяется следующим образом:
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam);
Все четыре параметра оконной процедуры идентичны первым четырем полям структуры MSG.
Функция окна вызывается непосредственно Windows и не может вызываться приложением напрямую. В функции окна используется соглашение о связях языка Паскаль, поэтому объявление функции CALLBACK обязательно.
Обработка сообщений в оконной функции
Функция окна получает сообщение из двух источников: из цикла обработки сообщений и от Windows:
· Из цикла обработки сообщений поступают сообщения ввода: перемещение и нажатие клавиш мыши, нажатие и отпускание клавиш клавиатуры и, если установлен генератор событий таймера, сообщения от таймера.
· Windows посылает функции окна сообщения поддержки окна напрямую, минуя очередь приложения и цикл обработки сообщений. Эти сообщения обычно вызваны событиями, требующими немедленной реакции по изменению вида окна.
Каждое получаемое окном сообщение идентифицируется номером, который содержится в параметре msg оконной функции. Если оконная процедура обрабатывает сообщение, то ее возвращаемым значением должен быть 0.
Все сообщения, не обрабатываемые оконной процедурой, должны передаваться функции Windows функцией DefWindowProc. При этом значение, возвращаемое DefWindowProc, должно быть возвращаемым значением оконной функции.
Удаление окна, сообщение WM_DESTROY
Сообщение WM_DESTROY показывает, что Windows находится в процессе ликвидации окна в ответ на полученную от пользователя команду (пользователь вызывает поступление этого сообщения, если нажмет мышью на пиктограмме “Close”, выберет пункт “Close” из системного меню или нажмет комбинацию клавиш Alt+F4).
Главное окно стандартно реагирует на это сообщение, вызывая функцию:
Эта функция ставит сообщение WM_QUIT в очередь сообщений приложения, что заставляет функцию WinMain прервать цикл обработки сообщений и выйти в систему, завершив работу приложения.