=================================================================================================
[인스턴스 서브 클래싱]
- 윈도우가 만들어진 후 그 윈도우 하나에 대해서만 윈도우 프로시저를 교체하는 것이다.
따라서 이후에 만들어지는 윈도우는 이 서브클래싱의 영향을 전혀 받지 않는다.
특정 윈도우 하나에 대해서만 윈도우 프로시저를 교체하는 것이므로 SetWindowLongPtr 함수가
사용된다.
[전역(클래스) 서브 클래싱]
- 윈도우 클래스에 대해 서브클래싱을 하는 것이다.
- 윈도우 클래스의 WNDCLASS 구조체를 직접 변경하며, 이때는 SetClassLongPtr 함수가 사용된다.
- 이미 만들어진 윈도우에 대해서는 전혀 효과가 없으며 앞으로 만들어질 윈도우만 영향을 받는다.
-------------------------------------------------------------------------------------------------
즉, 윈도우 클래스에 윈도우 프로시저가 등록되어 있고, 이 윈도우 클래스로부터 윈도우를 만들 때마다
윈도우 프로시저의 번지가 각 윈도우로 복사되는데, 원본(전역)과 사본(인스턴스) 중 어디를 변경하는가에
따라 서브 클래싱의 범위가 달라진다.
주의! 서브 클래싱은 같은 프로세스 내에서만 효력을 발휘한다!
- 전역의 경우에도 윈도우 클래스는 본질적으로 각 프로세스에 대해 지역적이기 때문이다.
( 서로 다른 프로세스 영역에서 시작되는 프로그램에 영향을 주지 않는다. )
시스템 전역 클래스에 대한 정보는 시스템이 가지고 있지만 각 프로세스가 참조하는 클래스 정보는
응용 프로그램이 시작될 때 전달 받는 복사본일 뿐이다.
-------------------------------------------------------------------------------------------------
[ 내용참조 및 예제참조 출처 - 윈도우즈 API 정복 1권]
=================================================================================================
[실행화면 - 인스턴스 서브클래싱]
- 초기 화면
- (인스턴스 서브클래싱이 적용된) 첫번째 에디트 윈도우를 클릭 했을 경우 전체 블록을 잡는다.
- 탭키로 인스턴스 서브클래싱이 적용되지 않은 두번째 에디트 윈도우로 포커스를 옮긴다.
-----------------------------------------------------------------------------------------------
[실행화면 - 전역(클래스) 서브클래싱]
- 초기화면
- 전역(클래스) 서브클래싱이 적용되지 않은 에디트 윈도우는 엔터를 눌러도 반응이 없다.
- 전역(클래스) 서브클래싱이 적용된 두번째 에디트 윈도우는 엔터를 입력할 경우
부모 윈도우의 캡션에 그 내용을 출력한다.
=================================================================================================
[소스코드 - 인스턴스 서브 클래싱]
#include <Windows.h>
// #include <> - 시스템 폴더 경로
// #include "" - 상대 경로 (현재 응용 프로그램의 경로)
#define ID_EDIT1 100
#define ID_EDIT2 200
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK SubEditProc(HWND, UINT, WPARAM, LPARAM);
HWND hEdit1, hEdit2;
WNDPROC OldEditProc;
HINSTANCE g_hInst;
int APIENTRY WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
static char MainClassName[] = TEXT("WinMain");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
g_hInst = hInstance;
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)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR *Mes = TEXT("에디트의 Enter키 입력을 검출합니다!");
switch(message)
{
case WM_CREATE : MoveWindow(hwnd, 350, 250, 500, 300, TRUE);
hEdit1 = CreateWindow (
TEXT("edit"),
TEXT("서브클래싱"),
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
10,
10,
200,
25,
hwnd,
(HMENU)ID_EDIT1,
g_hInst,
NULL
);
hEdit2 = CreateWindow (
TEXT("edit"),
TEXT("원래클래스"),
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
10,
50,
200,
25,
hwnd,
(HMENU)ID_EDIT2,
g_hInst,
NULL
);
SetFocus(hEdit1);
// ↓ 이전의 윈도우 프로시저의 번지를 기억! (3번째 인자 - 서브클래스 프로시저)
OldEditProc = (WNDPROC)SetWindowLongPtr(hEdit1, GWLP_WNDPROC,
(LONG_PTR)SubEditProc);
return 0;
case WM_PAINT : hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 100, Mes, lstrlen(Mes));
EndPaint(hwnd, &ps);
return 0;
// ↓ 이전의 윈도우 프로시저의 번지로 돌린다!
case WM_DESTROY : SetWindowLongPtr(hEdit1, GWLP_WNDPROC,
(LONG_PTR)OldEditProc);
PostQuitMessage(0);
return 0;
}
return (DefWindowProc(hwnd, message, wp, lp));
}
// 서브클래스 윈도우 프로시저 - hEdit1만 서브 클래싱이 적용되어 있다!
LRESULT CALLBACK SubEditProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
static BOOL INIT_ERASE_FLAG = TRUE;
switch(message)
{
case WM_KEYDOWN : if(INIT_ERASE_FLAG == TRUE)
{
SetWindowText(hEdit1, "");
SetWindowText(hEdit2, "");
}
INIT_ERASE_FLAG = FALSE;
if(wp == VK_RETURN)
{
MessageBox(hwnd, TEXT("Enter is pressed!"), TEXT("Edit"),
MB_OK);
SetFocus(hwnd);
}
if(wp == VK_TAB)
SetFocus(hEdit2);
if(wp == VK_LEFT)
wp = VK_RIGHT;
else if(wp == VK_RIGHT)
wp = VK_LEFT;
break;
case WM_LBUTTONDOWN : SetFocus(hEdit1);
SendMessage(hwnd, EM_SETSEL, 0, -1);
return 0;
}
// CallWindowProc 함수 : 관심을 가지는 메시지 이외에는 원래의 에디트 윈도우 방식으로 처리!
return (CallWindowProc(OldEditProc, hwnd, message, wp, lp));
}
-----------------------------------------------------------------------------------------------
[소스코드 - 전역(클래스) 서브 클래싱]
#include <Windows.h>
#define BUF_SIZE 256
#define ID_EDIT1 100
#define ID_EDIT2 200
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK SubEditProc(HWND, UINT, WPARAM, LPARAM);
HWND hEdit1, hEdit2;
WNDPROC OldEditProc;
HINSTANCE g_hInst;
int APIENTRY WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd )
{
static char MainClassName[] = TEXT("WinMain");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
g_hInst = hInstance;
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)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR *Mes = TEXT("에디트의 Enter키 입력을 검출합니다!");
switch(message)
{
case WM_CREATE : MoveWindow(hwnd, 350, 250, 500, 300, TRUE);
hEdit1 = CreateWindow (
TEXT("edit"),
NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
10,
10,
200,
25,
hwnd,
(HMENU)ID_EDIT1,
g_hInst,
NULL
);
// ↓ 위치 주의! - hEdit1이 속한 edit 윈도우 클래스가 서브클래싱의 대상이 된다.
// 즉, edit 윈도우의 클래스를 서브클래싱 적용한 이후부터 적용되게 된다.
// 전역 서브클래싱을 적용하려는 윈도우 바로 위에서 이전 윈도우 프로시저의 번지 기억!
// 3번째 인자 - 서브 클래스 프로시저명
OldEditProc = (WNDPROC)SetClassLongPtr(hEdit1, GCLP_WNDPROC,
(LONG_PTR)SubEditProc);
// hEdit2 윈도우에 전역 서브클래싱이 적용된다.
hEdit2 = CreateWindow (
TEXT("edit"),
NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
10,
50,
200,
25,
hwnd,
(HMENU)ID_EDIT2,
g_hInst,
NULL
);
SetFocus(hEdit1);
return 0;
case WM_PAINT : hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 100, Mes, lstrlen(Mes));
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY : SetClassLongPtr(hEdit1, GCLP_WNDPROC,
(LONG_PTR)OldEditProc);
PostQuitMessage(0);
return 0;
}
return (DefWindowProc(hwnd, message, wp, lp));
}
// 서브클래스 윈도우 프로시저 - hEdit2 (이후)만 서브 클래싱이 적용되어 있다!
LRESULT CALLBACK SubEditProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
TCHAR str[BUF_SIZE];
switch(message)
{
case WM_KEYDOWN : if(wp == VK_RETURN)
{
GetWindowText(hwnd, str, BUF_SIZE);
SetWindowText(GetParent(hwnd), str);
}
break;
}
// CallWindowProc 함수 : 관심을 가지는 메시지 이외에는 원래의 에디트 윈도우 방식으로 처리!
return (CallWindowProc(OldEditProc, hwnd, message, wp, lp));
}
=================================================================================================
'IT_Programming > MFC · API' 카테고리의 다른 글
[펌] 유니코드를 위한 Win API | MFC 프로그래밍 (0) | 2009.07.31 |
---|---|
[API] 슈퍼 클래싱 (Super Classing) (0) | 2009.07.29 |
[API] 사용자 정의 메시지 핸들러 & 메시지 크래커 (0) | 2009.07.29 |
[API] 윈도우 프로퍼티 (Window Property) (0) | 2009.07.24 |
[API] 여분의 메모리를 사용하는 이유와 방법 (0) | 2009.07.24 |