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 스타일을 지정하고 자식 창을 만들 때 자식 창에 대한 부모 창을 지정해야 합니다.
다음 예제에서는 크기가 동일한 자식 창 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>
...
앱 매니페스트 수정에 대한 자세한 내용은 애플리케이션 매니페스트를 참조하세요.