관리 메뉴

드럼치는 프로그래머

[API/MFC] 윈도우, 윈도우 클래스, WNDCLASS 구조체 , WNDCLASSEX, SetClassLong, GetClassLong, GetClassLongPtr, SetClassLongPtr 본문

★─Programing/☆─API | MFC

[API/MFC] 윈도우, 윈도우 클래스, WNDCLASS 구조체 , WNDCLASSEX, SetClassLong, GetClassLong, GetClassLongPtr, SetClassLongPtr

드럼치는한동이 2010. 2. 16. 16:24

[윈도우의 정의]

- 프로그램이 출력 결과를 내 보내고 사용자로부터 입력을 받아들이는 화면상의 사격영역

[윈도우 클래스]

정의 : 모든 윈도우들은 윈도우 클래스로부터 만들어 진다. 윈도우 클래스는 윈도우를 만들기

위한 형틀이며 생성될 윈도우의 여러가지 특징들을 모아놓은 구조체이다.

[윈도우 클래스의 종류]

1. 시스템 전역 클래스
   - 운영체제가 부팅될 때 등록되며 주로 컨트롤을 만들때 사용된다.
     ex) button, edit, scrollbar, listbox 등

2. 응용 프로그램 전역 클래스
   - dll에 의하여 등록되며 프로세스의 모든 모듈에서 이 클래스를 사용할수 있다.
   - 커스텀 컨트롤을 위한 클래스를 DLL에서정의하면 프로그램에서는  DLL을 로드해서 이
     클래스를 사용할 수 있다. 클래스 스타일에 GS_GLOBALCLASS 스타일을 지정해야 한다.

3. 응용 프로그램 로컬 클래스
   - 응용 프로그램 자신이 메인 윈도우나 차일드 또는 커스텀 컨트롤을 맏늘기 위해 프로그램 선두에서 등록한
    클래스이며 프로그램 내부에서 사용된다.ㄴ


[WNDCLASS 구조체]

typedef struct tagWNDCLASSA {
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCSTR      lpszMenuName;
    LPCSTR      lpszClassName;
} WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;


위와 같이 되어 있다... 각 구조체 멤버에 대한 설명은..


-------------------------------

----- lpszClassName -----

등록하고자 하는 윈도우 클래스의 이름을 나타낸다.

------------------------------


----- hInstance -----

이 윈도우 클래스를 등록한 응용 프로그램의 인스턴스 핸들이다.

메인 윈도우를 만들때 WinMain으로 전달된 hInstance 인수를 그대로 대입하면 된다.

------------------------------


----- lpFnWndProc -----

메시지 처리 함수를 지정한다. 이 클래스로 부터 만들어진 윈도우에 메시지가 전달되며

이 멤버가 지정하는 함수로 메시지가 전달되어 윈도우의 고유의 처리를 하게 된다.

------------------------------

----- hCursor -----

클래스 커서를 지정한다.

--------------------

-----  hIcon -----

클래스 아이콘을 지정한다.

--------------------

----- hbrBackground -----

윈도우의 작업영역을 칠할 배경 브러시를 지정한다.

---------------


----- lpszMenuName -----

이 클래스로부터 만들어진 윈도우가 사용할 메뉴를 지정한다. 메뉴는 윈도우 클래스에서뿐만 아니라

CreateWindow 함수에서 개별 윈도우를 만들때 지정할수도 있다. CreateWindow 함수에서 지정하면

lpszMenuName 에서 지정한 메뉴는 무시된다.


-------------------------

----- sytle -----

윈도우 클래스의 스타일을 지정한다.

--------------------

----- cbClsExtra -----

윈도우 클래스에서 사용하고자 하는 여분의 메모리양을 바이트 단위로 지정한다.

운영체제는 윈도우 클래스를 등록할 때 이 멤버가 지정하는 만큼의 메모리를 추가로 할당한다.


SetClassLong(Ptr); GetClassLong(Ptr); 등의 함수로 이 메모리를 사용한다.
-----------------------------------


----- cbWndExtra -----

cbClsExtra와 유사하되 개별 윈도우에서 사용하고자 하는 여분의 메모리양을 지정한다. 운영체제는

CreateWindow로 개별 윈도우를 만들 때마다 이 멤버가 지정하는 만큼의 메모리를 추가로 할당한다.

응용프로그램에서는 GetWindowLong(Ptr), SetWindowLong(Ptr) 등의 함수로 이 메모리를 사용한다.

-------------------------


[WNDCLASSEX]


WNDCLASS 구조체에 확장버전인 WNDCLASSEX 구조체는 두가지가 더 추가되었는데

하나는 UINT sbSize 구조체 사이즈를 지정하는 멤버이고 (버전확인을 위해) 또 하나는

HICON hIconSm;  으로 작은 아이콘을 지정할때 사용한다.

구조체 멤버는


typedef struct tagWNDCLASSEXA {
    UINT        cbSize;
    /* Win 3.x */
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCSTR      lpszMenuName;
    LPCSTR      lpszClassName;
    /* Win 4.0 */
    HICON       hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, NEAR *NPWNDCLASSEXA, FAR *LPWNDCLASSEXA;


위와 같다..

sbSize는 구조체 자체를 sizeof(); 로 대입하면되고.. 새로 생긴 작은아이콘 hIconSm 은

WndClassEx.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICON1),
IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),LR_DEFAULTCOLOR);

클래스 멤버를 초기화후 등록할때는

ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcs): 라는 함수로 등록해야 한다고한다....


-----------------------------------


[ GetClassLong, SetClassLong, GetClassLongPtr, SetClassLongPtr ]

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

LONG_PTR GetClassLongPtr(HWND hWnd, int nIndex);
ULONG_PTR SetClassLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong);

WNDCLASS(EX) 의 구조체 값은 윈도우 클래스를 등록할 때 정해지지만 등록된 후에도 수정할 수 있다.

그러한 방법을 제공하는 함수가 위의 함수들이다.

하지만 위에 GetClassLong, SetClassLong 두 함수는 과거에 많이 썻지만 최근 64비트 호환이 되지 않으므로

요즘에는 잘 쓰지않고 아래 두 함수 GetClassLongPtr, SetClassLongPtr 가  가장 많이 쓰인다고 한다.

함수인자의 첫번째와 세번째는 딱 봐도 무슨의미 인지 알겠지만 두번째 인자 nIndex는 클래스구조체의 값과 매치되는데 아래와 같다.

GCL_MENUNAME       
GCL_HBRBACKGROUND
GCL_HCURSOR  
GCL_HICON         
GCL_HMODULE     
GCL_CBWNDEXTRA
GCL_CBCLSEXTRA
GCL_WNDPROC  
GCL_STYLE         
GCW_ATOM          
GCL_HICONSM        

딱봐도 구조체와 대응된다는것 알수 있다.

해당 구조체의 값을 변경하는 인덱스는 위와 같은 인자를 주면 가능하다.

그러면 정말로 프로그램 실행중에 윈도우 클래스를 바꺼서   윈도우에 변화를 주는 예제를 만들어보자

※ 64비트호환 버전인 GetClassLongPtr , SetClassLongPtr 함수 사용시 위의 인자값에서 GCL 다음 P를 하나 더 붙여야 한다.

GCL_HBRBACKGROUND  의 경우 GCLP_HBRBACKGROUND  라고 해야 64비트 호환 함수 인자로 할수 있다.

하지만 독자의 컴퓨터에서는 SetClassLongPtr 함수가 이상하게 사용이 안됬다. 컴파일 에러가 났다. 이유는 모르겠다.


--------------- 윈도우 실행도중 클래스를 바꾸는 에제 SetClassLong 함수 사용  ---------------------


#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("First");  //윈도우 이름 및 타이틀바에 등록할 문자열

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
  HWND hWnd;
  MSG Message;
  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 = lpszClass;
  WndClass.lpszMenuName = NULL;
  WndClass.style = CS_HREDRAW | CS_VREDRAW;

  //------------ 위 부분은 윈도우 클래스를 설정해주는 것이다. --------------------

  RegisterClass(&WndClass);   //  <-- 여기서는 위에서 설정한 클래스를 등록한다.

  hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
    CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);   // 설정하고 등록한 윈도우를 생성한다.

  ShowWindow(hWnd,nCmdShow);   //생성한 윈도우를 출력..(이 함수를 호출하지않으면 윈도우가 보이지 않는다.)

  while(GetMessage(&Message,NULL,0,0))   //사용자가 종료하기 전까지 반복해서 메세지 처리를 호출한다.
  {
   TranslateMessage(&Message);
   DispatchMessage(&Message);
  }

  return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) //여기서 실제로 메시지를 처리한다.
{
 static HBRUSH hRed, hGreen, hBlue;
 static HBRUSH NowBrush;

 switch(iMessage)
  {
 case WM_CREATE:  
  hRed = CreateSolidBrush(RGB(255,0,0));
  hGreen = CreateSolidBrush(RGB(0,255,0));
  hBlue = CreateSolidBrush(RGB(0,0,255));
  NowBrush = hRed;
  return 0;

 case WM_LBUTTONDOWN:
  if(NowBrush == hRed) NowBrush = hGreen;
  else if(NowBrush == hGreen) NowBrush = hBlue;
  else if(NowBrush == hBlue)  NowBrush = hRed;

  
SetClassLong(hWnd,GCL_HBRBACKGROUND,(LONG)NowBrush);  

  InvalidateRect(hWnd,NULL,TRUE);

  return 0;

  case WM_DESTROY:
   DeleteObject(hRed);
   DeleteObject(hGreen);
   DeleteObject(hBlue);
   PostQuitMessage(0);
   return 0;
  }

 return DefWindowProc(hWnd,iMessage,wParam,lParam);  //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}

-------------------------------------------------------------------------------------------

위의 코드를 실행하면 마우스를 왼쪽 클릭할때마다 윈도우 배경색이 바뀌는 것을 볼수 있다.^^;


하지만 독자의 컴퓨터에서는 SetClassLongPtr 함수가 이상하게 사용이 안됬다. 컴파일 에러가 났다. 이유는 모르겠다.

그래서 32비트 SetClassLong 버전을 썼다.-_-ㅋㅋ


Comments