Windows 사용

이 섹션의 예제는 다음 작업을 수행하는 방법을 설명합니다.

기본 창 만들기

애플리케이션이 만드는 첫 번째 창은 일반적으로 기본 창입니다. CreateWindowEx 함수를 사용하여 창 클래스, 창 이름, 창 스타일, 크기, 위치, 메뉴 핸들, 인스턴스 핸들 및 만들기 데이터를 지정하여 기본 창을 만듭니다. 기본 창은 애플리케이션 정의 창 클래스에 속하므로 기본 창을 만들기 전에 창 클래스를 등록하고 클래스에 대한 창 절차를 제공해야 합니다.

대부분의 애플리케이션은 일반적으로 WS_OVERLAPPEDWINDOW 스타일을 사용하여 기본 창을 만듭니다. 이 스타일은 창에 제목 표시줄, 창 메뉴, 크기 조정 테두리, 최소화 및 최대화 단추를 제공합니다. CreateWindowEx 함수는 창을 고유하게 식별하는 핸들을 반환합니다.

다음 예제에서는 애플리케이션 정의 창 클래스에 속하는 기본 창을 만듭니다. 창 이름인 기본 창이 창의 제목 표시줄에 표시됩니다. 애플리케이션은 WS_VSCROLLWS_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 스타일을 지정하고 자식 창을 만들 때 자식 창에 대한 부모 창을 지정해야 합니다.

다음 예제에서는 크기가 동일한 자식 창 3개를 만들어 애플리케이션의 기본 창의 클라이언트 영역을 세 개의 기능 영역으로 나눕니다. 각 자식 창은 기본 창의 클라이언트 영역과 높이는 같지만 너비는 그 3분의 1입니다. 기본 창은 자체 창 만들기 프로세스 중에 기본 창이 수신하는 WM_CREATE 메시지에 대한 응답으로 자식 창을 만듭니다. 각 자식 창에는 WS_BORDER 스타일이 있으므로 각 자식 창에는 얇은 선 테두리가 있습니다. 또한 WS_VISIBLE 스타일이 지정되지 않았기 때문에 각 자식 창이 처음에 숨겨집니다. 또한 각 자식 창에는 자식 창 식별자도 할당됩니다.

기본 창은 크기가 변경될 때 기본 창이 수신하는 WM_SIZE 메시지에 대한 응답으로 자식 창의 크기를 조정하고 배치합니다. WM_SIZE에 대한 응답으로 기본 창은 GetClientRect 함수를 사용하여 그 클라이언트 영역의 치수를 검색한 다음 EnumChildWindows 함수에 치수를 전달합니다. EnumChildWindows는 각 자식 창에 핸들을 전달하여 애플리케이션 정의 EnumChildProc 콜백 함수에 전달합니다 이 함수는 MoveWindow 함수를 호출하여 각 자식 창의 크기를 조정하고 배치합니다. 크기와 위치는 기본 창의 클라이언트 영역 크기와 자식 창의 식별자를 기반으로 합니다. 이후에 EnumChildProc calls the 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에 대한 응답으로 창은 데이터를 저장하고 할당된 모든 리소스를 해제합니다. 기본 창은 PostQuitMessage 함수를 호출하여 애플리케이션을 종료한 후 WM_DESTROY 처리를 완료합니다.

다음 예제는 창을 제거하기 전에 사용자 확인을 요청하는 방법을 보여줍니다. WM_CLOSE에 대한 응답으로 , 아니요취소 단추가 있는 대화 상자가 표시됩니다. 사용자가 를 클릭하면, DestroyWindow가 호출되고, 그렇게 하지 않으면 창이 제거되지 않습니다. 애플리케이션이 WM_CLOSE 메시지를 처리하므로, 모든 경우에서 0가 반환됩니다. 제거되는 창은 기본 창이므로 이 예제에서는 WM_DESTROY에 대한 응답으로 PostQuitMessage를 호출합니다.

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;

계층적 창 사용

대화 상자가 반투명 창으로 표시되게 하려면 먼저 평소처럼 대화 상자를 만듭니다. 그런 다음 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까지의 값이며, 0은 창을 완전히 투명하게 만들고 255는 완전히 불투명하게 만듭니다. 이 매개 변수는 AlphaBlend 함수에서 활용성이 더 큰 BLENDFUNCTION을 모방합니다.

이 창을 다시 불투명하게 만들려면 SetWindowLong를 호출하여 WS_EX_LAYERED 비트를 제거한 다음 다시 칠할 것을 창에 요청합니다. 계층화 및 리디렉션과 관련된 일부 메모리를 해제할 수 있음을 시스템이 알 수 있도록 비트를 제거하는 것이 좋습니다. 코드 모양은 다음과 같습니다.

// 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은 Windows 10을 인식하도록 이 호환성 코드 조각을 그 app.manifest에 포함할 수 있습니다.

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

앱 매니페스트 수정에 대한 자세한 내용은 애플리케이션 매니페스트를 참조하세요.