창 프로시저 사용

이 섹션에서는 창 프로시저와 관련된 다음 작업을 수행하는 방법을 설명합니다.

창 프로시저 디자인

다음 예제에서는 일반적인 창 프로시저의 구조를 보여줍니다. 창 프로시저는 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); 
}