Описание функций библиотеки windows h
КАК быстро освоить API?
Чтобы понять что мы будем изучать, предлагаю вам на минутку перенестись в далёкие 80-ые годы теперь уже прошлого века! То были времена безраздельного правления злого волшебника DOSa. До появления доброй феи — оконной оболочки Windows труд угнетённых программистов был тяжёлым и рутинным. Подобно рудокопам, пробивающим себе дорогу в каменной породе железными молотками, писали они свои программы. Большинство программ — утилиты, базы данных, информационные системы — создавались тогда в текстовом режиме — унылом и беспросветном, где существует только 16 цветов и где экран — крохотное поле 80X25 символов. Те же смельчаки, которые решались предоставить пользователю графический интерфейс, были настоящими героями.
Почему? Ну, во-первых, никаких специальных функций для работы с графикой в DOS не было и в помине, и практически каждому разработчику приходилось либо писать свои собственные библиотеки или классы для работы с графикой, каждый раз изобретая велосипед, либо использвать те, что создали его коллеги. Это был тихий ужас! Писать графические функции приходилось чуть ли не не ассмеблере, генерируя 10-й вектор прерывания. И вот печальный итог — каждая фирма создавала свои библиотеки шрифтов, картинок и элементов управления. И каждый раз, проектируя новую программу, приходилось возвращаться к той самой печке и заново придумывать интерфейс пользователя. Представьте себе, что не было никаких стандартов, и каждый программист делал интерфейс, как Бог на душу пошлёт. Так это хорошо! — Скажете вы, — никто не зависел от стандартов, навязанных Microsoft, было простор для творчества. Так-то оно так, только программисты, которые пишут непонятные программы, отвечают, что они никакие не дизайнеры и проектировать интерфейс пользователя не их задача. В результате, очень часто программы ещё худо-бедно работали, но работать в них было сущим мучением.
Бедный пользователь был вынужден каждый раз тратить драгоценное время, чтобы понять — что же программист хотел этим сказать, когда сделал именно такие кнопки и, простите, как всё это работает?
Разработчикам игр было хуже всех. Для того, чтобы написать такую игру, как DOOM, надо было опускаться к самым низам и программировать уже не столько DOS, сколько железо, напрямую обращаясь к видеопамяти PCI видеокарты — иначе не будет быстродействия, ведь тормозит обычно графика. А если вспомнить, что в составе MS-DOS никогда не было никаких драйверов, то приходилось учитывать все популярные на тот момент видеокарты, программируя графику для каждого типа отдельно, чтобы потом игра вообще пошла! Может быть вы помните те времена, когда приходилось вручную указывать тип видеокарты, а для звуковой карты указывать IRQ, DMA и количество каналов? Какой пользователь может это знать?
С появлением Windows появилась прекрасная возможность сосредоточить свои силы не столько на внешнем обрамлении программы — кнопках, флажках и меню, сколько на её содержании, сути — том, что она реально делает. Это на самом деле важно, так как труд программистов занимает много времени, а значит, стоит больших затрат. Для разработчиков на языке СИ была написана обширная библиотека windows.h, включавшая в себя всю поднаготную Windows и позволявшая в значительной степени унифицировать процесс разработки. А следовательно, и снизить затраты на разработку ПО. Всю эту огромную спецификацию программирования под Windows назвали API (Application Programming Interface) — интерфейс прикладного программирования.
API покрывает собой всё — графику, элементы управления, системные функции, работу с устройствами и ещё многое другое. По сути, API функции это промежуточно звено между пользователем и ядром операционной системы. При работе программы API функции превращаются в системные вызовы и обрабатываются ядром ОС. Ядро в свою очередь позволяет скрыть от программиста всё железо, представляя всё hardware, как виртуальные устройства — виртуальную видеокарту, виртуальный монитор, виртуальный принтер.
Время шло, и компанией Microsoft была разработана библиотека классов MFC (Microsoft Foundation Classes), а компанией Borland OWL (Object Window Library), облачившие API в объектно-ориентированный вид. Теперь уже никто не программирует окна и графику на процедурном API с нуля, для этого есть другие, более универсальные средства. Но несмотря на это, до сих пор API поддерживается всеми библиотеками классов и очень широко используется. Ни одна библиотека классов не включает в себя всех API-функций. Очень часто разработчики решают за нас — что нам нужно, а без чего мы обойдёмся. Всегда, когда под рукой нет нужного средства, на помощь приходят API-функции. И если вы хотите, чтобы программа работала быстрее, а выполнимый файл занимал меньше места, не ленитесь использовать API-функции.
Ежегодно спецификация API пополняется новыми функциями, которые внедряются в систему с помощью патчей и сервисных пакетов. С каждой новой версией Windows, API разрастается в геометрической прогрессии, и выпускаемые по ней спецификации выглядят уже, как многотомные энциклопедии. Это основа-основ Windows. Используя нужные API-функции, вы всегда сможете сделать в всё, что захотите. Windows станет для вас ласковым ручным котёнком. Вы сможете рисовать на экране всё, что захотите, и самое удивительное — это будет работать!
В последнее время выходит великое множество литературы, посвящённой «интересным возможностям Windows», вроде «Windows глазами хаккера» или «Прикольные штучки для Windows», «Как напугать пользователя». Большинство исходных текстов в них написано именно на API.
Поскольку мы только начинаем изучение программирования для Windows, процедурный API-код подойдёт нам как нельзя лучше. Он поможет понять механизм программирования для Windows, даст нам базовые знания об этой операционной системе, её принципах и механизмах, подготовив в полной мере к изучению библиотек классов MFC и VCL. Изучив работу элементов управления, мы рассмотрим некоторые неочевидные на первый взгляд возможности Windows, заглянув за ту самую запретную черту, куда можно попасть только зная язык API.
КАК можно обойтись только windows.h?
Разработчики Windows в своё время явно погорячились, когда решили, что программист обойдётся одним единственным библиотечным файлом. Сначала было всё ничего, но он стал разрастаться и если бы вы его решили распечатать, вам пришлось бы сразу купить новый картридж для принтера и толстенную пачку бумаги. С каждой новой версией Windows число API функций всё прибывало, росло число структур, макросов и типов данных. На сегодняшний день windows.h включает в себя более 1000 одних только констант.
#define WM_QUIT 0x0012
А кроме того, прототипы ВСЕХ API-функций. Что было делать? Современный файл windows.h разделили на 3 составляющих по назначению: kernel, user и gdi. Теперь эти файлы носят такие названия:
winuser.h — объявления из модуля USER.EXE или ассоциированые с ним
wingdi.h — интерфейс графических устройств (GDI), работа с графикой
windef.h — определение фундаментальных типов данных
winnls.h — поддержка национального языка в локализованных версиях
wincon.h — консольный ввод-вывод, минующий интерфейс графических устройств
winbase.h — базовый программный интерфейс.
и другие.
В любом случае, к API-программе придётся подключать только windows.h. И это большой плюс. В программировании под DOS приходилось отдельно подключать библиотеку для работы со строками string.h, графическую библиотеку graphics.h, библиотеку ввода-вывода stdio.h. Windows.h «знает» не только все API-функции, но кроме того ещё и все функции языка СИ, которые мы использовали раньше. Многие библиотеки, которые в DOS актуальны, с началом программирования для Windows сразу отошли в мир иной это:: graphics.h, dir.h, stdio.h, conio.h, stdlib.h, process.h, dos.h. Не скоро теперь они встретятся нам на пути!
Файл windows.h существует до сих пор и пополняется новыми функциями и обновляется с каждой новой версией Visual Studio. При использовании библиотек классов MFC вы не будете его подключать, но только потому, что он уже подключён. В первых программах на API мы будем использовать именно его.
Стандартные функции Windows
В программе используются функции, описанные в различных заголовочных файлах из стандартной библиотеки windows.h:
LoadIcon – загружает значок (Icon) для использования в программе;
LoadCursor – загружает курсор (Cursor) мыши;
GetStockObject – получает графический объект – кисть (Stock);
RegisterClassEx – регистрирует класс окна;
CreateWindow – создает окно на основе класса окна;
ShowWindow – выводит окно на экран;
UpdateWindow – заставляет окно перерисовать свое содержимое;
GetMessage – получает сообщение из очереди сообщений;
TranslateMessage – преобразует некоторые сообщения, полученные с помощью клавиатуры;
DispatchMessage – отправляет сообщение оконной процедуре;
BeginPaint – инициирует начало процесса рисования окна;
GetClientRect – получает размер рабочей области окна;
DrawText – выводит на экран строку текста;
EndPaint – прекращает рисование окна;
PostQuitMessage – вставляет сообщение «Завершить» в очередь сообщений;
DefWindowProc – выполняет обработку сообщений по умолчанию.
Идентификаторы и типы данных
При программировании в среде Windows используют соглашения по именованию переменных – идентификатор переменной составляется из букв или частей слов, отражающих смысл этой переменной.
Префиксы некоторых переменных, использующихся в дальнейшем: c – символ; by –BYTE (беззнаковый символ); n –короткое целое; i –целое; cx, cy – целое (длины x и y; с означает счет – count); b или f –BOOL (булево целое, f – флаг – flag); w – WORD (беззнаковое короткое целое); l – LONG (длинное целое); dw – DWORD (беззнаковое длинное целое); fn – функция; s – строка; sz –строка, завершаемая нулем (string terminated by zero); h –описатель (handle); p – указатель (pointer).
Идентификаторы, написанные прописными буквами, задаются в заголовочных файлах Windows. Двух- или трехбуквенный префикс, за которым следует символ подчеркивания, показывает основную категорию ее принадлежности, например: CS – опция стиля класса (Class Style); IDI – идентификационный номер иконки (ID Icon); IDC – идентификационный номер курсора; WS – стиль окна (windows style); WM – cообщение окна.
Аналогичен смысл новых типов данных, например, тип UINT – 32-разрядное беззнаковое целое (unsigned int), PSTR – указатель на строку символов (pointer string), т.е. char*; LONG – длинное целое.
WndProc возвращает значение типа LRESULT – Long RESULT. Функция WinMain получает тип WINAPI (как и любая другая функция Windows), а функция WndProc получает тип CALLBACK – эти идентификаторы являются ссылкой на особую последовательность вызовов функций, которая имеет место между ОС Windows и ее приложением.
В программе использованы структуры данных: MSG – структура сообщения (message); WNDCLASSEX – структура класса окна; PAINTSTRUCT – структура рисования; RECT – структура прямоугольника.
При обозначении переменных структуры пользуются именем самой структуры и строчными буквами, например, переменная msg – структура типа MSG; wndclass – структура типа WNDCLASSEX.
В программе используются идентификаторы, предназначенные для разных типов описателей (handles): HINSTANCE – описатель экземпляра (instance) самой программы; HWND – описатель окна (handle to a window); HDC – описатель контекста устройства.
Основная программа
Для работы программы подключен файл windows.h, содержащий заголовочные файлы с объявлениями функций, структур и числовых констант. Далее следует декларация прототипа функции WndProc – «оконная процедура» для окна программы Hello.
Основной функцией (точкой входа программы), аналогом стандартной функции main языка Си для Windows является функция WinMain:
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow);
использующая последовательность вызовов WINAPI и возвращающая ОС Windows целое значение. В ней используются четыре параметра:
hInstance – описатель экземпляра – уникальное число, идентифицирующее программу;
hPrevInstance – предыдущий (previous) экземпляр; если в данный момент не было загружено копий программы, то hPrevInstance = 0 или NULL;
szCmdLine – указатель на строку, в которой содержатся любые параметры, переданные в программу из командной строки;
iCmdShow – число, показывающее, каким должно быть выведено на экран окно в начальный момент; обычно: SW_SHOWNORMAL (1) – вывод окна нормального размера, SW_SHOWMINNOACTIVE (7) – окно должно быть изначально свернутым; префикс SW означает «показать окно» (show window).
Регистрация класса окна
Окно всегда создается на основе класса окна. Класс окна идентифицирует оконную процедуру, которая выполняет процесс обработки поступающих сообщений.
Перед созданием окна необходимо зарегистрировать класс окна, вызвав функцию RegisterClassEx, это расширенная версия функции Register-Class (Ex – extended – расширенный). Параметр функции – указатель на структуру типа WNDCLASSEX, определенную в заголовочных файлах:
typedef struct tagWNDCLASSEX <
> WNDCLASSEX;
Префиксы LP и lp означают «длинный указатель» (long pointer), приставка lpfn – «длинный указатель на функцию» (long pointer to a function); приставка cb – «счетчик байт» (counter of bytes); префикс hbr – это «описатель кисти» (handle to a brush).
Для работы WinMain необходимо определить эту структуру:
WNDCLASSEX wndclass;
наиболее важными в ней являются второе и третье от конца поля. Второе поле – имя класса окна (обычно совпадает с именем программы), третье поле – адрес оконной процедуры, использующейся для всех окон, созданных на основе этого класса. Другие поля описывают характеристики окон, создаваемых на основе этого класса окна.
Поле cbSize равно длине структуры. Инструкция:
wndclass.style = CS_HREDRAW | CS_VREDRAW;
осуществляет объединение двух идентификаторов «стиля класса» с помощью поразрядной операции «ИЛИ» (|). В заголовочных файлах Windows, идентификаторы, начинающиеся с префикса CS, задаются в виде 32-разрядной константы, только один из разрядов которой установлен в 1. Например, CS_VREDRAW (горизонтальный) – 0x0001, а CS_HREDRAW (вертикальный) – 0x0002 показывают, что все окна должны целиком перерисовываться при изменении размеров окна. Эти идентификаторы называют «поразрядными флагами» (bit flags).
Третье поле wndclass.lpfnWndProc = WndProc; устанавливает оконную процедуру данного окна.
Следующие две инструкции:
wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0;
резервируют дополнительное пространство, которое может быть использовано программой, в данной программе эта возможность не используется – значения равны 0, иначе в этом поле было бы установлено «число байт» резервируемой памяти.
В следующем поле – описатель экземпляра программы, который является одним из параметров WinMain:
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
устанавливают значки (иконки), которые появляется на панели задач и в заголовке окна. Для получения описателя стандартного значка первый параметр устанавливается в NULL; при загрузке пользовательского значка этот параметр должен быть равен описателю экземпляра программы. Второй параметр определяется в заголовочных файлах, значок IDI_APPLICATION – это маленькое изображение окна. Функция LoadIcon возвращает описатель этого значка для полей wndclass.hIcon и wndclass.hIconSm, имеющих тип HICON («описатель значка» – handle to an icon).
Функция LoadCursorзагружает стандартный курсор IDC_ARROW и возвращает его описатель полю hCursor:
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
Поле hbrBackground задает цвет фона рабочей области окон (префикс hbr означает «описатель кисти» – handle to a brush). Кисть – графический объект, используемый для закрашивания области. В Windows имеется несколько стандартных кистей. В инструкции
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
функция GetStockObject возвращает описатель белой кисти.
Следующее поле задает меню класса окна, т.к. в нашем случае оно отсутствует – поле установлено в NULL:
На последнем этапе классу должно быть присвоено имя, которое может совпадать с именем программы, хранящемся в переменной szAppName:
После того как инициализированы все поля структуры, регистрируем класс окна, вызывая функцию: RegisterClassEx (&wndclass);
Создание окна
Класс окна определяет основные характеристики окна, что позволяет использовать один и тот же класс для создания множества различных окон.
Функция CreateWindow создает окно, детализируя информацию о нем, которая должна передаваться функции в качестве параметров:
hwnd = CreateWindow (szAppName, – имя класса окна;
«First Example», – заголовок окна;
WS_OVERLAPPEDWINDOW, – стиль окна;
CW_USEDEFAULT, – начальное положение по x
CW_USEDEFAULT, и по y;
CW_USEDEFAULT, – начальные размеры по x
CW_USEDEFAULT, и по y;
NULL, – описатель родительского окна;
NULL, – описатель меню окна;
hInstance, – описатель экземпляра программы;
NULL); – параметры создания.
Параметр «имя класса окна» – szAppName содержит строку «Hello», являющуюся именем зарегистрированного класса окна, этот параметр связывает окно с классом окна.
Окно, созданное программой, является обычным перекрывающимся окном с заголовком, системным меню слева на строке заголовка, иконками для сворачивания, разворачивания и закрытия окна.
WS_OVERLAPPEDWINDOW – стандартный «стиль окна»; «заголовок окна» – текст, который выводится в строке заголовка.
Параметры «начальное положение по x и по y» задают начальные координаты верхнего левого угла окна относительно левого верхнего угла экрана; идентификатор CW_USEDEFAULT задает по умолчанию начальное положение для перекрывающегося окна; аналогично задаются значения параметров «начальные размеры по x и по y».
Поскольку у нашего окна отсутствует родительское окно, параметр «описатель родительского окна» – NULL; аналогично «описатель меню окна» – NULL (у окна нет меню).
В параметр «описатель экземпляра программы» помещается описатель экземпляра, переданный программе в качестве параметра функции WinMain.
Значение «параметры создания» установлено в NULL, при необходимости этот параметр используется в качестве указателя на данные, к которым программа в дальнейшем могла бы обратиться.
Функция CreateWindow возвращает описатель созданного окна, который хранится в переменной hwnd типа. У каждого окна в Windows имеется его описатель, который используется для ссылки на это окно. При создании нескольких окон каждое из них имеет свой описатель, являющийся одним из важнейших, которыми оперирует программа для Windows.
Для многих функций Windows в качестве параметра требуется hwnd, благодаря чему Windows знает, к какому окну применить эту функцию.
Отображение окна
К тому времени, когда функция CreateWindow возвращает управление программе, окно уже создано внутри Windows, однако на экране монитора оно еще не появилось. Выводит окно на экран функция
ShowWindow (hwnd, iCmdShow);
параметр hwnd – описатель созданного окна; параметр iCmdShow – задает начальный вид окна на экране: SW_SHOWNORMAL (1) – на экран выводится обычное окно, фон рабочей области закрашивается заданной в классе окна кистью; SW_SHOWMINNOACTIVE (7) – окно не выводится, а на панели задач появляются его имя и иконка.
Функция UpdateWindow (hwnd); выполняет перерисовку рабочей области окна, посылая сообщение WM_PAINT в оконную процедуру (WndProc).
Цикл обработки сообщений
Программа получает информацию от пользователя через клавиатуру и мышь. Для каждой программы, работающей в данный момент, Windows поддерживает «очередь сообщений» (message queue). Когда происходит ввод информации, она преобразуется в «сообщение», которое помещается в эту очередь.
Программа извлекает сообщения из очереди, выполняя блок соответствующих команд, известный как «цикл обработки сообщений» (message loop):
while (GetMessage (&msg, NULL, 0, 0)) <
TranslateMessage (&msg);
DispatchMessage (&msg);
Переменная msg – структура типа MSG, определенная следующим образом: