Использование Windows

В примерах в этом разделе описывается выполнение следующих задач:

Создание главного окна

Первое окно, которое создает приложение, обычно является основным окном. Главное окно создается с помощью функции CreateWindowEx , указывая класс окна, имя окна, стили окна, размер, положение, дескриптор меню, дескриптор экземпляра и данные создания. Главное окно принадлежит классу окна, определяемому приложением, поэтому необходимо зарегистрировать класс окна и предоставить процедуру окна для класса перед созданием главного окна.

Большинство приложений обычно используют стиль WS_OVERLAPPEDWINDOW для создания главного окна. Этот стиль предоставляет окно заголовку, меню окна, границу размера и свернуть и развернуть кнопки. Функция CreateWindowEx возвращает дескриптор, который однозначно идентифицирует окно.

В следующем примере создается главное окно, принадлежащее классу окна, определяемому приложением. Имя окна, главное окно, появится в строке заголовка окна. Сочетая стили WS_VSCROLL и WS_HSCROLL со стилем WS_OVERLAPPEDWINDOW, приложение создает главное окно с горизонтальными и вертикальными полосами прокрутки в дополнение к компонентам, предоставляемым стилем WS_OVERLAPPEDWINDOW. Четыре вхождения константы CW_USEDEFAULT задают начальный размер и позицию окна для системных значений по умолчанию. Указав NULL вместо дескриптора меню, окно будет иметь меню, определенное для класса окна.

HINSTANCE hinst; 
HWND hwndMain; 
 
// Create the main window. 
 
hwndMain = CreateWindowEx( 
    0,                      // no extended styles           
    "MainWClass",           // class name                   
    "Main Window",          // window name                  
    WS_OVERLAPPEDWINDOW |   // overlapped window            
             WS_HSCROLL |   // horizontal scroll bar        
             WS_VSCROLL,    // vertical scroll bar          
    CW_USEDEFAULT,          // default horizontal position  
    CW_USEDEFAULT,          // default vertical position    
    CW_USEDEFAULT,          // default width                
    CW_USEDEFAULT,          // default height               
    (HWND) NULL,            // no parent or owner window    
    (HMENU) NULL,           // class menu used              
    hinst,                  // instance handle              
    NULL);                  // no window creation data      
 
if (!hwndMain) 
    return FALSE; 
 
// Show the window using the flag specified by the program 
// that started the application, and send the application 
// a WM_PAINT message. 
 
ShowWindow(hwndMain, SW_SHOWDEFAULT); 
UpdateWindow(hwndMain); 

Обратите внимание, что предыдущий пример вызывает функцию ShowWindow после создания главного окна. Это делается, так как система не отображает главное окно после его создания автоматически. Передав флаг SW_SHOWDEFAULT в ShowWindow, приложение позволяет программе, запускающей приложение, задать начальное состояние главного окна. Функция UpdateWindow отправляет окно его первого WM_PAINT сообщения.

Создание, перечисление и изменение размера дочерних окон

Клиентскую область окна можно разделить на разные функциональные области с помощью дочерних окон. Создание дочернего окна похоже на создание главного окна— используйте функцию CreateWindowEx . Чтобы создать окно определенного приложением класса окна, необходимо зарегистрировать класс окна и предоставить процедуру окна перед созданием дочернего окна. При создании окна необходимо предоставить дочернему окну стиль WS_CHILD и указать родительское окно для дочернего окна.

В следующем примере клиентская область основного окна приложения делится на три функциональные области, создавая три дочерних окна равных размеров. Каждое дочернее окно совпадает с высотой клиентской области главного окна, но каждая из них составляет одну треть ее ширины. Главное окно создает дочерние окна в ответ на сообщение WM_CREATE , которое главное окно получает во время собственного процесса создания окна. Так как каждое дочернее окно имеет стиль WS_BORDER , каждая из них имеет тонкую границу линии. Кроме того, поскольку стиль WS_VISIBLE не указан, каждое дочернее окно изначально скрыто. Обратите внимание, что каждое дочернее окно назначается идентификатором дочернего окна.

Размеры основного окна и положение дочерних окон в ответ на сообщение WM_SIZE , которое получает главное окно при изменении его размера. В ответ на WM_SIZE основное окно извлекает измерения своей клиентской области с помощью функции GetClientRect, а затем передает измерения функции EnumChildWindows. EnumChildWindows передает дескриптор каждому дочернему окну, в свою очередь, в функцию обратного вызова EnumChildProc . Размеры и позиции каждого дочернего окна, вызывая функцию MoveWindow ; размер и положение основаны на измерениях клиентской области главного окна и идентификатора дочернего окна. После этого EnumChildProc вызывает функцию ShowWindow, чтобы сделать окно видимым.

#define ID_FIRSTCHILD  100 
#define ID_SECONDCHILD 101 
#define ID_THIRDCHILD  102 
 
LONG APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    RECT rcClient; 
    int i; 
 
    switch(uMsg) 
    { 
        case WM_CREATE: // creating main window  
 
            // Create three invisible child windows. 

            for (i = 0; i < 3; i++) 
            { 
                CreateWindowEx(0, 
                               "ChildWClass", 
                               (LPCTSTR) NULL, 
                               WS_CHILD | WS_BORDER, 
                               0,0,0,0, 
                               hwnd, 
                               (HMENU) (int) (ID_FIRSTCHILD + i), 
                               hinst, 
                               NULL); 
            }
 
            return 0; 
 
        case WM_SIZE:   // main window changed size 
 
            // Get the dimensions of the main window's client 
            // area, and enumerate the child windows. Pass the 
            // dimensions to the child windows during enumeration. 
 
            GetClientRect(hwnd, &rcClient); 
            EnumChildWindows(hwnd, EnumChildProc, (LPARAM) &rcClient); 
            return 0; 

        // Process other messages. 
    } 
    return DefWindowProc(hwnd, uMsg, wParam, lParam); 
} 
 
BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam) 
{ 
    LPRECT rcParent; 
    int i, idChild; 
 
    // Retrieve the child-window identifier. Use it to set the 
    // position of the child window. 
 
    idChild = GetWindowLong(hwndChild, GWL_ID); 
 
    if (idChild == ID_FIRSTCHILD) 
        i = 0; 
    else if (idChild == ID_SECONDCHILD) 
        i = 1; 
    else 
        i = 2; 
 
    // Size and position the child window.  
 
    rcParent = (LPRECT) lParam; 
    MoveWindow(hwndChild, 
               (rcParent->right / 3) * i, 
               0, 
               rcParent->right / 3, 
               rcParent->bottom, 
               TRUE); 
 
    // Make sure the child window is visible. 
 
    ShowWindow(hwndChild, SW_SHOW); 
 
    return TRUE;
}

Уничтожение окна

Функцию DestroyWindow можно использовать для уничтожения окна. Как правило, приложение отправляет сообщение WM_CLOSE перед уничтожением окна, предоставляя окне возможность запрашивать подтверждение пользователя до того, как окно будет уничтожено. Окно, включающее меню окна, автоматически получает сообщение WM_CLOSE, когда пользователь нажимает кнопку "Закрыть" в меню окна. Если пользователь подтверждает, что окно должно быть уничтожено, приложение вызывает DestroyWindow. Система отправляет сообщение WM_DESTROY в окно после его удаления с экрана. В ответ на WM_DESTROY окно сохраняет свои данные и освобождает все выделенные ресурсы. Главное окно завершает обработку WM_DESTROY путем вызова функции PostQuitMessage, чтобы выйти из приложения.

В следующем примере показано, как запрашивать подтверждение пользователя перед уничтожением окна. В ответ на WM_CLOSE отображается диалоговое окно с кнопками "Да", "Нет" и "Отмена ". Если пользователь нажимает кнопку "Да", вызывается DestroyWindow ; в противном случае окно не уничтожается. Так как приложение обрабатывает сообщение WM_CLOSE , 0 возвращается во всех случаях. Так как разрушенное окно является главным окном, в примере вызывается PostQuitMessage в ответ на WM_DESTROY.

case WM_CLOSE: 
 
    // Create the message box. If the user clicks 
    // the Yes button, destroy the main window. 
 
    if (MessageBox(hwnd, szConfirm, szAppName, MB_YESNOCANCEL) == IDYES) 
        DestroyWindow(hwndMain); 
    return 0; 
 
case WM_DESTROY: 
 
    // Post the WM_QUIT message to 
    // quit the application terminate. 
 
    PostQuitMessage(0); 
    return 0;

Использование многоуровневой оси Windows

Чтобы диалоговое окно появилось как полупрозрачное окно, сначала создайте диалоговое окно как обычно. Затем на WM_INITDIALOG задайте многоуровневый бит расширенного стиля окна и вызовите SetLayeredWindowAttributes с нужным альфа-значением. Код может выглядеть следующим образом:

// Set WS_EX_LAYERED on this window 
SetWindowLong(hwnd, 
              GWL_EXSTYLE, 
              GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);

// Make this window 70% alpha
SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);

Обратите внимание, что третий параметр SetLayeredWindowAttributes — это значение, которое варьируется от 0 до 255, при этом окно полностью прозрачно и 255 делает его полностью непрозрачным. Этот параметр имитирует более универсальный BLENDFUNCTION функции AlphaBlend.

Чтобы сделать это окно полностью непрозрачным, удалите WS_EX_LAYERED бит, вызвав SetWindowLong, а затем попросите окно перенакрасить. Удаление бита требуется, чтобы система знала, что она может освободить некоторую память, связанную с слоем и перенаправлением. Код может выглядеть следующим образом:

// Remove WS_EX_LAYERED from this window styles
SetWindowLong(hwnd, 
              GWL_EXSTYLE,
              GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);

// Ask the window and its children to repaint
RedrawWindow(hwnd, 
             NULL, 
             NULL, 
             RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);

Чтобы использовать многоуровневые дочерние окна, приложение должен объявить себя в манифесте с поддержкой Windows 8.

Для Windows 10/11 этот фрагмент совместимости можно включить в него app.manifest , чтобы сделать его Windows 10 с поддержкой:

...
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- Windows 10 GUID -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
    </application>
</compatibility>
...

Дополнительные сведения об изменении манифеста приложения см. здесь: манифесты приложений