Поиск…


Создание окна

#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.
  • LRESULT: этот тип используется для представления возвращаемого значения оконных процедур. Обычно это ДОЛГО (следовательно, L ).


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow