어떤 프로세스에 윈도우 프로시져를 여러개 만들어야 할 때가 있다. (예를 들어, DLL로 기존 프로세스에 빌붙을 경우라든가)
그리고 그 특정 윈도우에 외부에서 어떤 명령을 보낼 경우에 해당 윈도우 프로시져를 사용할 경우가 있다.
하지만 일반적으로 윈도우 프로시져는 static 이어야 하기 때문에 어떤 클래스의 멤버함수로 두면 에러가 뻑 난다.
안되는 이유는 클래스의 멤버함수들은 보이지 않게 매개변수를 하나 더 추가적으로 전달받게 되는데,
바로 그 매개변수가 this 포인터이다.
하지만 윈도우 프로시져 원형이
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
이렇게 되기 때문에 this 포인터가 눈에 안보이게 선언됨으로써 더이상 그건 윈도우 프로시져가 아니게 되므로 에러가 발생한다. (컴파일이 안됨)
윈도우 프로시져를 클래스의 멤버함수로 만들려면, 함수 선언 앞부분에 static 을 붙여주기만 하면 일단 컴파일은 된다.
하지만 이렇게 될 경우 this 포인터를 전달받을 수 없게 되므로, 클래스의 다른 멤버들에 접근할 수가 없다.
그렇게 되면 클래스의 멤버함수로 선언한 의미가 없다.
이 모든 것을 해결하는 방법은 CreateWindow, CreateWindowEx 함수 호출시 가장 마지막 매개변수로 this 를 전달하는 것이다.
CreateWindow 함수의 원형은 다음과 같고,
HWND CreateWindowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );
가장 마지막 매개변수에 대한 설명은 다음과 같다.
- lpParam
-
[in] Long pointer to a value to be passed to the window through the CREATESTRUCT structure passed in the lParam parameter the WM_CREATE message.
그럼 실제로 적용하는 예제코드를 보자면,
// 클래스 선언
class aClass
{
public:
HWND CreateWnd(HINSTANCE hInstance);
// static 을 붙여 선언함
static LRESULT CALLBACK aWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam); private:
char m_szMsg[256]; // 여기에 있는 메세지를 화면에 뿌릴 계획
}
HWND aClass::CreateWnd(HINSTANCE hInstance)
{
WNDCLASSEX wndclass;
wndclass.lpfnWndProc = aWndProc; // 윈도우 프로시져 연결
...
...
return CreateWindowEx(/* 앞 부분 인자는 생략 */, this); // this 를 매개변수로 전달
}
{
WNDCLASSEX wndclass;
wndclass.lpfnWndProc = aWndProc; // 윈도우 프로시져 연결
...
...
return CreateWindowEx(/* 앞 부분 인자는 생략 */, this); // this 를 매개변수로 전달
}
LRESULT CALLBACK aClass:aWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
static aClass *paClass; // this 를 대신할 포인터
switch(nMsg)
{
case WM_CREATE:
// 생성될 때 넘겨받은 this 포인터를 보관하여 추후 클래스 멤버참조시 사용한다
paClass = (aClass*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
return 0;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
// 멤버에 접근할 때 보관한 포인터를 통해 접근한다. paClass->
// 그냥 m_szMsg 로 접근하면 컴파일 에러가 난다.
DrawText(hDC, paClass->m_szMsg, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
return 0;
}
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}
{
static aClass *paClass; // this 를 대신할 포인터
switch(nMsg)
{
case WM_CREATE:
// 생성될 때 넘겨받은 this 포인터를 보관하여 추후 클래스 멤버참조시 사용한다
paClass = (aClass*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
return 0;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
// 멤버에 접근할 때 보관한 포인터를 통해 접근한다. paClass->
// 그냥 m_szMsg 로 접근하면 컴파일 에러가 난다.
DrawText(hDC, paClass->m_szMsg, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
return 0;
}
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}
'WindowsAPI' 카테고리의 다른 글
응용 프로그램을 위한 최상의 사용자 환경을 만드는 방법 (윈도우즈 사용자 인터페이스 기술 문서) (0) | 2009.04.12 |
---|---|
DLLMain 에서 해서는 안되는 것들, 해도 되는 것들. (0) | 2009.04.12 |
레지스트리 - MUICache 라는 키에 대해 (0) | 2009.04.12 |
프로그램 추가/제거 레지스트리 경로로 만들기 (0) | 2009.04.12 |
RunDll32.exe 를 이용한 방법들. (0) | 2009.04.12 |