Win32 API
Работа с окнами
Поиск…
Создание окна
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
const TCHAR CLSNAME[] = TEXT("helloworldWClass");
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PTSTR cmdline,
int cmdshow)
{
WNDCLASSEX wc = { };
MSG msg;
HWND hwnd;
wc.cbSize = sizeof (wc);
wc.style = 0;
wc.lpfnWndProc = winproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLSNAME;
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, TEXT("Could not register window class"),
NULL, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
NULL,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hwnd) {
MessageBox(NULL, TEXT("Could not create window"), NULL, MB_ICONERROR);
return 0;
}
ShowWindow(hwnd, cmdshow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
{
return DefWindowProc(hwnd, wm, wp, lp);
}
Первое, что можно увидеть, - это два макроопределения UNICODE
и _UNICODE
. Эти макросы заставляют нашу программу понимать широкие символьные строки ( wchar_t[n]
), а не простые узкие строки ( char[n]
). В результате все строковые литералы должны быть завернуты в TEXT(
макрос). TCHAR
типом символа для строк Win32 является TCHAR
, определение которого зависит от того, определен ли UNICODE
. Включен новый заголовок: <tchar.h>
содержит декларация TCHAR
.
Окно состоит из так называемого класса окна . Это описывает информацию о окне, которое должно делиться между его экземплярами, например, значком, курсором и другими. Класс окна идентифицируется именем класса окна, который указан в глобальной переменной CLSNAME
в этом примере. Первый акт WinMain
состоит в том, чтобы заполнить структуру класса окон, WNDCLASSEX wc
. Участники:
- cbSize: размер, в байтах, структуры
- style: стили класса окна. На данный момент это 0.
- lpfnWndProc: Это одно из наиболее важных полей. Он хранит адрес оконной процедуры . Процедура окна - это функция, которая обрабатывает события для всех окон, которые являются экземплярами этого класса окна.
- cbClsExtra: количество дополнительных байтов для выделения класса окна. Для большинства ситуаций этот член равен 0.
- cbWndExtra: количество дополнительных байтов для каждого отдельного окна. Не путайте это с
cbClsExtra
, что является общим для всех экземпляров. Это часто 0. - hInstance: дескриптор экземпляра. Просто назначьте аргумент
hInst
вWinMain
в это поле. - hIcon: дескриптор значка для класса окна.
LoadIcon(NULL, IDI_APPLICATION)
загружает значок приложения по умолчанию. - hКурсор: указатель курсора для класса окна.
LoadCursor(NULL, IDC_ARROW)
загружает курсор по умолчанию. - hbrBackground: ручка для фоновой кисти.
GetStockObject (WHITE_BRUSH)
дает ручку белой кисти. Возвращаемое значение должно бытьGetStockObject
потому чтоGetStockObject
возвращает общий объект. - lpszMenuName: имя ресурса в строке меню. Если строка меню не требуется, это поле может быть NULL.
- lpszClassName: имя класса, которое идентифицирует эту структуру класса окна. В этом примере глобальная переменная
CLSNAME
хранит имя класса окна. - hIconSm: дескриптор значка маленького класса.
После инициализации этой структуры вызывается функция RegisterClassEx
. Это заставляет класс окна регистрироваться в Windows, что делает его известным приложению. Он возвращает 0 при сбое.
Теперь, когда оконный класс зарегистрирован, мы можем отобразить это окно с помощью CreateWindowEx
. Аргументами являются:
- stylesex: расширенные стили окон. Значение по умолчанию - WS_EX_LEFT.
- clsname: Имя класса
- cap: заголовок окна или подпись. В этом случае это заголовок отображается в строке заголовка окна.
- стили: стили окна. Если вы хотите создать окно верхнего уровня (родительского), подобное этому, флаг, который должен пройти, - WS_OVERLAPPEDWINDOW.
- x: Координата x в верхнем левом углу окна.
- y: y-координата верхнего левого угла окна
- cx: ширина окна
- cy: Высота окна
- hwndParent: дескриптор родительского окна. Поскольку это окно само по себе является родительским окном, этот аргумент равен NULL.
- hMenuOrID: если созданное окно является родительским окном, то этот аргумент является дескриптором меню окна. Не путайте это с помощью меню класса, которое является
WNDCLASSEX::lpszClassName
. Меню класса является общим для всех экземпляров окон с тем же именем класса. Этот аргумент, однако, специфичен только для этого экземпляра. Если созданное окно является дочерним окном, то это ID дочернего окна. В этом случае мы создаем родительское окно без меню, поэтому передается NULL. - hInst: дескриптор экземпляра приложения.
- и т. д. Дополнительная информация, которая передается оконной процедуре окна. Если дополнительная информация не передается, пропустите NULL.
Если x
или y
или cx
или cy
- CW_USEDEFAULT
, значение этого аргумента будет определено Windows. Вот что делается в этом примере.
CreateWindowEx
возвращает дескриптор в только что созданное окно. Если создание окна завершилось неудачно, оно вернуло NULL
.
Затем мы показываем окно, вызывая ShowWindow
. Первым аргументом для этой функции является дескриптор окна. Второй аргумент - стиль show, который указывает, как должно отображаться окно. Большинство приложений просто передают аргумент cmdshow
переданный в WinMain
. После того, как окно будет показано, оно должно быть обновлено вызовом UpdateWindow
. Это приводит к отправке сообщения об обновлении в окно. Мы узнаем, что это значит в другом учебнике.
Теперь наступает сердцевина приложения: насос сообщений. Он передает сообщения, отправленные в это приложение операционной системой, и отправляет сообщения в процедуру окна. Вызов GetMessage
возвращает ненулевое значение, пока приложение не получит сообщения, которые заставляют его выйти, и в этом случае он возвращает 0. Единственный аргумент, который касается нас, - это указатель на структуру MSG
которая будет заполнена информацией о сообщении. Другими аргументами являются все 0.
Внутри цикла сообщений TranslateMessage
преобразует сообщения виртуальных клавиш в символьные сообщения. Смысл этого, опять же, для нас неважен. Он принимает указатель на структуру MSG
. Вызов, непосредственно следуя за ним, DispatchMessage
, отправляет сообщение, указанное его аргументом, в оконную процедуру окна. Последнее, что должен сделать WinMain
, это вернуть код состояния. Член wParam
структуры MSG
содержит это возвращаемое значение, поэтому возвращается.
Но это только для функции WinMain
. Другая функция - winproc
, оконная процедура. Он будет обрабатывать сообщения для окна, которые отправляются ему Windows. Подпись для winproc
:
- hwnd: дескриптор окна, сообщения которого обрабатываются.
- wm: идентификатор окна сообщения
- wp: Один из аргументов информации сообщения. Это зависит от аргумента
wm
- lp: Один из аргументов информации сообщения. Это зависит от аргумента
wm
. Этот аргумент обычно используется для передачи указателей или дескрипторов
В этой простой программе мы сами не обрабатываем никаких сообщений. Но это не значит, что Windows тоже. Вот почему нужно вызывать DefWindowProc
, который содержит код обработки окон по умолчанию. Эта функция должна быть вызвана в конце каждой оконной процедуры.
Что такое ручка?
Ручка - это тип данных, который представляет собой уникальный объект. Они являются указателями, но для секретных структур данных, поддерживаемых операционной системой. Детали этих структур не должны касаться нас. Все, что нужно сделать пользователю, это просто создать / восстановить дескриптор, используя вызов API, и передать его другим вызовам API, используя этот тип дескриптора. Единственным типом дескриптора, который мы использовали, былHWND
возвращаемый CreateWindowEx
. Константы
В этом примере мы сталкиваемся с несколькими константами, которые находятся во всех шапках и начинаются с префикса в 2 или 3 буквы. (Типы Windows также находятся во всех шапках)- IDI_APPLICATION: имя ресурса, содержащее значок приложения по умолчанию. Это используется с
LoadIcon
илиLoadImage
(LoadIcon в этом примере). - IDC_ARROW: имя ресурса, указывающее курсор приложения по умолчанию. Это используется с
LoadIcon
илиLoadImage
(LoadIcon в этом примере). - WHITE_BRUSH: имя объекта запаса. Этот объект представляет собой белую кисть.
- MB_ICONERROR: флаг, используемый с
MessageBox
для отображения значка ошибки. - WS_EX_LEFT: расширенный стиль окна по умолчанию. Это приводит к тому, что окно имеет свойства, выровненные по левому краю.
- WS_OVERLAPPEDWINDOW: стиль окна, указывающий, что окно должно быть родительским окном с заголовком, полем размера и другими элементами, типичными для окон верхнего уровня.
- CW_USEDEFAULT: используется с аргументами
x
,y
,cx
илиcy
CreateWindowEx
. Заставляет Windows выбирать допустимое значение для аргумента, для которого был переданCW_USEDEFAULT
.
Типы Windows
При программировании для Windows вам придется привыкнуть к типам Win32, которые являются псевдонимами для встроенных типов. Эти типы находятся во всех шапках. Типы псевдонимов, используемые в этой программе:- TCHAR: общий тип символа. Если
UNICODE
определен, этоwchar_t
. Иначе, этоchar
. - UINT: целое число без знака. Используется для представления идентификатора сообщения в процедурах окна и других целей.
- WPARAM: В Win16 это был аргумент WORD (следовательно, префикс
W
). Однако с введением Win32 это теперьUINT_PTR
. Это иллюстрирует суть этих псевдонимов Windows; они там, чтобы защитить программы от изменений. - LPARAM: Это
LONG
аргумент (LONG_PTR
в Win64). - PTSTR: указатель
P
означает указатель.T
означает общий символ, а строкаSTR
- значение. Таким образом, это указатель на строкуTCHAR
. Другие типы строк включают:- LPTSTR: То же, что
PTSTR
- LPCTSTR: средства
const TCHAR *
- PCTSTR: То же, что и
LPCTSTR
- LPWSTR: Широкая строка (
wchar_t *
) - LPCWSTR: Средство
const wchar_t *
- PWSTR: То же, что и
LPWSTR
- и многое другое. Как вы можете видеть, типы Win32 могут быть трудными для понимания, особенно с таким количеством синонимичных типов, что является артефактом Win16.
- LPTSTR: То же, что
- LRESULT: этот тип используется для представления возвращаемого значения оконных процедур. Обычно это ДОЛГО (следовательно,
L
).