==================================================================================================
[사용자 정의 메시지 핸들러 - 메시지 핸들러 분리]
- 메시지 처리 코드를 별도의 함수로 분리!
- 가독성 ↑, 성능 (다소)↓
- 메시지가 발생할 때마다 함수를 호출하면서 오버헤드 현상이 일어난다.
그렇기 때문에 case문에 처리코드를 넣는 것보다는 성능에 손해가 발생한다.
하지만 초당 20억 ~ 40억개 이상의 명령을 처리하는 요즘 CPU 속도를 감안하면
이 정도의 속도 손실은 무시할 만하다. 오히려 사람이 작업하기 편다는 측면에서 사용할 만하다.
------------------------------------------------------------------------------------------------
[메시지 크랙커]
- HANDLE_MSG 매크로를 사용해서 " case 메시지 : return 함수 (인자); " 형태로 치환하는 형태의 구현
- windowsx.h 헤더 파일을 포함해야 한다.
- 윈도우 프로시저의 WPARAM wParam, LPARAM lParam의 인자 이름을 바꿔서는 안된다.
- 장점 : 1) 운영체제가 업그레이드되면 메시지의 추가 정보가 바뀔 수 있는데
메시지 크랙커는 이런 변화에 충분히 대응할 수 있도록 작성되어 있다.
2) 소스 길이가 길면 길수록 메시지 크랙커의 가치가 더 빛난다.
3) 더이상 wParam, lParam의 의미에 대해 신경 쓸 필요가 없이 오로지 메시지 크랙커의 인자에만
신경써서 구현할 수 있다.
4) 비슷한 함수는 핸들러를 통합
- 단점 : 1) 헤더 파일에서 함수 원형을 복사해 오는 방법밖에 없다.
2) Win32 API의 0, -1을 좀 더 인간적이고 이해하기 쉬운 TRUE, FASLE로 바꾸려하다보니
이를 미리 숙지 못할 경우 엉뚱한 코드를 작성할 위험이 있다.
3) 메시지 크랙커를 사용하려면 또 다른 함수 집합을 익혀야 한다.
4) 소스 코드가 짧을 경우 오히려 더 번거로워질 수도 있다.
5) 일부 매크로에 버그 존재
- 동작과정 : (windowsx.h)
1) switch문의 " case 메시지 : " 구문을 만들어낸다.
#define HANDLE_MSG(hwnd, message, fn) \
case (message):
return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
2) "return 함수(인자)" 형태의 구문을 만든다. (ex : WM_SIZE)
#define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) \
((fn) ((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), 0L)
→ 최종 결과 : case WM_SIZE :
return Msg_Crk(hwnd, wParam, LOWORD(lParam), HIWORD(lParam))
- 메시지 크랙커 작성 순서
1) switch문 안에 처리하고자 하는 메시지에 대해 HANDLE_MSG(핸들, 메시지, 처리함수명) 매크로
구문을 삽입!
2) 함수의 본체를 만든다. (메시지 처리 함수의 원형은 windowsx.h에 있다.)
ex) "WM_SIZE"의 경우
/* void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy) */
#define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)
※ 함수를 만들 때 매크로에 대응하는 함수 fn을 만든다. (ex : WM_SIZE)
void Cls_OnSize(HWND, UINT state, int cx, int cy) // Cls_ == 메시지를 받을 윈도우_
==================================================================================================
[실행화면]
--------------------------------------------------------------------------------------------------
[ 내용 참조 및 예제 출처 - 윈도우즈 API 정복 1권 ]
==================================================================================================
[소스코드 - 사용자 정의 메시지 핸들러]
#include <windows.h>
#define ELAPSE 1000
#define TIMER_ID 1
#define BUF_SIZE 1024
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
/* 사용자 정의 메시지 핸들러 */
LRESULT OnCreate(HWND, UINT, WPARAM, LPARAM);
LRESULT OnDestroy(HWND, UINT, WPARAM, LPARAM);
LRESULT OnPaint(HWND, UINT, WPARAM, LPARAM);
LRESULT OnKeyDown(HWND, UINT, WPARAM, LPARAM);
LRESULT OnLButtonDown(HWND, UINT, WPARAM, LPARAM);
LRESULT OnTimer(HWND, UINT, WPARAM, LPARAM);
LRESULT OnSize(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
static char MainClassName[] = TEXT("WinMain");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = MainClassName;
wndclass.lpszMenuName = NULL;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndclass);
hwnd = CreateWindow (
MainClassName,
MainClassName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
(HMENU) 0,
hInstance,
NULL
);
ShowWindow(hwnd, nShowCmd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
switch(message) // 사용자 정의 메시지 핸들러를 사용함으로써 달라지는 switch문
{
case WM_CREATE : return onCreate(hwnd, message, wp, lp);
case WM_LBUTTONDOWN : return onLButtonDown(hwnd, message, wp, lp);
case WM_KEYDOWN : return onKeyDown(hwnd, message, wp, lp);
case WM_PAINT : return onPaint(hwnd, message, wp, lp);
case WM_TIMER : return onTimer(hwnd, message, wp, lp);
case WM_SIZE : return onSize(hwnd, message, wp, lp);
case WM_DESTROY : return onDestroy(hwnd, message, wp, lp);
}
return (DefWindowProc(hwnd, message, wp, lp));
}
/* 사용자 정의 메시지 핸들러 구현 */
LRESULT OnCreate(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
SetTimer(hwnd, TIMER_ID, ELAPSE, NULL);
return 0;
}
LRESULT OnDestroy(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
KillTimer(hwnd, TIMER_ID);
PostQuitMessage(0);
return 0;
}
LRESULT OnPaint(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
TCHAR *msg = TEXT("사용자 메시지 처리 핸들러 구현!");
HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 10, msg, lstrlen(msg));
EndPaint(hwnd, &ps);
return 0;
}
LRESULT OnKeyDown(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
RECT rect;
TCHAR str[BUF_SIZE];
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 80, 500, 100);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
wsprintf(str, TEXT("%c 키를 누르셨습니다!"), wp);
TextOut(hdc, 10, 80, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
return 0;
}
LRESULT OnLButtonDown(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
RECT rect;
TCHAR str[BUF_SIZE];
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 100, 500, 120);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
lstrcpy(str, "마우스 왼쪽 버튼을 누르셨습니다!");
TextOut(hdc, 10, 100, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
return 0;
}
LRESULT OnTimer(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
RECT rect;
TCHAR str[BUF_SIZE];
static int count = 0;
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 60, 500, 80);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
wsprintf(str, TEXT("%d초 경과했습니다!"), count++);
TextOut(hdc, 10, 60, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
return 0;
}
LRESULT OnSize(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
RECT rect;
TCHAR str[BUF_SIZE];
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 40, 500, 60);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
wsprintf(str, TEXT("현재 작업 영역의 크기: %d*%d!"), LOWORD(lp), HIWORD(lp));
TextOut(hdc, 10, 40, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
return 0;
}
-----------------------------------------------------------------------------------------------
[소스코드 - 메시지 크래커]
#include <windows.h>
#include <windowsx.h> // 메시지 크래커를 사용하기 위해 추가하는 헤더파일
#define ELAPSE 1000
#define TIMER_ID 1
#define BUF_SIZE 1024
/* 메시지 크랙커 - windowsx.h에 명시된 형태로 매개인자를 적어준다. */
BOOL MsgCrk_OnCreate(HWND, LPCREATESTRUCT);
void MsgCrk_OnDestroy(HWND);
void MsgCrk_OnPaint(HWND);
void MsgCrk_OnKey(HWND, UINT, BOOL, int, UINT);
void MsgCrk_OnLButtonDown(HWND, BOOL, int, int, UINT);
void MsgCrk_OnTimer(HWND, UINT);
void MsgCrk_OnSize(HWND, UINT, int, int);
/* 윈도우즈 콜백함수 */
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
static char MainClassName[] = TEXT("MsgCrk");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = MainClassName;
wndclass.lpszMenuName = NULL;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndclass);
hwnd = CreateWindow (
MainClassName,
MainClassName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
(HMENU) 0,
hInstance,
NULL
);
ShowWindow(hwnd, nShowCmd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) // 메시지 크랙커를 사용함으로써 달라지는 switch문
{
HANDLE_MSG(hwnd, WM_CREATE, MsgCrk_OnCreate);
HANDLE_MSG(hwnd, WM_LBUTTONDOWN, MsgCrk_OnLButtonDown);
HANDLE_MSG(hwnd, WM_KEYDOWN, MsgCrk_OnKey);
HANDLE_MSG(hwnd, WM_PAINT, MsgCrk_OnPaint);
HANDLE_MSG(hwnd, WM_TIMER, MsgCrk_OnTimer);
HANDLE_MSG(hwnd, WM_SIZE, MsgCrk_OnSize);
HANDLE_MSG(hwnd, WM_DESTROY, MsgCrk_OnDestroy);
}
return (DefWindowProc(hwnd, message, wParam, lParam));
}
/* 메시지 크랙커에 등록한 함수 구현 */
BOOL MsgCrk_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
SetTimer(hwnd, TIMER_ID, ELAPSE, NULL);
return TRUE;
}
void MsgCrk_OnDestroy(HWND hwnd)
{
KillTimer(hwnd, TIMER_ID);
PostQuitMessage(0);
}
void MsgCrk_OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
TCHAR *msg = TEXT("메시지 크랙커 구현!");
HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 10, msg, lstrlen(msg));
EndPaint(hwnd, &ps);
}
void MsgCrk_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)
{
// 메시지 크래커는 비슷한 함수는 핸들러를 통합하기도 한다.
// BOOL fDown : WM_KEYUP, WM_KEYDOWN 메시지 구분 용도
RECT rect;
TCHAR str[BUF_SIZE];
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 80, 500, 100);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
wsprintf(str, TEXT("%c 키를 누르셨습니다!"), vk);
TextOut(hdc, 10, 80, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
}
void MsgCrk_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
RECT rect;
TCHAR str[BUF_SIZE];
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 100, 500, 120);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
lstrcpy(str, "마우스 왼쪽 버튼을 누르셨습니다!");
TextOut(hdc, 10, 100, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
}
void MsgCrk_OnTimer(HWND hwnd, UINT id)
{
RECT rect;
TCHAR str[BUF_SIZE];
static int count = 0;
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 60, 500, 80);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
wsprintf(str, TEXT("%d초 경과했습니다!"), count++);
TextOut(hdc, 10, 60, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
}
void MsgCrk_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
RECT rect;
TCHAR str[BUF_SIZE];
HDC hdc = GetDC(hwnd);
SetRect(&rect, 10, 40, 500, 60);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
wsprintf(str, TEXT("현재 작업 영역의 크기: %d*%d!"), cx, cy);
TextOut(hdc, 10, 40, str, lstrlen(str));
ReleaseDC(hwnd, hdc);
}
==================================================================================================
'IT_Programming > MFC · API' 카테고리의 다른 글
[API] 슈퍼 클래싱 (Super Classing) (0) | 2009.07.29 |
---|---|
[API] 서브 클래싱( SUB CLASSING ) (0) | 2009.07.29 |
[API] 윈도우 프로퍼티 (Window Property) (0) | 2009.07.24 |
[API] 여분의 메모리를 사용하는 이유와 방법 (0) | 2009.07.24 |
[API] 윈도우 창에 글 출력하기 (0) | 2009.07.22 |