Создание полноценной оконной процедуры в Win32 API (Часть 1)

ЛАБОРАТОРНАЯ РАБОТА № 2

Тема работы: Основы рисования и копирования изображений. Рисование графических примитивов

Цель работы: Приобрести практические навыки создания приложений с использованием Win32 API, научиться рисовать и редактировать изображения.

Win32 API (далее WinAPI) – это набор функций (API – Application Programming Interface), работающих под управлением ОС Windows. Они содержатся в библиотеке windows.h.

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

Не будем внедряться в теорию. Начнём с того, как создать этот проект в MVS, а в конце статьи будет разобран простой пример.

Итак. Сначала открываем Visual Studio, затем, нажимаем на вкладку «Файл», далее «Создать проект»:

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Затем, в раскрывающемся списке Visual C++ выбираем пункт Win32, там и будет «Проект Win32». Щелкаем по нему: Вводим название проекта, указываем путь и нажимаем «ОК». Далее будет написано: «Добро пожаловать в мастер приложения Win32». Нажимаем далее. По-умолчанию у надписи «Пустой проект» галочка отсутствует. Нам нужно её поставить и убедиться, что у нас «Тип Приложения» — Приложение Windows. Если всё верно, нажимаем – «Готово».

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

У нас должен быть пустой проект такого вида:

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Ну а теперь начнём писать простую программу, которая традиционно будет выводить на экран надпись: «Привет, Мир!!!».

Естественно, к проекту нужно добавить файл типа «имя».cpp. Кликаем по «Файлы исходного кода» правой кнопкой мыши, в раскрывающемся списке выбираем вкладку – «Добавить», далее «Создать элемент…». В результате у нас должно появиться такое окно:

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Выбираем «Файл С++», вводим имя, нажимаем «Добавить». Затем открываем этот файл и вставляем в него такой код (подробности далее):

?

#include <windows.h> // заголовочный файл, содержащий функции API   // Основная функция - аналог int main() в консольном приложении: int WINAPI WinMain(HINSTANCE hInstance, // дескриптор экземпляра приложения HINSTANCE hPrevInstance, // в Win32 не используется LPSTR lpCmdLine, // нужен для запуска окна в режиме командной строки int nCmdShow) // режим отображения окна { // Функция вывода окна с кнопкой "ОК" на экран (о параметрах позже) MessageBox(NULL, L"Привет, мир!!!", L"Оконная процедура", MB_OK); return NULL; // возвращаем значение функции }

Результат должен быть таким:

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Теперь остановимся поподробнее на коде программы.

В первой строке мы подключаем заголовочный файл windows.h. В нём содержатся все необходимые «апишные» функции. Здесь всё понятно.

В 4-7 строках у нас описание функции int WINAPI WinMain().

Квалификатор WINAPI, нужен для функции WinMain всегда. Просто запомните это. WinMain – название функции. Она имеет четыре параметра. Первый из них – HINSTANCE hInstance (строка 4). hInstance является дескриптором экземпляра окна (это некий код оконной процедуры, идентификатор, по которой ОС будет отличать её от остальных окон). Через него можно обращаться к окну в процессе работы в других функциях (об этом позже), что-либо менять в параметрах окна. HINSTANCE является одним из многочисленных типов данных определенных в WinAPI, таким же как int, например. А запись HINSTANCE hInstance говорит нам о том, что мы создаём новую переменную типа HINSTANCE с названием hInstance.

О типах данным мы поговорим позже, поэтому переходим к следующему параметру: HINSTANCE hPrevInstance (строка 5). Как написано в комментариях, в Win32 он не используется, так как он создан для 3.x разрядной системы, из предыдущего понятно, что это дескриптор экземпляра окна. Далее у нас переменная типа LPSTR (строка 6) с именем lpCmdLine. Она используется в том случае, если мы запускаем окно через командную строку с прописью параметров. Очень экзотический способ, поэтому мы не будем на нём задерживаться.

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

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

?

int MessageBox(HWND hWnd, // дескриптор родительского окна LPCTSTR lpText, // указатель на строку с сообщением LPCTSTR lpCaption, // указатель на строку с текстом заголовка UINT uType);// флаги для отображения кнопок, стиля пиктограммы и прочее

В нашем случае, первому параметру присвоен ноль. Всё потому, что у нас нет родительских окон (оно не запущено какой-нибудь программой).

Далее у нас идут две переменные типа LPCTSTR: lpText и lpCaption. Первая сообщает информацию, которая будет выведена в окне в текстовом виде. Вторая сообщает, что будет написано в тексте заголовка к окну. Это аналог char *str, но всё же нет. Для того, чтобы текст выводился корректно, нужно перед строкой поставить букву L (UNICODE строка).

Ну и последний тип данных – UINT – 32-х битное целое без знака. То есть аналог unsigned int. Этому параметру можно передавать некоторые значения (о них тоже позже), за счёт чего можно менять вид кнопки. В нашем случае – это MB_OK — означает, что окно создаёт кнопку с надписью «ОК» и соответствующим действием при её нажатии (закрытием приложения).

В строке 11 мы возвращаем значение функции, так как она имеет не тип void.

ЛИТЕРАТУРА

1. Побегайло А. Системное программирование в Windows. – СПб.: БХВ-Петербург, 2006

2. Лав Р. Linux. Системное программирование. – СПб.: Питер, 2008

3. Несвижский В. Программирование аппаратных средств в Windows. - СПб.: БХВ-Петербург, 2008

4. Джонсон М. Харт. Системное программирование в среде Win32. M.: Издательский дом «Вильямс», 2001

5. Джеффри Рихтер. Windows. Создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows/ Пер. с англ. — 4-е изд. — СПб.: Питер; М.: Издательство «Русская Редакция»; 2008

6. Ал Вильямс. Системное программирование в Windows 2000. - СПб.: Питер, 2001

7. Румянцев И.В. Азбука программирования в Win32 API. – М.: Горячая линия – телеком, 2001

ЛАБОРАТОРНАЯ РАБОТА № 3

Тема работы: Взаимодействие программы с пользователем. Диалоговые окна и их элементы. Меню и акселераторы

Цель работы: Приобрести практические навыки создания простейших программ для Windows с использованием Win32 API

В WINAPI определено множество типов данных, так же, как и в C/С++ (int, char, float и т.д.). Учить их определения не обязательно. Достаточно помнить, что они существуют, а когда они появятся или потребуются где-нибудь в программе, посмотреть их определения. В дальнейшем мы будем использовать их все. Условно их можно разделить на несколько видов: основные, дескрипторные, строковые и вспомогательные.

Основные типы

С основными типами данных трудностей возникнуть не должно. Если всё же возникнут, то нужно сюда.

BOOL – этот тип данных аналогичен bool. Он также имеет два значения – 0 или 1. Только при использовании WINAPI принято использовать вместо 0 спецификатор NULL. О нём ниже.

BYTE – байт, ну или восьмибитное беззнаковое целое число. Аналог – unsigned char.

DWORD — 32-битное беззнаковое целое. Аналоги: unsigned long int, UINT.

INT – 32-битное целое. Аналог – long int.

LONG – 32-битное целое – аналог всё также long int.

NULL – нулевой указатель. Вот его объявление:

?

void *NULL=0;

UINT – 32-битное беззнаковое целое. Аналоги: unsigned long int, DWORD.

Дескрипторные типы данных

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

?

HANDLE h;

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

(function(w, d, n, s, t) { w[n] = w[n] || []; w[n].push(function() { Ya.Direct.insertInto(142193, "yandex_ad_center", { ad_format: "direct", font_size: '14px', type: "728x90", links_underline: false, site_bg_color: "FFFFFF", title_color: "428BCA", url_color: "777777", text_color: "333333", hover_color: "0088CC", favicon: true, no_sitelinks: false }); }); t = d.getElementsByTagName("script")[0]; s = d.createElement("script"); s.src = "//an.yandex.ru/system/context.js"; s.type = "text/javascript"; s.async = true; t.parentNode.insertBefore(s, t); })(window, document, "yandex_context_callbacks"); ?

// получает дескриптор для устройства ввода или вывода: HANDLE h = GetStdHandle(DWORD nStdHandle);

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

Не будем вдаваться в физику создания дескрипторов. Разве что, при необходимости или для большего понимания процессов.

Примечание: для удобства в WINAPI предусмотрены сокращения для типов данных. Первая буква H – означает, что это дескриптор, от слова handle.

HANDLE – дескриптор объекта.

HBITMAP – дескриптор растрового изображения. От фразы handle bitmap.

HBRUSH – дескриптор кисти. От фразы handle brush.

HCURSOR – дескриптор курсора. От фразы handle cursor.

HDC – дескриптор контекста устройства. От фразы handle device context.

HFONT – дескриптор шрифта. От фразы handle font.

HICONS – дескриптор криптограммы. От фразы handle icons.

HINSTANCE – дескриптор экземпляра приложения. От фразы handle instance.

HMENU – дескриптор меню. От фразы handle menu.

HPEN – дескриптор пера. От фразы handle pen.

HWND – дескриптор окна. От фразы handle window.

Строковые типы данных

Для начала начнём, с того, какие кодировки существуют в Windows ОС.

Есть два вида кодировок символов: ANSI и UNICODE. Однобайтные символы относятся к ANSI, двухбайтные — к кодировке UNICODE. Мы можем с лёгкостью подключить UNICODE кодировку в свойствах проекта. И тогда в коде создать переменную типа char можно будет так:

?

// создаём строку из 10 элементов: wchar_t str[10];

Если же мы хотим использовать кодировку ANSI, то мы традиционно напишем:

?

// тоже создаём строку из 10 элементов: char str[10];

В WINAPI, в зависимости от того, подключён юникод или нет, используются два вида строк UNICODE-ные или TCHAR-ные. Ниже описаны строковые типы данных.

Всё также для удобства, первые две буквы LP – от фразы long pointer сигнализируют о том, что это указатель.

LPCSTR – указатель на константную строку, заканчивающуюся нуль-терминатором. От фразы long pointer constant string.

LPCTSTR – указатель на константную строку, без UNICODE. От фразы long pointer constant TCHAR string. Это надстройка функции LPCSTR.

LPCWSTR – указатель на константную UNICODE строку. От фразы фразы long pointer constant wide character string. Это надстройка функции LPCSTR.

LPSTR – указатель на строку, заканчивающуюся нуль-терминатором. От фразы long pointer string.

LPTSTR – указатель на строку, без UNICODE. От фразы long pointer TCHAR string. Это надстройка функции LPSTR.

LPWSTR – указатель на UNICODE строку. От фразы long pointer wide character string. Это надстройка функции LPSTR.

TCHAR – символьный тип — аналог char и wchar_t.

Вспомогательные типы

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

?

LRESULT CALLBACK ИмяФункции(HWND hWnd, UINT uMSg, WPARAM wParam, LPARAM lParam);

Работа с данной функцией будет в следующих разделах.

LPARAM – тип для описания lParam (long parameter). Используются вместе с wparam в некоторых функциях.

LRESULT – значение, возвращаемое оконной процедурой имеет тип long.

WPARAM – тип для описания wParam (word parameter). Используются вместе с lParam в некоторых функциях.

На этом типы данных не закончены. В дальнейшем мы обязательно будем обращаться к данной статье.

ЛАБОРАТОРНАЯ РАБОТА № 4

Тема работы: Общие элементы управления

Цель работы: Приобрести практические навыки создания простейших программ для Windows с использованием Win32 API

Итак, мы остановились на функции WinMain(). В её последних строках содержались вызовы двух функций, взаимодействующих с нашей функцией WndProc() (о ней здесь и будет идти речь) и оператор возврата значения функции. Конструкция функции WndProc() должна быть условно такая:

?

LRESULT CALLBACK WndProc(HWND hWnd, // дескриптор окошка UINT uMsg, // сообщение, посылаемое ОС WPARAM wParam, // параметры LPARAM lParam) // сообщений, для последующего обращения { // 1) создаём нужные переменные // 2) расписываем условия, при которых нужно выполнить нужное действие (switch) // 3) Возвращаем значение функции }

LRESULT – это возвращаемое значение. CALLBACK нужно писать, так как это функция обратного вызова. Сначала создаём необходимые переменные. Для начала создадим экземпляр контекста устройства HDC для нужной ориентации текста в окне. Кроме того, для обработки области окна нам нужны ещё две переменные RECT (прямоугольная область окна) и PAINTSTRUCT (в структуре информация об окне для прорисовки) соответственно:

?

// создаём нужные переменные: HDC hDC; PAINTSTRUCT ps; RECT rect; // и т.д.

Чтобы поменять цвет текста (и не только) нужно создать переменную типа COLORREF и присвоить ей возвращаемое значение функции RGB() (от англ. Red Green Blue) с тремя параметрами:

?

// создавали нужные переменные COLORREF colorText = RGB(255, 0, 0); // параметры int // и т.д.

Эта функция преобразовывает целочисленный тип в интенсивность цвета и возвращает значение смешивания трёх цветов (интенс. красн. + интенс. зел.+ интенс. син.). Как видно с помощью градаций этих цветов, можно создать 255*255*255= 16’581’375 цветов. ОС Windows и различные функции наших программ ежесекундно отправляют тысячи сообщений каждому отдельному приложению. Эти сообщения могут быть отправлены из-за нажатия клавиши или нажатия кнопки на мыши и т.д. Для этих случаев у нас существует структура MSG, описанная в WinMain(), которая хранит информацию об этих сообщениях. В WndProc() есть условия выбора для этих сообщений. Если ОС отправляет сообщение WM_PAINT, например, то в окне должно что-то рисоваться. Эти сообщения обрабатываются условием switch()(оператор множественного выбора), параметрами которого являются uMsg. uMsg мы создали при описании нашей функции WndProc(). Основной значение в этом операторе, без которых окно не будет обновляться после сворачивания и не закроется: WM_DESTROY. Также есть WM_PAINT, который нужен для прорисовки в клиентской области. WM – от слов Window Message. То есть:

?

// создавали переменные switch(uMsg){ case WM_PAINT: // что то рисуем case WM_DESTROY: // обязательно делаем условие закрытия окошка default: return DefWindowProc(hWnd, uMsg, wParam, lParam); // об этом далее }

И что же мы должны делать в этих «кейсах»? При посылке сообщения WM_PAINT – вызываем функции рисования BeginPaint(), GetClientRect(), SetTextColor(), DrawText(), EndPaint(). По названию видно, что эти функции делают. Функция BeginPaint() в прямом смысле начинает рисовать. Только для этого ей нужно иметь дескриптор окна и объект PAINTSTRUCT (у нас это ps). Она возвращает значение типа HDC, поэтому нам нужно присвоить ей hDc. GetClientRect() выбирает область. Параметры у неё аналогичны предыдущей функции: дескриптор окна и указатель на объект класса RECT (у нас это rect). Функция SetTextColor() возвращает цвет текста. Её параметры: возвращаемое значение функции BeginPaint() – hDC и указатель на объект класса COLORREF. Мы могли и не задавать отдельно цвет текста, создавая при этом переменную colorText, а могли сделать это прямо в ней. Но с точки зрения читаемости кода и его понятливости – это в корне не правильно. Старайтесь всегда объявлять переменные отдельно и писать в комментариях, зачем они нужны и тогда не будет вопросов, какие параметры имеет функция, спустя год как вы последний раз закрыли проект по WinAPI. Также соблюдайте венгерскую нотацию по программированию, суть которой: имена переменных должны нести смысл их существования и показывать тип данных. Объявление функции DrawText():

(function(w, d, n, s, t) { w[n] = w[n] || []; w[n].push(function() { Ya.Direct.insertInto(142193, "yandex_ad_center", { ad_format: "direct", font_size: '14px', type: "728x90", links_underline: false, site_bg_color: "FFFFFF", title_color: "428BCA", url_color: "777777", text_color: "333333", hover_color: "0088CC", favicon: true, no_sitelinks: false }); }); t = d.getElementsByTagName("script")[0]; s = d.createElement("script"); s.src = "//an.yandex.ru/system/context.js"; s.type = "text/javascript"; s.async = true; t.parentNode.insertBefore(s, t); })(window, document, "yandex_context_callbacks"); ?

int DrawText( HDC hDC,// дескриптор контекста устр-ва LPCTSTR lpchText, // указатель на нашу строку int nCount, // длина текста (если равно -1, то определяет сам) LPRECT lpRect, // указатель на объект RECT UINT uFormat // формат отображения текста );

На счёт первых 4х параметров всё ясно. Четвёртый uFormat – имеет несколько видов. Обычно используются DT_SINGLELINE, DT_CENTER и DT_VCENTER для отображения текста в центре области, в одну линию. Но Вы можете задать другие параметры (о чём поговорим в следующих уроках). Функция EndPaint() имеет два параметра: дескриптор окна и объект ps. Заметили аналогию с BeginPaint()? Что делать при вызове WM_PAINT, мы знаем (не забываем в конце дописать break). WM_DESTROY посылается окошку функцией DestroyWindow(), которая вызывается в случае, если мы его закрыли. А это происходит в операторе default. При этом происходит вызов функции DefWindowProc(), параметры которой те же, что и у WndProc(). В своём теле WM_DESTROY должен иметь функцию PostQuitMessage(), которая посылает WinMain() сообщение WM_QUIT. Её параметр обычно NULL, интерпретирующийся для главной функции WinMain(), как WM_QUIT.

?

VOID WINAPI PostQuitMessage(int nExitCode);

По завершению switch() мы возвращаем нулевое значение функции WndProc(). А теперь вернёмся к WinMain(), в частности к обработчику сообщений:

?

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

Функция GetMessage() имеет такое описание:

?

BOOL WINAPI GetMessage(LPMSG lpMsg, // указатель на структуру MSG HWND hWnd, // дескриптор окошка UINT wMsgFilterMin, // фильтры UINT wMsgFilterMax // фильтры для выборки сообщений );

Она обрабатывает сообщения, посылаемые ОС. Первый параметр – это адрес структуры MSG, в которую помещается очередное сообщение. Второй параметр — дескриптор окна. Третий и четвёртый параметры указывают порядок отбора сообщений. Обычно это нулевые значения и функция отбирает любые значения из очереди. Цикл прекращается, если она получает сообщение WM_QUIT. В таком случае она возвращает FALSE и мы выходим из программы. Функции TranslateMessage() и DispatchMessage() в цикле нужны для интерпретации самих сообщений. Обычно это используется при обработке нажатых кнопок на клавиатуре. В следующих уроках мы познакомимся с этими хитростями. По окончанию цикла мы возвращаем ОС код возврата msg.wParam. В итоге у нас должен получиться такой код:

?

#include <windows.h> // заголовочный файл, содержащий WINAPI   // Прототип функции обработки сообщений с пользовательским названием: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); TCHAR mainMessage[] = L"Какой то-текст!"; // строка с сообщением   // Управляющая функция: int WINAPI WinMain(HINSTANCE hInst, // дескриптор экземпляра приложения HINSTANCE hPrevInst, // не используем LPSTR lpCmdLine, // не используем int nCmdShow) // режим отображения окошка { TCHAR szClassName[] = L"Мой класс"; // строка с именем класса HWND hMainWnd; // создаём дескриптор будущего окошка MSG msg; // создём экземпляр структуры MSG для обработки сообщений WNDCLASSEX wc; // создаём экземпляр, для обращения к членам класса WNDCLASSEX wc.cbSize = sizeof(wc); // размер структуры (в байтах) wc.style = CS_HREDRAW | CS_VREDRAW; // стиль класса окошка wc.lpfnWndProc = WndProc; // указатель на пользовательскую функцию wc.lpszMenuName = NULL; // указатель на имя меню (у нас его нет) wc.lpszClassName = szClassName; // указатель на имя класса wc.cbWndExtra = NULL; // число освобождаемых байтов в конце структуры wc.cbClsExtra = NULL; // число освобождаемых байтов при создании экземпляра приложения wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // декриптор пиктограммы wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // дескриптор маленькой пиктограммы (в трэе) wc.hCursor = LoadCursor(NULL, IDC_ARROW); // дескриптор курсора wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // дескриптор кисти для закраски фона окна wc.hInstance = hInst; // указатель на строку, содержащую имя меню, применяемого для класса if(!RegisterClassEx(&wc)){ // в случае отсутствия регистрации класса: MessageBox(NULL, L"Не получилось зарегистрировать класс!", L"Ошибка", MB_OK); return NULL; // возвращаем, следовательно, выходим из WinMain } // Функция, создающая окошко: hMainWnd = CreateWindow( szClassName, // имя класса L"Полноценная оконная процедура", // имя окошка (то что сверху) WS_OVERLAPPEDWINDOW | WS_VSCROLL, // режимы отображения окошка CW_USEDEFAULT, // позиция окошка по оси х NULL, // позиция окошка по оси у (раз дефолт в х, то писать не нужно) CW_USEDEFAULT, // ширина окошка NULL, // высота окошка (раз дефолт в ширине, то писать не нужно) (HWND)NULL, // дескриптор родительского окна NULL, // дескриптор меню HINSTANCE(hInst), // дескриптор экземпляра приложения NULL); // ничего не передаём из WndProc if(!hMainWnd){ // в случае некорректного создания окошка (неверные параметры и тп): MessageBox(NULL, L"Не получилось создать окно!", L"Ошибка", MB_OK); return NULL; } ShowWindow(hMainWnd, nCmdShow); // отображаем окошко UpdateWindow(hMainWnd); // обновляем окошко while(GetMessage(&msg, NULL, NULL, NULL)){ // извлекаем сообщения из очереди, посылаемые фу-циями, ОС TranslateMessage(&msg); // интерпретируем сообщения DispatchMessage(&msg); // передаём сообщения обратно ОС } return msg.wParam; // возвращаем код выхода из приложения }   LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ HDC hDC; // создаём дескриптор ориентации текста на экране PAINTSTRUCT ps; // структура, сод-щая информацию о клиентской области (размеры, цвет и тп) RECT rect; // стр-ра, определяющая размер клиентской области COLORREF colorText = RGB(255, 0, 0); // задаём цвет текста switch(uMsg){ case WM_PAINT: // если нужно нарисовать, то: hDC = BeginPaint(hWnd, &ps); // инициализируем контекст устройства GetClientRect(hWnd, &rect); // получаем ширину и высоту области для рисования SetTextColor(hDC, colorText); // устанавливаем цвет контекстного устройства DrawText(hDC, mainMessage, -1, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER); // рисуем текст EndPaint(hWnd, &ps); // заканчиваем рисовать break; case WM_DESTROY: // если окошко закрылось, то: PostQuitMessage(NULL); // отправляем WinMain() сообщение WM_QUIT break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); // если закрыли окошко } return NULL; // возвращаем значение }

А после компиляции такое окошко:

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

ЛИТЕРАТУРА

1. Побегайло А. Системное программирование в Windows. – СПб.: БХВ-Петербург, 2006

2. Лав Р. Linux. Системное программирование. – СПб.: Питер, 2008

3. Несвижский В. Программирование аппаратных средств в Windows. - СПб.: БХВ-Петербург, 2008

4. Джонсон М. Харт. Системное программирование в среде Win32. M.: Издательский дом «Вильямс», 2001

5. Джеффри Рихтер. Windows. Создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows/ Пер. с англ. — 4-е изд. — СПб.: Питер; М.: Издательство «Русская Редакция»; 2008

6. Ал Вильямс. Системное программирование в Windows 2000. - СПб.: Питер, 2001

7. Румянцев И.В. Азбука программирования в Win32 API. – М.: Горячая линия – телеком, 2001

ЛАБОРАТОРНАЯ РАБОТА № 5

Тема работы: Структура реестра. Работа с реестром

Цель работы: Приобрести практические навыки работы с реестром Windows с использованием Win32 API

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

Копирование файлов, часто с обновлением, и объединением отсортированных файлов – распространенные формы последовательной обработки. Простое копирование позволяет определить сильные и слабые стороны разных систем и перейти к Win32.

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

Содержание работы

1. Изучить программы копирования файлов.

2. Последовательно набрать и отладить программы копирования файлов в среде Visual Studio C++ .NET 2003.

3. Выполнить задание по копированию файла 1 в файл 2, выбрав произвольные имена файлов в различных программах.

4. Подготовить отчет по выполненной работе.

5. В отчете ответить на контрольные вопросы.

5. Порядок выполнения программ в среде Visual C++ .NET 2003

1. Запустить Microsoft Visual Studio C++ .NET 2003.

2. Создать проект под именем cpC. Для этого выполнить команды меню File, New, Project.

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Рис.1. Создание нового проекта cpC консольного приложения

На появившейся вкладке New Project выбрать Win32 Console Project, в окне Name: набрать имя проекта cpC. В окне Location: набрать путь к папке, в которой будет записан проект и щелкнуть мышью OK. На появившейся вкладке щелкнуть мышью Finish.

3.На экране появляется текст файла cpC.cpp, в котором находится заготовка программы консольного приложения.

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Рис 2. Содержимое файла cpC.cpp

4.После набора текста программы выполняется ее редактирование с использованием из меню Build команды Build Solution. В случае исправления всех ошибок в папке Debug проекта создается исполняемый файл с расширением .exe - cpC.exe, который необходимо выполнить.

5.Выполнение программы производится из командной строки. Для этого можно использовать программу Far, при этом следует указать имя исходного файла, который должен быть создан до запуска программы cpC.exe, и имя файла, куда производится копирование.

6.Аналогично выполняется создание проектов cpW, cpCF, создание исполняемых файлов cpW.exe, cpCF.exe и выполнение программ копирования файлов с использованием Win32 и фунции-полуфабриката Win32.

Содержание отчета

В отчет должны быть включены следующие разделы:

1.Общие сведения об интерфейсе прикладного программирования API Win32.

2.Особенности использования API Win32 для копирования файлов.

3.Листинги различных программ копирования файлов.

4.Результаты копирования файлов, выполненных с использованием стандартной библиотеки С, с использованием Win32 и с использованием функции-полуфабриката Win32.

7.Контрольные вопросы

1. Что такое API Win32?

2. Какие операционные системы обслуживает API Win 32?

3.Какие особенности имеет API Win 32?

4. Какие преимущества программирования дает API 32?

5. Какой основной тип переменных используется в Win 32?

6. Для управления каких систем могут быть написаны программы с использованием Win32?

7. Что означает строка int main (int argc, LPTSTR argv [])?

8. Поясните, какую функцию выполняет данный оператор: hIn = CreateFile (argv [1], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

9. Поясните, какую функцию выполняет данный оператор: hOut = CreateFile (argv [2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

10.Поясните, какую функцию выполняет данный оператор: while (ReadFile (hIn, Buffer, BUF_SIZE, &nIn, NULL) && nIn > 0)

11. Поясните, какую функцию выполняет данный оператор: WriteFile (hOut, Buffer, nIn, &nOut, NULL);

12. Поясните, какую функцию выполняет данный оператор: if (!СopyFile (argv [1], argv [2], FALSE)).

ЛИТЕРАТУРА

1. Побегайло А. Системное программирование в Windows. – СПб.: БХВ-Петербург, 2006

2. Лав Р. Linux. Системное программирование. – СПб.: Питер, 2008

3. Несвижский В. Программирование аппаратных средств в Windows. - СПб.: БХВ-Петербург, 2008

4. Джонсон М. Харт. Системное программирование в среде Win32. M.: Издательский дом «Вильямс», 2001

5. Джеффри Рихтер. Windows. Создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows/ Пер. с англ. — 4-е изд. — СПб.: Питер; М.: Издательство «Русская Редакция»; 2008

6. Ал Вильямс. Системное программирование в Windows 2000. - СПб.: Питер, 2001

7. Румянцев И.В. Азбука программирования в Win32 API. – М.: Горячая линия – телеком, 2001

ЛАБОРАТОРНАЯ РАБОТА № 6

Тема работы: Запуск и завершение процесса. Создание и завершение потока. Синхронизация

Цель работы: Приобрести практические навыки работы с потоками в ОС Windows с использованием Win32 API

Ниже представлен листинг:

?

#include <windows.h>   LRESULT CALLBACK WindowProcess(HWND, UINT, WPARAM, LPARAM);   int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCommandLine, int nCommandShow){ TCHAR className[] = L"Мой класс"; HWND hWindow; MSG message; WNDCLASSEX windowClass;   windowClass.cbSize = sizeof(windowClass); windowClass.style = CS_HREDRAW | CS_VREDRAW; windowClass.lpfnWndProc = WindowProcess; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = className; windowClass.cbWndExtra = NULL; windowClass.cbClsExtra = NULL; windowClass.hIcon = LoadIcon(NULL, IDI_WINLOGO); windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); windowClass.hInstance = hInst;   if(!RegisterClassEx(&windowClass)) { MessageBox(NULL, L"Не получилось зарегистрировать класс!", L"Ошибка", MB_OK); return NULL; } hWindow = CreateWindow(className, L"Программа ввода символов", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, NULL, CW_USEDEFAULT, NULL, (HWND)NULL, NULL, HINSTANCE(hInst), NULL ); if(!hWindow){ MessageBox(NULL, L"Не получилось создать окно!", L"Ошибка", MB_OK); return NULL; } ShowWindow(hWindow, nCommandShow); UpdateWindow(hWindow); while(GetMessage(&message, NULL, NULL, NULL)){ TranslateMessage(&message); DispatchMessage(&message); } return message.wParam; }   LRESULT CALLBACK WindowProcess(HWND hWindow, UINT uMessage, WPARAM wParameter, LPARAM lParameter) { HDC hDeviceContext; PAINTSTRUCT paintStruct; RECT rectPlace; HFONT hFont; static char text[2]={' ','\0'}; switch (uMessage) { case WM_CREATE: MessageBox(NULL, L"Пожалуйста, вводите символы и они будут отображаться на экране!", L"ВНИМАНИЕ!!!", MB_ICONASTERISK|MB_OK); break; case WM_PAINT: hDeviceContext = BeginPaint(hWindow, &paintStruct); GetClientRect(hWindow, &rectPlace); SetTextColor(hDeviceContext, NULL); hFont=CreateFont(90,0,0,0,0,0,0,0, DEFAULT_CHARSET, 0,0,0,0, L"Arial Bold" ); SelectObject(hDeviceContext,hFont); DrawText(hDeviceContext, (LPCWSTR)text, 1, &rectPlace, DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hWindow, &paintStruct); break; case WM_KEYDOWN: switch (wParameter) { case VK_HOME:case VK_END:case VK_PRIOR: case VK_NEXT:case VK_LEFT:case VK_RIGHT: case VK_UP:case VK_DOWN:case VK_DELETE: case VK_SHIFT:case VK_SPACE:case VK_CONTROL: case VK_CAPITAL:case VK_MENU:case VK_TAB: case VK_BACK:case VK_RETURN: break; default: text[0]=(char)wParameter; InvalidateRect(hWindow, NULL, TRUE); break; }break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWindow, uMessage, wParameter, lParameter); } return NULL; }

Данная программа выводит цифры и буквы, при этом не реагирует на нажатие дополнительных клавиш, типа enter, shift и т.д.

В функции WinMain() ничего нового. А в WindowProcess() мы добавили обработчики событий нажатия клавиши.

Нажатие любой клавиши автоматически посылает системе аппаратное сообщение, которое обрабатывается и высылается приложению. За эту операцию отвечает сообщение WM_KEYDOWN.

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

С 87-й по 101-ю строки мы обрабатываем сообщение WM_KEYDOWN (нажатие клавиши). Сначала мы создаём переключатель switch для значения wParameter, куда записан идентификатор клавиши. С 90-й по 95-ю строки мы исключаем значения home, end, page up, page down, стрелка влево, стрелка вправо, стрелка вверх, стрелка вниз, delete, shift, space, ctrl, caps lock, alt, tab, backspace, enter соответственно. Возможно, на вашей клавиатуре есть ещё клавиши, вы можете также их исключить при необходимости, потому что при нажатии будет «абракадабра». То есть если в идентификаторе wParameter у нас эти значения, мы ничего не делаем – в 96-й строке оператор break.

А под значениями default у нас выполняется преобразование. В 66 строке мы создали статическую строку типа char из 2-х элементов. Статическая она, потому что в процессе работы программы мы неоднократно выходим из WindowProcess() в цикл обработки с GetMessage(), расположенный в WinMain(), а значение клавиши нам нужно сохранять. Ну а в 98 строке мы инициализируем её первый элемент wParameter-ом.

В следующей строке мы вызываем функцию InvalidateRect(), после чего выходим из WM_KEYDOWN. Первым параметром идёт – дескриптор окна, вторым – область будущего «затирания» окна (NULL – всё окно перерисовывается в WM_PAINT), третьим параметром идёт «затирание» фона (если TRUE, то стираем). При этом мы автоматически посылаем приложению message WM_PAINT и окно перерисовывается заново. Для чего это нужно?

Как мы помним в случаях сворачивания, перемещения окна вызывается WM_PAINT. Нам же это нужно сделать явно, то есть сделать окно недействительным, для того, чтобы сразу вывести значение нажатой клавиши на экран. Иначе она появится только тогда, когда мы начнём манипулировать окном.

Теперь возвратимся 65-й строке. В ней объявлен экземпляр класса HFONT, который отвечает за шрифт, его размер и другие премудрости. Он будет использоваться в WM_PAINT.

В 69-й строке есть обработчик сообщения WM_CREATE. Он срабатывает, когда создаётся окно, то есть вызывается функция CreateWindow(). На этом этапе решено создать дополнительное окно с сообщением для удобства (строки 70-72).

Наконец, обработчик WM_PAINT. С 75-й по 77-ю строки происходит вызов функций контекста устройства (описывалось в статье).

А с 78-й по 82-ю строки вызывается функция CreateFont(). С её помощи мы меняем шрифт, и размер буквы. Вот её описание:

?

HFONT CreateFont(int, // высота шрифта int, // ширина символов int, // угол наклона букв int, // угол наклона строки int, // толщина букв («жирность») DWORD, // курсив DWORD, // подчеркивание DWORD, // перечеркивание DWORD, // набор символов DWORD, // точность вывода DWORD, // точность отсечения DWORD, // качество вывода DWORD, // шаг между буквами LPCTSTR // имя шрифта );

Шрифт выставлен Arial Bold – то есть Arial жирным. В строке 83 мы задаём контексту изменённые параметры шрифта. С 84-й по 85-ю строки ничего нового. Мы вводим на экран полученный идентификатор клавиши, преобразованный в тип char. В функции DrawText() его нужно преобразовать к типу LPCWSTR, что она и требует.

Результат работы программы при вводе буквы «с» такой:

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Для начала убедитесь, что Вы разбираетесь в выделении памяти с помощью функции alloc (malloc), free, с помощью операторов new, delete и понимаете функцию преобразованию itoa().

Рассмотрим листинг, представленный ниже:

?

LRESULT CALLBACK WindowProcess(HWND hWindow, UINT uMessage, WPARAM wParameter, LPARAM lParameter) { HDC hDeviceContext; PAINTSTRUCT paintStruct; RECT rectPlace; HFONT hFont;   static PTCHAR text; static int size = 0;   switch (uMessage) { case WM_CREATE: text=(PTCHAR)GlobalAlloc(GPTR,50000*sizeof(TCHAR)); break; case WM_PAINT: hDeviceContext = BeginPaint(hWindow, &paintStruct); GetClientRect(hWindow, &rectPlace); SetTextColor(hDeviceContext, NULL); hFont=CreateFont(50,0,0,0,0,0,0,0, DEFAULT_CHARSET, 0,0,0,VARIABLE_PITCH, "Arial Bold"); SelectObject(hDeviceContext,hFont); if(wParameter != VK_RETURN) DrawText(hDeviceContext, (LPCSTR)text, size, &rectPlace, DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hWindow, &paintStruct); break; case WM_CHAR: switch(wParameter) { case VK_RETURN: size=0; break; default: text[size]=(char)wParameter; size++; break; } InvalidateRect(hWindow, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(NULL); GlobalFree((HGLOBAL)text); break; default: return DefWindowProc(hWindow, uMessage, wParameter, lParameter); } return NULL; }

Результат после ввода CppStudio.com будет таким:

Создание полноценной оконной процедуры в Win32 API (Часть 1) - student2.ru

Код для функции WinMain не приводится, так как он не менялся с предыдущих уроков.

Данная программа позволяет вводить текст по мере возможности и стирать его клавишей ENTER.

Наверное, Вы заметили, что в программе в пред

Наши рекомендации