MFC

클래스 멤버 함수를 윈도우 프로시져로 등록하기 [3/3]

디버그정 2008. 9. 1. 20:20

우선 클래스 멤버 함수를 윈도우 프로시져로 등록하는건 간단합니다.
아래처럼 클래스 선언에서 함수명 앞에 static를 붙여주기면 하면 됩니다.

class A
{
public:
    HWND CreateEventWnd(HINSTANCE hInstance);
    static LRESULT CALLBACK EventWndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
         LPARAM lParam);
}

멤버 함수들은 보이지 않게 인자 하나를 추가로 더 전달받게 되는데요.
아시겠지만 this 포인터 입니다.
이 this 포인터가 인자로 하나 더 붙기 때문에 윈도우 프로시져가 될 수 없습니다.
그래서 this 포인터를 전달하기 않게 하기 위해 static 멤버로 만듭니다.  
이렇게 하면 컴파일 에러 없이 잘 동작 합니다.

하지만 문제는 this 포인터를 전달받지 못하기 때문에
클래스의 다른 멤버들을 접근 할 수 없게 됩니다.
어떤 다른 방법을 통하여 this 포인터를 전해 줘야 합니다.
아래는 m_szMessage 멤버 변수에 들어있는 메시지를
윈도우 중앙에 뿌려주는 간단한 예제 입니다.

class A
{
public:
    HWND CreateEventWnd(HINSTANCE hInstance);
    static LRESULT CALLBACK EventWndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
        LPARAM lParam);
private:
    char m_szMessage[256]; // 여기에 들어가는 메시지를 화면에 뿌려준다.
};

HWND A::CreateEventWnd(HINSTANCE hInstance)
{
    // 메시지를 준비한다.
    // 이 메시지가 윈도우 중앙에 뿌려진다.
    strcpy(m_szMessage, "Hello, world!");

    WNDCLASSEX wndclass;
    wndclass.lpfnWndProc = EventWndProc;
    ......

    // 윈도우를 생성할 때 this 포인터를 넘겨준다.
    return CreateWindowEx(/*앞 부분 인자 생략*/, this);
}

LRESULT CALLBACK A::EventWndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
    LPARAM lParam)
{
    A *pA; // this를 대신할 포인터 변수

    switch(nMsg)
    {
    case WM_CREATE:
        // 생성될 때 넘겨받은 this 포인터를 보관한다.
        pA = *(A **) lParam;
        SetWindowLong(hWnd, GWL_USERDATA, (LONG) pA);
        return 0;  
    case WM_PAINT:
        hDC = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &rect);

        // this 포인터를 얻어온다.
        pA = (A *) GetWindowLong(hWnd, GWL_USERDATA);

        // 멤버에 접근 할 때는 pA-> 를 사용해서 접근한다.
        // 그냥 m_szMessage만 달랑 쓰면 컴파일 에러가 날것이다.
        DrawText(hDC, pA->m_szMessage, -1, &rect,
            DT_SINGLELINE | DT_CENTER | DT_VCENTER);

        EndPaint(hWnd, &ps);
        return 0;
    }  
    return DefWindowProc(hWnd, nMsg, wParam, lParam);
}


위에것은 구식의 방법이다..


요즘의 밑에 방법으로  -0-/

------------------------------------------------------------------------------

class A
{
public:
    HWND CreateEventWnd(HINSTANCE hInstance);
    static LRESULT CALLBACK EventWndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
        LPARAM lParam);
private:
    char m_szMessage[256]; // 여기에 들어가는 메시지를 화면에 뿌려준다.
};

HWND A::CreateEventWnd(HINSTANCE hInstance)
{
    // 메시지를 준비한다.
    // 이 메시지가 윈도우 중앙에 뿌려진다.
    strcpy(m_szMessage, "Hello, world!");

    WNDCLASSEX wndclass;
    wndclass.lpfnWndProc = EventWndProc;
    ......

    // 윈도우를 생성할 때 this 포인터를 넘겨준다.
    return CreateWindowEx(/*앞 부분 인자 생략*/, this);
}

LRESULT CALLBACK A::EventWndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
    LPARAM lParam)
{
    static A *pA; // this를 대신할 포인터 변수

    switch(nMsg)
    {
    case WM_CREATE:
        // 생성될 때 넘겨받은 this 포인터를 보관한다.
        pA = (A *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
        return 0;  

    case WM_PAINT:
        hDC = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &rect);

        // 멤버에 접근 할 때는 pA-> 를 사용해서 접근한다.
        // 그냥 m_szMessage만 달랑 쓰면 컴파일 에러가 날것이다.
        DrawText(hDC, pA->m_szMessage, -1, &rect,
            DT_SINGLELINE | DT_CENTER | DT_VCENTER);

        EndPaint(hWnd, &ps);
        return 0;
    }  
    return DefWindowProc(hWnd, nMsg, wParam, lParam);
}