SetWindowLong

원형

LONG SetWindowLong( HWND hWnd, int nIndex, LONG dwNewLong);

MFC 원형

해당하는 함수 없음

인수

▶hWnd : 속성을 변경하고자 하는 윈도우의 핸들

▶nIndex : 변경하고자 하는 속성을 지정하며 다음 중 하나의 값을 줄 수 있다.

설명
GWL_EXSTYLE 확장 스타일
GWL_STYLE 윈도우 스타일
GWL_WNDPROC 윈도우 프로시저의 번지
GWL_HINSTANCE 인스턴스 핸들
GWL_ID 윈도우의 ID
GWL_USERDATA 윈도우와 관련된 사용자 데이터
DWL_DLGPROC 대화상자 프로시저의 주소
DWL_MSGRESULT 대화상자 프로시저의 리턴값
DWL_USER 사용자 데이터

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

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

리턴

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

설명

윈도우의 속성은 CreateWindow(Ex) 함수로 윈도우를 생성할 때 지정한다. 일단 윈도우가 만들어진 후에는 이 함수로 윈도우의 속성을 변경할 수 있다. 이때 주로 변경의 대상이 되는 것은 GWL_STYLE 즉 윈도우의 스타일이며 여분 메모리 조작을 위해서도 이 함수가 사용된다. 또한 윈도우 프로시저의 번지를 새로운 함수로 바꿈으로써 윈도우를 서브 클래싱할 수도 있다.

단 이 함수는 같은 스레드에 속한 윈도우의 속성만을 변경할 수 있다. 다른 스레드에서 생성한 윈도우의 속성은 변경할 수 없다. 또한 이 함수로 변경할 수 있는 값들 중 특정 스타일은 시스템에 의해 캐시되므로 변경 즉시 효과가 나타나지 않을 수도 있으며 SetWindowPos 함수로 캐시를 비워주어야 하는 것도 있다. 다음 예제를 통해 이 함수의 사용예를 보도록 하자.

예제 1

다음 예제는 윈도우의 스타일을 실행중에 변경한다. GWL_STYLE 인덱스로 윈도우의 스타일을 조사하여 WS_THICKFRAME 스타일을 토글한다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	LONG wndStyle;
	char Mes[]="마우스 버튼을 누를 때마다 경계선의 스타일을 변경한다";

	switch(iMessage) {
	case WM_LBUTTONDOWN:
		wndStyle=GetWindowLong(hWnd,GWL_STYLE);
		if (wndStyle & WS_THICKFRAME) {
			wndStyle=wndStyle & ~WS_THICKFRAME;
		} else {
			wndStyle=wndStyle | WS_THICKFRAME;
		}
		SetWindowLong(hWnd,GWL_STYLE,wndStyle);
		SendMessage(hWnd,WM_NCPAINT,1,0);
		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));
}

마우스를 누를 때만 경계선 스타일이 바뀌며 크기 조정 여부가 토글된다. 경계선 스타일은 비작업 영역의 모양에 영향을 주므로 스타일을 바꾼 직후에는 반드시 WM_NCPAINT 메시지를 보내주어 변경된 경계선 스타일이 즉시 적용되도록 해 주어야 한다.

이 방법을 사용하면 윈도우의 모든 스타일과 확장 스타일을 실행중에 마음대로 변경할 수 있다. 단 확장 스타일중에 WS_EX_TOPMOST 스타일은 여러가지 부수적 효과가 있으므로 SetWindowLong 함수로 변경할 수 없으며 반드시 SetWindowPos 함수로 바꿔 주어야 한다.

예제 2

다음 예제는 이 함수로 윈도우 프로시저를 교체하는 서브클래싱을 한다. 윈도우 프로시저는 윈도우로 전달되는 모든 메시지를 처리함으로써 윈도우의 행동 방식을 결정하는데 이 함수를 변경하면 윈도우의 동작을 원하는대로 수정할 수 있다. 서브클래싱의 원리는 다음과 같다.

원래의 윈도우 프로시저를 서브클래스 프로시저로 교체하고 서브클래스 프로시저에서 원하는 메시지를 가로채서 먼저 처리함으로써 표준 컨트롤 등의 동작을 변경한다. 개념적으로 도스의 인터럽터 가로채기와 유사하다.

HWND hEdit1;
WNDPROC OldEditProc;
LRESULT CALLBACK EditSubProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch (iMessage) {
	case WM_CHAR:
		if (wParam == 'C' || wParam == 'c')
			return 0;
		if (wParam == 'D' || wParam == 'd')
			wParam = 'Z';
		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[]="에디트에 C키 입력을 금지하고 D입력을 Z로 바꾼다.";
	switch(iMessage) {
	case WM_CREATE:
		hEdit1=CreateWindow("edit",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER,
			10,10,300,25,hWnd,(HMENU)0,g_hInst,NULL);
		SetFocus(hEdit1);
		OldEditProc=(WNDPROC)SetWindowLong(hEdit1,GWL_WNDPROC,(LONG)EditSubProc);
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,10,100,Mes,strlen(Mes));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		SetWindowLong(hEdit1,GWL_WNDPROC,(LONG)OldEditProc);
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

EditSubProc이라는 서브클래스 프로시저를 정의하고 SetWindowLong 함수로 에디트의 윈도우 프로시저를 이 함수로 교체하였다. 이때 원래의 윈도우 프로시저는 OldEditProc 변수에 저장해 두어야 디폴트 메시지 처리를 할 수 있다. 서브클래스 프로시저에서는 WM_CHAR 메시지를 받았을 때 C 문자가 입력되는 것을 거부할 수 있으며 D문자는 Z문자로 바꿀 수도 있다. 즉, 서브클래스 프로시저는 항상 원래 프로시저보다 먼저 메시지를 받기 때문에 원하는 어떤 처리든지 할 수 있다.

이 예제는 서브클래싱의 개념을 보여주기 위해 가시적으로 확인이 쉬운 WM_CHAR 메시지를 사용했는데 실제 프로그래밍에서는 WM_KEYDOWN을 가로채서 특정 키가 입력되는 것을 알아낸다거나 WM_LBUTTONDOWN 메시지를 가로채서 마우스 액션을 바꿀 수도 있다. 또한 WM_PAINT나 WM_NCPAINT를 가로채면 윈도우의 모양을 완전히 바꿀 수도 있다. 그러나 SetWindowLong 함수에 의한 인스턴스 서브클래싱은 윈도우가 이미 만들어지고 난 후에 이루어지는 것이므로 WM_CREATE는 가로챌 수 없으며 여분 메모리는 절대로 조작해서는 안된다는 제약이 있다.

예제 3

다음 예제는 윈도우의 여분 메모리를 사용하는 방법을 보여준다. 여분 메모리는 윈도우를 생성할 때 추가로 할당되는 메모리이며 윈도우가 자신의 고유한 용도로 사용할 수 있는 메모리 영역이다. 주로 자신의 고유한 속성값이나 설정상태를 기억할 때 사용한다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	int x,y;
	switch(iMessage) {
	case WM_CREATE:
		for (x=0;x<1000;x+=100)
			for (y=0;y<1000;y+=100) {
				CreateWindow("ChildCls",NULL,WS_CHILD | WS_VISIBLE,
				x,y,100,100,hWnd,(HMENU)NULL,g_hInst,NULL);
			}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

LRESULT CALLBACK ChildProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	int Shape;
	COLORREF Color;
	HBRUSH hBrush, OldBrush;

	switch(iMessage) {
	case WM_CREATE:
		SetWindowLong(hWnd, 0, 0);
		SetWindowLong(hWnd, 4, RGB(0,0,255));
		return 0;
	case WM_LBUTTONDOWN:
		Shape=GetWindowLong(hWnd,0);
		Shape++;
		if (Shape==3)
			Shape=0;
		SetWindowLong(hWnd,0,Shape);
		InvalidateRect(hWnd,NULL,TRUE);
		return 0;
	case WM_RBUTTONDOWN:
		Color=GetWindowLong(hWnd,4);
		if (Color == RGB(0,0,255)) {
			Color=RGB(255,0,0);
		} else {
			Color = Color << 8;
		}
		SetWindowLong(hWnd,4,Color);
		InvalidateRect(hWnd,NULL,TRUE);
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		Color=GetWindowLong(hWnd,4);
		Shape=GetWindowLong(hWnd,0);
		hBrush=CreateSolidBrush(Color);
		OldBrush=(HBRUSH)SelectObject(hdc,hBrush);
		switch (Shape) {
		case 0:
			Rectangle(hdc,0,0,100,100);
			break;
		case 1:
			RoundRect(hdc,0,0,100,100,40,40);
			break;
		case 2:
			Ellipse(hdc,0,0,100,100);
			break;
		}
		EndPaint(hWnd, &ps);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

이 예제는 9개의 차일드 윈도우를 생성하되 각각의 차일드는 8바이트의 여분 메모리(정수 두 개)를 가지고 있다. 여분 메모리는 윈도우 클래스의 cbWndExtra 멤버에 그 양을 지정한다. 차일드 윈도우는 여분 메모리의 첫 4바이트에 자신의 작업영역에 그릴 도형의 모양을 기억하며 다음 4바이트에 도형의 색상을 기억한다. 왼쪽 마우스 버튼을 누르면 GetWindowLong으로 여분 메모리에서 도형의 모양을 읽어와 다음 도형 모양으로 변경하며 오른쪽 마우스 버튼을 누르면 도형의 색상을 변경한다.

WM_PAINT에서는 여분 메모리로부터 도형의 모양과 색상을 읽어와 작업 영역에 해당 도형을 그린다. 각 윈도우가 고유의 여분 메모리를 가지므로 별도의 전역 변수없이 스스로 자신의 상태를 훌륭하게 기억할 수 있다. 크기가 큰 정보를 여분 메모리에 담고자 할 때는 구조체 포인터를 사용한다.

참고함수

GetWindowLong : 윈도우의 속성값을 조사한다.

플랫폼

95이상

참조

윈도우의 속성에 대해서는 10-3절을 참조하고 서브클래싱에 대해서는 11-2절을 참조한다.


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