SetClassLong

원형

DWORD SetClassLong( HWND hWnd, int nIndex, LONG dwNewLong);

MFC 원형

해당하는 함수 없음

인수

▶ hWnd : 수정할 클래스가 속해있는 윈도우의 핸들. 윈도우의 핸들을 통해 윈도우 클래스를 간접적으로 지정하며 수정대상은 이 윈도우가 아니라 윈도우가 속해있는 윈도우 클래스이다.

▶ nIndex : 수정할 값을 지정하며 다음 값 중 하나를 지정한다. 윈도우 클래스를 등록할 때 사용하는 WNDCLASS 구조체의 멤버에 대응된다.

설명
GCL_CBCLSEXTRA

cbClsExtra 멤버값. 클래스의 여분 메모리 양을 변경하며 이 값을 변경하더라도 기존에 들어는 값은 변하지 않는다.

GCL_CBWNDEXTRA

cbWndExtra 멤버값. 윈도우의 여분 메모리 양을 변경하며 이 값을 변경하더라도 기존에 들어는 값은 변하지 않는다.

GCL_HBRBACKGROUND 윈도우의 배경 브러시 핸들. hbrBackground 멤버
GCL_HCURSOR 윈도우의 커서 핸들. hCursor 멤버
GCL_HICON 윈도우의 아이콘 핸들. hIcon 멤버
GCL_HMODULE 윈도우 클래스를 등록한 프로그램의 핸들. hInstance 멤버
GCL_MENUNAME 메뉴 리소스 문자열. hMenu 멤버
GCL_STYLE 윈도우 클래스의 스타일. style 멤버
GCL_WNDPROC 윈도우 프로시저의 주소. lpfnWndProc 멤버

또는 윈도우 클래스에 여분 메모리가 등록되어 있을 경우 여분 메모리의 오프셋을 지정할 수 있다. 이 값은 반드시 양수여야 하며 cbClsExtra-4보다는 작아야 한다. 예를 들어 여분 메모리가 16바이트 지정되어 있으면 nIndex는 0~12까지 지정할 수 있다.

▶dwNewLong : 새로 변경할 32비트값이며 nIndex에 따라 값의 의미는 달라진다.

리턴

성공하면 이전에 설정되어 있던 32비트값을 리턴하며 값이 설정되어 있지 않았으면 0을 리턴한다. 또한 에러가 발생해도 0을 리턴한다.

설명

윈도우 클래스는 WNDCLASS(EX) 구조체에 의해 속성들이 지정되며 RegisterClass(Ex) 함수에 의해 이 속성들이 등록된다. 일단 등록된 클래스의 속성을 변경하고자 할 때 SetClassLong 함수가 사용되는데 WNDCLASS 구조체의 멤버 중 어떤 값을 변경할 것인가를 nIndex 인수로 지정해 주고 dwNewLong 인수로 새로운 속성값을 지정해 주면 된다. 단 윈도우 클래스의 정보 중 이름은 변경할 수 없다.

윈도우 클래스의 속성 중 어떤 것을 변경하는가에 따라 효과는 다양하게 나타난다. 배경 브러시를 변경할 수도 있고 커서 모양을 바꿀 수도 있고 윈도우 프로시저를 변경할 수도 있다. 이어지는 예제로 이 함수의 사용예를 살펴보도록 하자.

예제 1

다음 예제는 이미 만들어진 윈도우의 커서를 변경한다. 윈도우의 작업영역에서 보여줄 커서는 윈도우 클래스의 hCursor멤버에서 지정하는데 이 멤버를 SetClassLong 함수로 실행중에 변경하는 예를 보인다.

HCURSOR hArrow, hIBeam, hWait, hNow;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	char Mes[]="마우스 버튼을 누르면 커서 모양이 바뀝니다";

	switch(iMessage) {
	case WM_CREATE:
		hArrow=LoadCursor(NULL,IDC_ARROW);
		hIBeam=LoadCursor(NULL,IDC_IBEAM);
		hWait=LoadCursor(NULL,IDC_WAIT);
		hNow=hArrow;
		return 0;
	case WM_LBUTTONDOWN:
		if (hNow==hArrow)
			hNow=hIBeam;
		else if (hNow==hIBeam)
			hNow=hWait;
		else
			hNow=hArrow;
		SetClassLong(hWnd, GCL_HCURSOR,(LONG)hNow);
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,10,10,Mes,lstrlen(Mes));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

세개의 표준 커서를 미리 만들어 두고 마우스 버튼을 누를 때마다 윈도우 클래스의 hCursor 멤버를 변경함으로써 커서를 바꾸고 있다. 작업영역 전체의 커서를 변경할 때는 이 방법을 사용하고 화면의 특정 부위에서만 커서를 변경할 때는 WM_SETCURSOR 메시지를 사용해야 한다.

예제 2

다음 예제는 윈도우 클래스에 등록되어 있는 메시지 처리 함수를 실행중에 변경하는 전역 서브클래싱을 보여준다. 윈도우 클래스의 윈도우 프로시저를 변경하면 이후 이 윈도우 클래스로부터 생성되는 모든 윈도우들은 변경된 윈도우 프로시저가 메시지를 처리함으로써 메시지 처리 방식을 바꿀 수 있다. 모든 컨트롤의 동작 방식을 바꾸고자 할 때 이 방법이 사용된다.

HWND hEdit1, hEdit2, hEdit3, hEditHidden;
WNDPROC OldEditProc;
LRESULT CALLBACK EditSubProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	char str[256];
	switch (iMessage) {
	case WM_KEYDOWN:
		if (wParam==VK_RETURN) {
			GetWindowText(hWnd,str,256);
			SetWindowText(GetParent(hWnd),str);
		}
		break;
	}
	return CallWindowProc(OldEditProc,hWnd,iMessage,wParam,lParam);
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	char Mes[]="모든 에디트키의 Enter키 입력을 검출합니다";
	switch(iMessage) {
	case WM_CREATE:
		hEditHidden=CreateWindow("edit",NULL,WS_CHILD | WS_BORDER,
			10,10,200,25,hWnd,(HMENU)0,g_hInst,NULL);

		OldEditProc=(WNDPROC)SetClassLong(hEditHidden,GCL_WNDPROC,(LONG)EditSubProc);

		hEdit1=CreateWindow("edit",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER,
			10,10,300,25,hWnd,(HMENU)1,g_hInst,NULL);
		hEdit2=CreateWindow("edit",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER,
			10,50,300,25,hWnd,(HMENU)1,g_hInst,NULL);
		hEdit3=CreateWindow("edit",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER,
			10,90,300,25,hWnd,(HMENU)1,g_hInst,NULL);
		SetFocus(hEdit1);
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,10,120,Mes,strlen(Mes));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		SetClassLong(hEdit1,GCL_WNDPROC,(LONG)OldEditProc);
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

4개의 에디트 컨트롤을 생성하는데 이 중 hEditHidden는 전역 서브 클래싱을 위해 사용할 숨겨진 에디트 컨트롤이다. 윈도우 클래스는 윈도우 핸들로 간접적으로 지정할 수 있기 때문에 전역 서브 클래싱을 하기 위해서는 반드시 먼저 만들어진 윈도우가 있어야 한다. 그러나 전역 서브 클래싱의 효과는 먼저 만들어진 윈도우에는 적용되지 않으므로 숨겨진 윈도우를 먼저 만들고 이 윈도우를 대상으로 전역 서브클래싱을 한다.

전역 서브클래싱은 SetClassLong 함수로 GCL_WNDPROC값을 새로운 윈도우 프로시저로 대체함으로써 구현된다. 예제에서는 새로운 윈도우 프로시저로 사용할 EditSubProc이라는 콜백 함수가 미리 정의되어 있으며 이 함수는 반드시 WndProc과 같은 원형을 가지고 있어야 한다. 윈도우 프로시저를 새로운 함수로 대체할 때 반드시 이전에 설정되어 있던 윈도우 프로시저 주소를 저장해 두어야 디폴트 메시지 처리를 할 수 있는데 예제에서는 OldEditProc 이라는 변수에 SetClassLong 함수가 리턴하는 이전 함수의 번지를 저장해 두었다.

전역 서브클래싱을 한 후 만들어진 hEdit1, hEdit2, hEdit3 컨트롤은 EditSubProc이라는 함수가 메시지를 처리하게 된다. 이 함수에서는 엔터키 입력이 있을 때 자신의 텍스트를 읽어 메인 윈도우의 캡션에 출력하는 일을 하고 있는데 이외에 어떠한 다른 메시지 처리도 가능하다.

에디트에 문자열을 입력한 후 Enter키를 누르면 메인 윈도우의 캡션이 즉시 변경된다.

예제 3

다음 예제는 윈도우 클래스의 스타일을 실행중에 변경한다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	char Mes[]="마우스 버튼을 누를 때마다 HREDRAW, VREDRAW 스타일을 토글합니다";
	RECT rt;
	DWORD clsStyle;

	switch(iMessage) {
	case WM_LBUTTONDOWN:
		clsStyle=GetClassLong(hWnd,GCL_STYLE);
		if (clsStyle & CS_HREDRAW) {
			clsStyle=clsStyle & ~(CS_HREDRAW | CS_VREDRAW);
		} else {
			clsStyle=clsStyle | (CS_HREDRAW | CS_VREDRAW);
		}
		SetClassLong(hWnd,GCL_STYLE,clsStyle);
		InvalidateRect(hWnd,NULL,TRUE);
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,10,10,Mes,lstrlen(Mes));
		GetClientRect(hWnd,&rt);
		Ellipse(hdc,rt.left,rt.top+50,rt.right,rt.bottom);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

마우스 버튼을 누를 때마다 CS_HREDRAW, CS_VREDRAW 스타일을 토글함으로써 작업영역 그리기에 영향을 준다. 이 두 스타일이 지정되어 있으면 작업영역 크기가 바뀔 때마다 다시 그려지지만 그렇지 않으면 크기가 바뀌어도 다시 그려지지 않기 때문에 다음과 같이 화면이 깨지게 된다.

이외에 이 함수는 윈도우의 배경 브러시를 바꾸거나 메뉴를 바꾸는 용도로도 사용할 수 있다.

참고함수

GetClassLong : 윈도우 클래스의 속성값을 조사한다.

플랫폼

95이상

참조

윈도우 클래스에 대해서는 10-2절을 참조하고 서브클래싱에 대해서는 11-2절을 참조하기 바란다.


written by http://www.winapi.co.kr