posted by nsakura 2010. 7. 15. 00:58

#include <windows.h>

HINSTANCE g_hlnst;

LPCTSTR lpszClass=TEXT("windows");

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,WPARAM wParam,LPARAM lParam){
 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_hlnst=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,nShowCmd);

 while(GetMessage(&Message,NULL,0,0)){
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }
 
 return (int)Message.wParam;
}

소스 분석은 일어나서 바로 하겠습니다.

간단한 설명으로는 그냥 윈도우 창하나 만드는 소스라고보시면 됩니다.

자고 일어났으니 분석에 나서 봅시다..

뭐  그리 어려운건 아니에요.

자 우리들이 프로그래밍할때 main이 있었죠? 윈도우 프로그래밍에서의 main은 WinMain입니다.

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) 입니다.

 인수 의미 
 hInstance 프로그램의 인스턴스 핸들 
 hPrevInstance 바로 앞에 실행된 현재 프로그램의 인스턴스 핸들. 없는 경우 NULL이 된다 . win32에서는 항상 NULL 16비트와 호환성을 위해 존재 
 lpszCmdParam argv 인수에 해당하는 보통 실행 직후에 열 파일의 경우 전달된다. 
 nCmdShow 프로그램이 실행될 형태이며 최소화, 보통 모양 등이 전달된다. 


자 그럼 Instance Instance계속 나오죠. 이게 뭘까요?

간단히 말해 인스턴스는 실행중인 프로그램 하나를 칭하는 말입니다.

윈도우 환경을 우리는 많이 쓰잖아요? 윈도우는 멀티태스킹 환경이지요. 그래서 여러개의 프로그램이 동작을 하죠?

뿐만 아니라 같은 프로그램을 두개 키는 경우도 있을겁니다. 메모장을 두개 실행한다던다..

이때 실행되고 있는 각각의 프로그램을 instance라고 하는것이지요.

[instance의 값은 정수값을 가집니다. 프로그램 내부에에서 자기 자신을 가리키는 1인칭 대명사 이다.]

LPCTSTR lpszClass=TEXT("제목");  제목표시줄에 이름을 설정하는곳이다.

LPCTSTR가 뭔지 모르겠다구요? 간단히 말하면 문자열 변수 입니다.

한번 들어가보죠 LPCTSTR window.h > windef.h >winnt.h 에 보시면.

typedef LPCSTR LPCTSTR; 라고 되어있죠?

LPCSTR은?

typedef CONST CHAR *LPCSTR, *PCSTR;

라고 되어있지요. 결국 문자열입니다.

찾아보니 재미있는 문장이 있네요. 프로그램 시작점이 WinMain이기 때문에 main이라는 이름의 일반 함수를 만들어 사용하는것도

가능 합니다. 이거 참.. 재미있네요?.

메시지 처리 함수,

이 프로그램에서는 두개의 함수만 정의하고 있다. 하나는 프로그램 시작점 WinMain이고 나머지는 WndProc이다 .

WndProc 사용자와 시스템이 보내오는 메시지를 처리하는 아주 중요한 일을 담당 도스에서는 main하나만으로 프로그램을 작성 가능

가능 하지만 윈도우즈에서는 특별한 일을 제외하면 이 두개의 함수가 모두 있어야 한다.

WinMain 메인 윈도우를 만들고 화면에 윈도우를 표시하기만 한다.[초기화 시키는 작업임으로 대채로 모양이 일정]

WndProc 대부분의 일이 이 함수에서 이루어 진다. [실질적으로 고유한 처리를 하는곳 프로그램마다 천차만별]

WNDCLASS 

프로그램의 중간에 나오는 WndClass 구조체의 구성을 한번 볼까요?

windows.h에 정의 되어있습니다.

typedef struct tagWNDCLASS{
 UINT style;
 WNDPROC lpfnWndProc;
 int cbClsExtra
 int cbWndExtra
 HINSTANCE hInstance
 HICON hIcon
 HCURSOR hCursor
 HBRUSH hbrBackground
 LPCSTR lpszMenuName
 LPCSTR lpszClassName
}WNDCLASS

 style  윈도우의 형태 주로 CS_HREDRAW CS_VREDRAW 사용
수평,수직크기가 변경되면 윈도우를 다시 그림.
 WNDPROC  윈도우의 메시지 처리 함수를 지정 메시지가 발생할때마다 이 멤머가 지정하는 함수가 호출
 cbClsExtra,cbWndExtra  일종의 예약어 특수한경우 아니면 사용안함
사용을 안하는 경우 0으로 지정
 hInstance  이 윈도우 클래스를 등록하는 프로그램의 번호 WinMain의 인수로 전달된 인스턴스값을 그대로 대입.
 hIcon,hCursor  윈도우가 사용할 마우스 커서와 아이콘을 지정 LoadCursor 함수와 LoadIcon함수를 사용하여 아이콘과 커서를 읽어와 이 멤버에 대입.
 hbrBackground  윈도우 배경 색상을 지정 GetStockObject라는 함수를 사용 기본적으로 제공하는 브로시를 지정하거나 COLOR_WINDOW같은 시스템 색상을 지정이 가능하다.
 lpszMenuName  이 프로그램이 사용할 매뉴를 지정 매뉴는 프로그램 코드에서 실행중에 만드는 것이 아니라 리소스 에디터에 의해 별도로 만들어져 링크시에 같이 합쳐진다.
 lpszClassName  윈도우 클래스의 이름을 문자열로 처리 지정한 이름은 CreateWindow 함수에 전달된다.
   
   

윈도우 생성 함수.

HWND CreateWindow(lpszClassName,lpszWindowName,dwStyle,x,y,nWidth,nHeight, hWndParent,hmenu,hinst,lpvParam);

 lpszClassName  생성하고자 하는 윈도우 클래스를 지정하는 문자열 WNDCLASS의 lpszClassName를 기입한다.
 lpszWindowName  윈도우 타이틀 바에 나타날 문장 마음데로 지정가능하다. 위의 예제에서는 windows라고 뜰 것이다.
 dwStyle  만들고자하는 윈도우의 형태를 지정하는 인수 일종의 비트 필드값 OR연산자로 연결  WS_OVERLAPPEDWINDOW 시스템매뉴,최대, 최소 버튼, 타이틀바, 경계선을 가진 윈도우를 만든다.
 x,y,nWidth,nHeight  윈도우의 크기와 위치를 지정.
 hWndParent  부모윈도우가 있는 경우 부모 윈도우의 핸들을 지정.
 hmenu  윈도우에서 사용할 메뉴의 핸들을 지정한다.
 hinst  프로그램의 핸들을 지정
 lpvParam  CREATESTRUCT 라는 구조체 번지 여러개의 윈도우를 만들때 각 윈도우에 고유의 파라메터를 전달하는 특수 목적에 사용.

자! 이제 윈도우가 생성되겠지!? 라고 생각하는 분 많을것이다 하지만. 아니다! 이렇게만하면 화면에 출려되지 않는다.

이유는 간단. 메모리에서만 윈도가 생성되었지만 화면에 출력되는 부분은 없기 때문이다.

여기서 사용 되는것이 BOOL ShowWindow(hWnd,nCmdShow); 함수를 만들어야 비로서 화면에 출력 되는 것이다.

hWnd는 설명을 안해도 되겠죠. 그럼 nCmdShow는 무엇인가?

윈도 화면에 출력하는 방법을 지정 하는것이며

다음과 같은 상수가 정의되어있다.

 매크로 상수 의미 
 SW_HIDE 윈도우를 숨긴다.
 SW_MINIMIZE  윈도우를 최소화하고 활성화 시키지 않는다.
 SW_RESTORE  윈도우를 활성화시킨다.
 SW_SHOW  윈도우를 활성화하여 보여준다.
 SW_SHOWNORMAL  윈도우를 활성화하여 보여준다.

메세지 루프

윈도우즈를 메세지 구동 시스템이라고도 하는데 이 점이 도스와 뚜렷한 차이를 이룬다. 도스는 프로그래머에가 미리 정해준 일련된 명

령을 순서대로 실행하는 순차적 방법을 사용 윈도는 다르다 실행순서가 명확하지가 않는다. 즉 상황에 따라 실행하는게 달라지는데

이걸 메세지라고 한다.

위의 프로그램에서는 

 while(GetMessage(&Message,NULL,0,0)){
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }

이 부분 이다.

BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFliterMin, UINT wMsgFilterMax);

이 함수는 큐에서 메시지를 읽어들인다

메세지큐는 사용자로 부터 발생한 메세지가 잠시 대기하는 일종의 메세지 임지 저장 영역.

잃어드린메세지는 MSG구조체에 저장된다. WM_QUIT일 경우 false를 리턴.

BOOL TranslateMessage(CONST mSG *lpmsg);

이 키보드에서 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있도록 한다.

그냥 간단하게 A를 누르면 A문자가 입력되었다는 메시지를 만들어낸다고 보면 된다.

LONG DispatchMessage(CONST MSG*lpmsg);

메세지 큐에서 꺼낸 메시지를 윈도우의 매시지 처리 함수로 전달(WndProc)

위에 함수는 공통적으로 MSG 구조체를 사용한다.

typedef struct tagMSG{
 HWND hwnd;
 UINT message;
 WPARAM wParam;
 LPARAM lParam;
 DWORD time;
 POINT pt;
}MSG

 hwnd  메세지를 받을 윈도우 핸들.
 message  어떤 종류의 메시지인가를 나타낸다.(중요)
 wParam  전달된 메시지에 대한 부가적인 정보를 가진다. 어떤의미를 가지는가는 메시지 별로 다르다. 32비트 값이다.
 lParam  전달된 메시지에 대한 부가적인 정보를 가진다. 어떤의미를 가지는가는 메시지 별로 다르다. 32비트 값이다.
 time  메시지가 발생한 시간이다.
 pt  메시지가 발생했을 때의 마우스 위치이다.


GetMessage로 메세지를 받아오고 그걸 MSG에 저장 그리고 DispatchMessage 함수에 의해 으용 프로그램의 메시지 처리 함수

(WndProc)으로 전달.

메시지의 종류는 무척 많다. 그중 몇 개만 뽑아서 정리해봤다. (설마 다외우자!~ 라고 하시는분은 안계시겠지?)

 WM_QUIT  프로그램을 끝낼 때 발생하는 메세지
 WM_LBUTTONDOWN  마우스 좌측 버튼을 누를 경우 발생한다
 WM_KEYDOWN  키보드의 키를 눌렀다.
 WM_CHAR  키보드로 부터 문자가 입력 될 때 발생한다.
 WM_PAINT  화면을 다시 그려야 할 필요가 있을 때 발생한다.
 WM_CREATE  윈도우가 처음 만들어질 때 발생한다.
 WM_DESTROY  윈도우가 메모리에서 지워질때 발생한다.

메세지 루프가 종룓회면 프로그램은 마지막으로  Message.wParam을 리턴하고 종료

윈도우 프로시저

메세지 처리 함수는 메시지가 발생할 때 프로그램의 반을 처리하는 일을 한다고 했다.  WndProc[window procedure] 보통 윈프록이라

한다. 그런데 여러분들은 이상하다고 느껴지지 않는가? 위에 프로그램은 선언과 정의는 되어있지만 winmain에서 사용하는 부분이

없다고 생각하지 않는가?

이는 winproc함수는 운영체제에 의해 호출이 되고 이걸 콜백(call back)함수라고 한다.

WndProc 함수의 인수는 모두 4개 msg 구조체의 멤버 4개와 동일하다,.(time,pt제외)

WndProc의 구조는 대체로 다음과 같아.
switch(iMessage){
case MSG1:
  처리1;
  retrun 0;
case MSG2:
  처리2:
  retrun 0;
case MSG3:
  처리1:
  retrun 0;
default:
  return DefWindowProc(...........);
}

그럼 함수내용을 잠깐 둘러보도록 하자

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,WPARAM wParam,LPARAM lParam){
 switch(iMessage){
 case WM_DESTROY
  PostQuitMessage(0);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

WM_DESTROY 메세지가 들어오면 PostQuitMessage 함수를 호출

WM_QUIT메세지를 보낸다 WM_QUIT메세지가 입력되면 메세지 루프의 GetMessage 함수 리턴값이 False가 되어 while을 빠져

나오면서 WinMain이 종료

이 부분이 되겠죠?

 while(GetMessage(&Message,NULL,0,0)){
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 } 


그 외의 메세지가 입력되면

그 메세지는 DefWindowProc함수로 전달되어 별다른 코드 없이 윈도우창을 줄이거나 등등 작업을 할수있는 것이다.

상당히 dos시절에 비하면 편하다.


프로그램의 흐름은 이런 흐름도를 가진다.

뭐 큐가 따로 없어서 링크드 리스트로 대충 표현을 해놓았다 그냥 큐라고 보면 된다.

자 결과는 이런 결과물이 나온다.



 

'Computer > Win API' 카테고리의 다른 글

WinApi MessageBox  (0) 2010.07.17
WinApi 여러가지 출력  (0) 2010.07.16
WinApi DrawText  (0) 2010.07.15
WinApi DC 예제  (0) 2010.07.15
WinApi 예제1의 확장  (0) 2010.07.15