WinAPI-기본코드 함수분석 및 정리

 

윈도우즈 API의 기본코드와 구조에 대해서 알아보자

 

#include <windows.h>

 

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

HINSTANCE g_hInst;

LPCTSTR lpszClass = TEXT("SKFirst");

 

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 )

{

           switch(iMessage)

           {

           case WM_DESTROY:

                     PostQuitMessage(0);

                     return 0;

           }

 

           return(DefWindowProc(hWnd, iMessage, wParam, lParam));

}




*WinMain

 

int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpszCmdParam, int nCmdShow)

 

위의 WinMain은 프로그램의 시작점이다도스에서의 main과 같다
 
프로그램의 시작점이WinMain main이라는 함수를 만들어서 사용할 수도 있다
하지만 일반적으로 main이라는 함수는 사용하지 않는 것이 좋다. WinMain은 원형이 고정되어있다. 

APIENTRY 지정자는 윈도우즈 표준 호출 규약인 __stdcall을 사용한다는 뜻 

콜백함수이다.

 
다음은 WinMain 인수에 대한 설명이다.

 

hInstance         프로그램의 인스턴스 핸들

hPrevInstance   바로 앞에 실행된 현재 프로그램의 인스턴스 핸들없을 경우 NULL, 이제 거의 사용하지 않는다.

lpszCmdParam  명령 행으로 입력된 프로그램 인수도스의 argv인수에 해당

nCmdShow       프로그램이 처음 실행 되었을 때 윈도우 창의 형태최소보통 등

 

위 설명 중 인스턴스(Instance)라는 용어는 실행중인 프로그램 하나를 칭하는 용어이다
예를 들어 Windows Internet Explorer을 두 개 실행 할 때 운영체제는 이 프로그램의 인스터스를 이용하여 각각의 독립적인 프로그램으로 인식한다윈도우에서 사용하는 프로그램은 고유한 인스턴스 번호를 가지고 있다
.

 

WinMain 함수에서 하는 가장 중요한 일은 메인 윈도우를 만드는 일이다윈도우가 존재해야 입출력이 가능하기 때문이다윈도우를 만들기 위해서는 먼저 윈도우 클래스를 등록한 후CreateWindow 함수를 호출해야 한다윈도우 클래스(WNDCLASS)는 윈도우의 여러 가지 특성을 정의하는 구조체이다구조체의 멤버는 10개가 존재하면 역할을 아래와 같다.



*윈도우 클래스(WNDCLASS)와 등록


윈도우 클래스는 만들어질 윈도우의 여러 가지 특성을 정의하는 구조체이며 모든 윈도우는 윈도우 클래스의 정보를 기반으로 만들어진다.

 

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

윈도우의 스타일을 정의한다윈도우의 형태를 지정하는 곳이다만은 멤버를 가지며, OR( | )연산자로 연결하여 사용한다.

 

lpfnWndProc

위도우의 메시지 처리 함수를 지정한다메시지가 발생할 때마다 이 멤버가 지정하는 함수가 호출되며 이 함수가 모든 메시지를 처리한다.

 

cbClsExtra, cbWndExtra

일종의 예약 영역이다윈도우가 내부적으로 사용하며 아주 특수한 목적에 사용되는 여분의 공간이다.

 

hInstance

이 윈도우 클래스를 등록하는 프로그램의 번호이다. WinMain의 인수로 전달된 hInstance 값을 그대로 대입하면 된다.

 

hIcon, hCursor

생성된 윈도우가 사용할 마우스 커서와 아이콘의 모양을 지정한다.

 

hbrBackground

윈도우 배경색을 색칠할 붓을 지정한다가장 일반적으로 흰색 붓(WHITE_BRUSH)를 사용한다.

 

lpszMenuName

생성할 윈도우가 사용할 메뉴를 지정한다예를 들어 Explorer에서 도구나 페이지 같은 것이다.

 

lpszClassName

윈도우 클래스 이름을 정의한다단순히 이름이므로 한글이나 공백을 포함할 수 있다일반적으로 실행 파일의 이름과 일치시켜 사용한다.

 

*윈도우 특성 등록

 

ATOM RegisterClass(CONST WNDCLASS* lpWndClass)

 

위 함수는 윈도우 클래스(WNDCLASS) 구조체의 번지를 전달받아 앞으로 전달한 특성을 가진 윈도우를 사용하겠다고 운영체제에게 알리는 역할을 한다.


*윈도우 생성(CreateWindow)

 

RegisterClass를 이용하여 윈도우 클래스를 등록한 후에는 윈도우 클래스 특성을 기본으로 해서 윈도우를 생성해야 한다윈도우를 생성할 때에는 CreateWindow함수를 사용한다.

 

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

 

lpszClassName

생성하고자 하는 윈도우의 클래스를 지정하는 문자열이다앞서 설명했듯이 CreateWindow함수는 윈도우를 생성할 때 윈도우 클래스(WNDCLASS)에 정의된 속성대로 윈도우를 생성한다.

 

lpszWindowName

윈도우의 타이틀 바에 나타날 문자열이다지금 이 포스트를 보고 있는 Explorer의 타이틀 바는 엉뚱하고 기발하게……”일 것이다이러한 타이틀 바에 글을 정의할 수 있다.

 

dwStyle

만들고자 하는 윈도우의 형태를 지정하는 인수이다예를 들어생성하는 윈도우의 크기를 조절 가능하도록 할 것인가타이틀 바를 가질 것인가또는 스크롤 바의 유무 등을 설정한다앞서 윈도우 클래스의 Style을 설정하듯이 OR( | )연산자를 여러 개의 속성을 지정할 수 있다.

 

X, Y, nWidth, nHeight

생성할 윈도우의 크기와 위치를 지정한다앞의 두 인수는 생성될 윈도우의 위치이고 뒤에 두 인수는 윈도우의 크기이다단위는 픽셀이다.

 

hWndParent

부모 윈도우가 있을 경우 보모 윈도우의 핸들을 지정한다예를 들어 팝업창과 같은 현재 윈도우에서 새로운 윈도윈도 생성할 때 이전 윈도우가 부모 윈도우가 된다이때 부모 윈도우의 핸들을 지정한다부모가 없는 경우에는 NULL을 지정하면 된다.

 

hmenu

윈도우에서 사용할 메뉴의 핸들을 지정한다앞서 윈도우 클래스(WNDCLASS)에도 메뉴를 지정하는 멤버가 존재했다윈도우 클래스에서 지정한 메뉴는 그 윈도우 클래스를 기반으로 하는 모든 윈도우에서 공통적으로 사용되는 반면 지금 이 인수로 지정되는 메뉴는 현재 생성되는 윈도우에서만 사용된다.

 

hinst

윈도우를 만드는 주체즉 프로그램의 핸들을 지정한다. WinMain의 인수로 전달된hInstance를 입력하면 된다.

 

lpvParam

CREATESTRUCT라는 구조체의 번지이며 여러 개의 윈도우를 만들 때 사용된다잘 사용하지 않는다.

 

CreateWindow 함수는 윈도우에 관한 모든 정보를 메모리에 만든 후 윈도우를 대표하는 번호인 윈도우 핸들을 리턴 한다넘겨지는 윈도우 핸들은 hWnd라는 변수에 저장되었다가 이 윈도우를 참조하는 모든 함수의 인수로 사용된다. CreateWindow 함수로 만든 윈도우는 현재 메모리상에만 존재한다메모리 상에 존재하는 윈도우를 화면에 보이게 하기 위해서는 아래와 같은 함수가 필요하다.


*윈도우 화면에 출력하기

 

BOOL ShowWindow(hWnd, nCmdShow);

 

이 함수는 앞서 설명한 것과 같이 CreateWindow를 이용하여 윈도우를 메모리상에 저장한 것을 이용하여 화면에 보여주는 역할을 한다.


*메시지 루프

 

윈도우는 메시지 구동 시스템(Message Driven System)이다무슨 말이냐 하면 도스와 같이 미리 정해진 명령들을 순차적으로 실행 하는 방법이 아닌 프로그램의 실행 순서가 명확하게 정해져 있지 않으며 Event에 따라 실행 순서가 달라진다여기서 Event란 사용자의 내부적인 동작을 말하는데 키보드를 누르거나 마우스의 이동 등이 이에 해당된다. Event가 곧 메시지로 볼 수 있는데 정확히 말하면 메시지는 Event에 의해 발생된 일체의 변화에 대한 정보이다메시지를 받은 프로그램은 메시지가 어떤 정보를 담고 있는가를 분석하여 무슨 동작을 할 것인가를 결정한다아래의 코드는 윈도우 프로그램에서 메시지를 처리하는 부분이다일반적으로WinMain 함수의 끝에 아래의 형식으로 존재한다.

 

while(GetMessage(&Message, NULL, 0, 0))

{

           TranslateMessage(&Message);

           DispatchMessage(&Message);

}

 

 

BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)

 

이 함수는 메시지 큐에서 메시지를 읽어 들인다여기서 메시지 큐는 Event가 임시로 저장되는 공간이라고 보면 된다읽어 들인 메시지는 첫 번째 인수(LPMSG)가 지정하는 MSG 구조체에 저장된다만약 읽어 들인 메시지가 프로그램을 종료하라는 WM_QUIT일 경우 외엔 항상TURE를 리턴한다나머지 3개의 인수는 잘 사용하지 않는다.

 

 

BOOL TranslateMessage(CONST MSG* lpMsg)

 

이 함수는 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 사용할 수 있도록 한다쉽게 말해 사용자가 키보드를 눌러 키보드의 눌림(WM_KEYDOWN) 메시지가 발생할 때 문자가 입력되었다는 메시지(WM_CHAR)를 만드는 역할을 한다, A를 누르면 A문자가 입력되었다는 메시지를 만든다.

 

 

LONG DispatchMessage(CONST MSG* lpmsg)

 

이 함수는 메시지 큐에서 꺼낸 메시지를 윈도우의 메시지 처리 함수(WndProc)로 전달하는 역할을 한다.

 

위 함수에서 공통적으로 MSG라는 구조체를 사용하는데 이 구조체는 메시지에 대한 정보를 정의한다. MSG의 구조는 아래와 같다.

 

typedef struct tagMSG

{

           HWND             hwnd;

           UINT               message;

           WPARAM         wParam;

           LPARAM                     lParam;

           DWORD                     time;

           POINT             pt;

} MSG;

 

 

hwnd               메시지를 받을 윈도우 핸들

message           어떤 종류의 메시지인가를 나타낸다.

wParam           전달된 메시지에 대한 부가적인 정보

lParam             전달된 메시지에 대한 부가적인 정보

time                메시지가 발생한 시간

pt                   메시지가 발생했을 때 마우스의 위치



 *윈도우 프로시저

 

윈도우 프로시저(Window Procedure)란 메시지를 처리하는 함수로 메시지가 발생할 때 발생한 메시지에 대한 반응을 처리하는 일을 한다앞서 배우 포스트의 메시지 루프에서는 단순히 메시지를 메시지 처리함수 즉윈도우 프로시저로 보내는 역할을 할 뿐 메시지에 대한 처리는 하지 윈도우 프로시저가 한다이렇게 운영체제에 의해 호출되는 응용 프로그램 내의 함수를 콜백(CallBack) 함수라고 한다.

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

 

위 함수는 윈도우 프로시저 함수로 총 4개의 인수를 가진다이때 이 4개의 인수의 기능은 이전 포스트에서 배운 MSG구조체의 앞의 4개의 인수의 기능과 동일하다위 함수에서“WndProc”은 사용자가 임의로 지정할 수 있는 함수의 이름이다. ( 하지만 그냥 기본적으로 사용하는것이 일반적이다. )

 

윈도우 프로시저의 구조는 대체로 아래와 같다.

 

switch( iMessage)

{

           case Msg1:

                     처리1;

                      return 0;

           case Msg2:

                     처리2;

                      return 0;

           case Msg3:

                     처리3;

                      return 0;

           default:

                     return DefWindowProc(hWnd, iMessage, wParam, lParam);

}

 

윈도우 프로시저는 위와 같은 분기 구조로 메시지에 해당하는 분기를 찾아가 처리를 하는 방식이다.  이때 무사히 모든 처리를 완료 했다면 0을 리턴 하도록 약속되어 있다

마지막의DefeWindowProc 함수는 윈도우 프로시저에서 처리하지 않는 나머지 메시지에 관한 처리를 대신 해준다한 예로윈도우의 이동이나 크기의 변경 등을 처리해 준다.

 

 

지금까지 포스트에서 다룬 내용은 Windows API를 이용하여 간단한 윈도우 생성이었다앞으로 다룰 포스트는 Windows API함수를 이용하여 윈도우를 조작하거나그림을 그리는 것 등에 관해서 다룰 것이다.

참고 : www.winapi.co.kr



추가한 내용
winapi 프로젝트를 만들땐 콘솔이 아닌 윈도우환경으로 만들어야한다. 
=> 프로젝트 설정이 다를 경우 main을 못찾는다고 에러난다.

LIBCMT.lib(crt0.obj) : error LNK2001: unresolved external symbol _main

유니코드와 멀티바이트등을 신경써주어야 한다. ( 유니코드 디폴트 설정 )
또한 많은 여러 라이브러리가 존재하므로 프로젝트 설정도 신경 써주어야한다. 
 

 

윈도우 프로시저(Window Procedure)란 메시지를 처리하는 함수로 메시지가 발생할 때 발생한 메시지에 대한 반응을 처리하는 일을 한다앞서 배우 포스트의 메시지 루프에서는 단순히 메시지를 메시지 처리함수 즉윈도우 프로시저로 보내는 역할을 할 뿐 메시지에 대한 처리는 하지 윈도우 프로시저가 한다이렇게 운영체제에 의해 호출되는 응용 프로그램 내의 함수를 콜백(CallBack) 함수라고 한다.

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

 

위 함수는 윈도우 프로시저 함수로 총 4개의 인수를 가진다이때 이 4개의 인수의 기능은 이전 포스트에서 배운 MSG구조체의 앞의 4개의 인수의 기능과 동일하다위 함수에서“WndProc”은 사용자가 임의로 지정할 수 있는 함수의 이름이다.

 

윈도우 프로시저의 구조는 대체로 아래와 같다.

 

switch( iMessage)

{

           case Msg1:

                     처리1;

                      return 0;

           case Msg2:

                     처리2;

                      return 0;

           case Msg3:

                     처리3;

                      return 0;

           default:

                     return DefWindowProc(hWnd, iMessage, wParam, lParam);

}

 

윈도우 프로시저는 위와 같은 분기 구조로 메시지에 해당하는 분기를 찾아가 처리를 하는 방식이다.  이때 무사히 모든 처리를 완료 했다면 0을 리턴 하도록 약속되어 있다마지막의DefeWindowProc 함수는 윈도우 프로시저에서 처리하지 않는 나머지 메시지에 관한 처리를 대신 해준다한 예로윈도우의 이동이나 크기의 변경 등을 처리해 준다.

 

 

지금까지 포스트에서 다룬 내용은 Windows API를 이용하여 간단한 윈도우 생성이었다앞으로 다룰 포스트는 Windows API함수를 이용하여 윈도우를 조작하거나그림을 그리는 것 등에 관해서 다룰 것이다.

[출처]
 Windows 창 만들기 - 1. 기본코드|작성자 싸마

이 글을 공유하기

댓글

Designed by JB FACTORY