창 프로시저 사용
이 섹션에서는 창 프로시저와 관련된 다음 작업을 수행하는 방법을 설명합니다.
창 프로시저 디자인
다음 예제에서는 일반적인 창 프로시저의 구조를 보여줍니다. 창 프로시저는 switch 문의 메시지 인수를 개별 사례 문으로 처리하는 개별 메시지와 함께 사용합니다. 각 사례는 각 메시지에 대한 특정 값을 반환합니다. 처리하지 않는 메시지의 경우 창 프로시저는 DefWindowProc 함수를 호출합니다.
LRESULT CALLBACK MainWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{
switch (uMsg)
{
case WM_CREATE:
// Initialize the window.
return 0;
case WM_PAINT:
// Paint the window's client area.
return 0;
case WM_SIZE:
// Set the size and position of the window.
return 0;
case WM_DESTROY:
// Clean up window-specific data objects.
return 0;
//
// Process other messages.
//
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
WM_NCCREATE 메시지는 창을 만든 직후에 전송되지만 애플리케이션이 FALSE를 반환하여 이 메시지에 응답하면 CreateWindowEx 함수가 실패합니다. 창이 이미 만들어진 후 WM_CREATE 메시지가 전송됩니다.
창이 제거될 때 WM_DESTROY 메시지가 전송됩니다. DestroyWindow 함수는 제거되는 창의 자식 창을 삭제합니다. WM_NCDESTROY 메시지는 창이 제거되기 직전에 전송됩니다.
최소한 창 프로시저는 WM_PAINT 메시지를 처리하여 직접 그려야 합니다. 일반적으로 마우스 및 키보드 메시지도 처리해야 합니다. 개별 메시지에 대한 설명을 참조하여 창 프로시저에서 처리해야 하는지 여부를 확인합니다.
애플리케이션은 메시지 처리의 일부로 DefWindowProc 함수를 호출할 수 있습니다. 이러한 경우 애플리케이션은 메시지를 DefWindowProc에 전달하기 전에 메시지 매개 변수를 수정하거나 자체 작업을 수행한 후 기본 처리를 계속할 수 있습니다.
대화 상자 프로시저는 WM_CREATE 메시지 대신 WM_INITDIALOG 메시지를 수신하고 처리되지 않은 메시지를 DefDlgProc 함수에 전달하지 않습니다. 그렇지 않으면 대화 상자 프로시저는 창 프로시저와 정확히 동일합니다.
창 프로시저를 Window 클래스와 연결
클래스를 등록할 때 창 프로시저를 창 클래스와 연결합니다. WNDCLASS 구조체를 클래스에 대한 정보로 채워야 하며 lpfnWndProc 멤버는 창 프로시저의 주소를 지정해야 합니다. 클래스를 등록하려면 WNDCLASS 구조체의 주소를 RegisterClass 함수에 전달합니다. 창 클래스가 등록되면 창 프로시저가 해당 클래스로 만든 각 새 창과 자동으로 연결됩니다.
다음 예제에서는 이전 예제의 창 프로시저를 창 클래스와 연결하는 방법을 보여줍니다.
int APIENTRY WinMain(
HINSTANCE hinstance, // handle to current instance
HINSTANCE hinstPrev, // handle to previous instance
LPSTR lpCmdLine, // address of command-line string
int nCmdShow) // show-window type
{
WNDCLASS wc;
// Register the main window class.
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MainWindowClass";
if (!RegisterClass(&wc))
return FALSE;
//
// Process other messages.
//
}
창 서브클래싱
창의 instance 서브클래스하려면 SetWindowLong 함수를 호출하고 창에 대한 핸들을 지정하여 GWL_WNDPROC 플래그와 서브클래스 프로시저에 대한 포인터를 서브클래스합니다. SetWindowLong 은 원래 창 프로시저에 대한 포인터를 반환합니다. 이 포인터를 사용하여 원래 프로시저에 메시지를 전달합니다. 하위 클래스 창 프로시저는 CallWindowProc 함수를 사용하여 원래 창 프로시저를 호출해야 합니다.
참고
32비트 및 64비트 버전의 Windows와 호환되는 코드를 작성하려면 SetWindowLongPtr 함수를 사용합니다.
다음 예제에서는 대화 상자에서 편집 컨트롤의 instance 서브클래스하는 방법을 보여줍니다. 서브클래스 창 프로시저를 사용하면 컨트롤에 입력 포커스가 있을 때마다 편집 컨트롤이 ENTER 키와 TAB 키를 비롯한 모든 키보드 입력을 받을 수 있습니다.
WNDPROC wpOrigEditProc;
LRESULT APIENTRY EditBoxProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndEdit;
switch(uMsg)
{
case WM_INITDIALOG:
// Retrieve the handle to the edit control.
hwndEdit = GetDlgItem(hwndDlg, ID_EDIT);
// Subclass the edit control.
wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit,
GWL_WNDPROC, (LONG) EditSubclassProc);
//
// Continue the initialization procedure.
//
return TRUE;
case WM_DESTROY:
// Remove the subclass from the edit control.
SetWindowLong(hwndEdit, GWL_WNDPROC,
(LONG) wpOrigEditProc);
//
// Continue the cleanup procedure.
//
break;
}
return FALSE;
UNREFERENCED_PARAMETER(lParam);
}
// Subclass procedure
LRESULT APIENTRY EditSubclassProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
if (uMsg == WM_GETDLGCODE)
return DLGC_WANTALLKEYS;
return CallWindowProc(wpOrigEditProc, hwnd, uMsg,
wParam, lParam);
}