Windows_/Windows32_API

WinMain() , WNDCLASS 기본 윈도우 프로젝트

sosal 2014. 7. 25. 23:16
반응형

/*

 * http://sosal.kr/

 * made by so_Sal

 */



여기서 다룰 내용
int WinMain()
struct WNDCLASS
ShowWindow();
UpdateWindow();
GetMessage();
TranslateMessage();
DispatchMessage();

struct MSG



int
WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nShowCmd);

WinMain 함수는 윈도우 기반 응용 프로그램을 위한 초기 진입점으로서 커널에 의해서 호출됩니다.


HINSTANCE hInstance
현재 윈도우 응용 프로그램의 Instance(메모리) 핸들
윈도우 95 이전에는 프로세스마다 메모리가 독립적이지 못해
WinMain()의 파라미터로, 윈도우의 Instance(메모리)의 첫 주소를 넣어줬다.
윈도우 9x버전 이후로는 의미가 없어졌고, Win16 프로그램의 호환성을 위해 존재한다.

HINSTANCE hPrevInstance
이전 윈도우 응용 프로그램의 Instance 핸들입니다.
32bit에서 위 변수는 항상 NULL값을 가집니다. 그런데 이 변수가 왜 필요할까요?
이전 16bit 운영체제에선 가용 메모리의 한계가 2^16 (16M)이었습니다.
따라서 메모리 절약은 프로그램에 있어서 필수적이었고, 메모리를 절약하기 위해
실행하려는 윈도우 인스턴스가 만약 실행되고 있다면,
hPrevInstance는 이미 실행중인 윈도우의 Instance 핸들을 나타내며,
아래와 같이 윈도우 클레스를 공유하여 메모리를 절약하는 방법을 썼습니다.

if( !hPrevInstance )
{
   wndclass.cbStyle = CS_HREDRAW | CS_VREDRAW;
      // 다른 윈도우클래스 초기화가 이어짐
   RegisterClass(&wndclass);
}
물론 32bit에서는 hPrevInstance는 항상 NULL값을 가지며,
위 코드가 있어도 상관없지만, 사실 필요는 없습니다.

LPSTR lpCmdLine
쉘, 또는 응용프로그램에 의해 입력된 argv와 같은 인자입니다.
프로그램 이름은 넘어오지 않으며, argv[1], argv[2]와 같이 따로 나뉘어 들어오지 않습니다.
전체 명령줄을 얻기 위해 GetCommandLine() 함수를 사용합니다.

int nShowCmd
윈도우 상태 옵션을 나타냅니다.
|로 연결하여 아래 옵션을 여러개 사용할 수 있습니다.
   SW_HIDE                           // 숨긴다
   SW_SHOWNORMAL            // Normal 크기로 활성화
   SW_SHOWMINIMIZED         // 최소화 크기로 활성화
   SW_SHOWMAXIMIZED        // 최대화 크기로 활성화
   SW_SHOWNOACTIVATE      // 최근의 위치와 크기로 활성화
   SW_SHOW                         // 조건 없이 활성화
   SW_MINIMIZE                    // 최소화 상태로 활성화
   SW_MAXIMIZE                   // 최대화 상태로 활성화
   SW_SHOWDEFAULT           // 초기에 윈도우 생성시의 Flag값에 따라 결정
   SW_SHOWMINNOACTIVE    // 최소화 상태로 표시, 이미 활성화되어 있다면 내버려둔다
   SW_SHOWNA                     // 현상태 유지
  

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

UINT style :: 출처 :: msdn.microsoft.com

StyleAction
CS_BYTEALIGNCLIENTAligns the window's client area on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.
CS_BYTEALIGNWINDOWAligns the window on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.
CS_CLASSDCAllocates one device context to be shared by all windows in the class. Because window classes are process specific, it is possible for multiple threads of an application to create a window of the same class. It is also possible for the threads to attempt to use the device context simultaneously. When this happens, the system allows only one thread to successfully finish its drawing operation.
CS_DBLCLKSSends a double-click message to the window procedure when the user double-clicks the mouse while the cursor is within a window belonging to the class.
CS_DROPSHADOWWindows XP: Enables the drop shadow effect on a window. The effect is turned on and off through SPI_SETDROPSHADOW. Typically, this is enabled for small, short-lived windows such as menus to emphasize their Z order relationship to other windows.
CS_GLOBALCLASSSpecifies that the window class is an application global class. For more information, see Application Global Classes.
CS_HREDRAWRedraws the entire window if a movement or size adjustment changes the width of the client area.
CS_NOCLOSEDisables Close on the window menu.
CS_OWNDCAllocates a unique device context for each window in the class.
CS_PARENTDCSets the clipping rectangle of the child window to that of the parent window so that the child can draw on the parent. A window with the CS_PARENTDC style bit receives a regular device context from the system's cache of device contexts. It does not give the child the parent's device context or device context settings. Specifying CS_PARENTDC enhances an application's performance.
CS_SAVEBITSSaves, as a bitmap, the portion of the screen image obscured by a window of this class. When the window is removed, the system uses the saved bitmap to restore the screen image, including other windows that were obscured. Therefore, the system does not send WM_PAINT messages to windows that were obscured if the memory used by the bitmap has not been discarded and if other screen actions have not invalidated the stored image.

This style is useful for small windows (for example, menus or dialog boxes) that are displayed briefly and then removed before other screen activity takes place. This style increases the time required to display the window, because the system must first allocate memory to store the bitmap.

CS_VREDRAWRedraws the entire window if a movement or size adjustment changes the height of the client area.



lpfnWndProc :: 윈도우로 메시지가 왔을 때, 메시지를 처리할 함수의 이름이 들어갑니다.

cbClsExtra   :: 윈도우 클레스를 운영체제에 등록할때 추가로 사용할 예약 메모리 지정 (단위 byte)
cbWndExtra  :: 개별 윈도우가 만들어질 때 메모리를 개별적으로 추가 할당받음
     cb~Extra 인자는 윈도우즈가 내부적으로 특수한 목적에 사용되는 예약 공간입니다.
     사용하지 않을경우 0 으로 지정하면 됩니다.

hInstance     :: 윈도우 클레스를 사용하는 Instance(메모리) 핸들의 값으로,
                      WinMain 인자의 hInstance값을 넣어줍니다.
                      
HICON hIcon :: 최소화 되었을 경우 출력될 아이콘 LoadIcon() 함수를 이용하여 지정합니다.
HCURSOR hCursor :: 윈도우가 사용할 마우스 커서를 LoadCursor() 함수를 이용하여 지정합니다.

hbrBackground :: 윈도우의 배경 색상을 채색할 브러시를 지정하는 인자입니다.
                         GetStockObject() 함수를 사용하여 가져오며, 꼭 (HBRUSH)로 형변환 해줍니다.
                         WHITE_BRUSH가 가장 많이 사용됩니다.

lpszMenuName :: 이 프로그램이 사용할 메뉴바를 지정합니다.
                          메뉴바, 스크롤바 등은 윈도우에서 제공하는 리소스 객체로
                          프로그래머가 코드로 만드는것이 아닙니다.

lpszClassName :: 윈도우 클레스의 이름을 지정합니다. 이름은 CreateWindow() 함수에 전달되어
                           윈도우 클레스에서 정의한 특성값을  참조하여 윈도우를 생성합니다.





BOOL ShowWindow(HWND hWnd, int nCmdShow) //hWnd 윈도우를 보여줍니다.

HWND hWnd :: 대상 윈도우 핸들로, CreateWindow 함수가 리턴한 핸들값을 보통 넣습니다.

nCmdShow  :: 대상 윈도우의 show 상태를 지정합니다.
   SW_HIDE                           // 숨긴다
   SW_SHOWNORMAL            // Normal 크기로 활성화
   SW_SHOWMINIMIZED         // 최소화 크기로 활성화
   SW_SHOWMAXIMIZED        // 최대화 크기로 활성화
   SW_SHOWNOACTIVATE     // 최근의 위치와 크기로 활성화
   SW_SHOW                         // 조건 없이 활성화
   SW_MINIMIZE                    // 최소화 상태로 활성화
   SW_MAXIMIZE                   // 최대화 상태로 활성화
   SW_SHOWDEFAULT           // 초기에 윈도우 생성시의 Flag값에 따라 결정
   SW_SHOWMINNOACTIVE    // 최소화 상태로 표시, 이미 활성화되어 있다면 내버려둔다
   SW_SHOWNA                     // 현상태 유지

BOOL UpdateWindow(HWND hWnd)
HWND hWnd :: 대상 윈도우 핸들로, 새로 갱신하고자 하는 변수가 들어갑니다.




GetMessage(),TranslateMessage(),DispatchMessage();
윈도우즈의 가장 큰 특징은 메시지 구동 시스템 입니다.
C언어처럼 프로그래머에 의해 입력된 일련의 명령들을 순차적으로 진행하지 않고,
어떤 메시지, 이벤트가 발생했는가에 따라 프로그램의 실행되어집니다.
순서에 따르지 않고, 발생한 메시지에 대한 반응을 정의하는 방식으로 프로그래밍 합니다.
일반적인 윈도우는 WinMain() 함수 끝에 메세지 루프를 생성합니다.

메시지 루프는
while(Getmessage(&Msg,0,0,0){
   TranslateMessage(&Msg);
   DispatchMessage(&Msg);
}
위와 같이 3개의 함수들로 이루어져 있으며, While() 무한루프 구조입니다.


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

LPMSG lpMsg :: 메시지 큐로부터 메시지를 받아들여 저장하는 변수
HWND hWnd :: 메시지를 받을 윈도우 핸들
UINT wMsgFilterMin ~ Max :: 읽어들일 메시지의 범위를 지정, 0을 넣으면 범위를 지정하지 않음

BOOL TranslateMessage(CONST MSG *lpMsg);
키보드로부터 발생한 이벤트를 메세지화 하는 함수입니다.
"A버튼 발생"을 문자 'A'로 바꿔주는 함수라고 생각할 수 있습니다.

LONG DispatchMessage(CONST MSG *lpMsg);
윈도우의 메시지 처리함수 WndProc으로 메시지를 전달하는 함수입니다.

3개 함수를 이용해 생성하는 루프는 다음과 같이 묶을 수 있습니다.
GetMessage :: 메시지 큐로부터 메시지를 받아들여서
TranslateMessage :: 프로그램이 원하는 형태로 메시지를 바꾼 후
DispatchMessage :: 메시지 처리 함수로 보낸다!

메시지 루프에서 쓰이는 함수들은 모두 MSG라는 구조체를 매개변수로 사용합니다.

typedef struct tagMSG
{
   HWND hwnd;           // 메시지를 받을 윈도우 핸들
   UINT message;       // 메시지의 종류를 나타내는 값.
   WPARAM wParam;  // 전달된 메시지의 부가적인 정보
   LPARAM lpParam;   // 전달된 메시지의 부가적인 정보
   DWORD time;          // 메시지가 발생한 시간
   POINT pt;               // 메시지가 발생했을 때의 마우스의 위치
} MSG;

UINT message          // 자주 쓰이는 메시지 종류 값
   WM_QUIT                 :: 프로그램을 끝낼 때 발생하는 메시지
   WM_LBUTTONDOWN :: 마우스 좌측 버튼 클릭 발생 메시지
   WM_RBUTTONDOWN :: 마우스 우측 버튼 클릭 발생 메시지
   WM_CHAR                :: 키보드로부터 문자가 입력될 때 발생하는 메시지
   WM_PAINT               :: 화면을 다시 그려야 할 필요가 있을때 발생
   WM_DESTORY          :: 윈도우가 메모리에서 파괴될 떄 발생
   WM_CREATE            :: 윈도우가 처음 만들어질 때 발생


메시지 루프가 종료되면 프로그램은 Message.wParam을 리턴하는데,
이 값은 WM_QUIT으로부터 전달받은 exit code 입니다.

윈도우 api에 관련한 책이라면 항상 등장하는 Hello World 소스입니다.


#include<windows.h>
#include<tchar.h>

LRESULT FAR PASCAL WndProc(HWND, UINT, UINT, LONG);
//메세지 처리함수 선언

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
       LPSTR lpCmdLine,int nCmdShow)
{
     static TCHAR szAppName[] = _T("Hello Win");
     MSG msg;
     HWND hwnd;
     WNDCLASS
wndclass;

     if(!hPrevInstance)
     {
          wndclass.style = CS_HREDRAW | CS_VREDRAW;
                                 // 가로 세로 크기변화가 있을 때, 자신의 영역을 다시 칠한다.
          wndclass.lpfnWndProc = WndProc; //메시지 처리 구동 함수
          wndclass.cbClsExtra = 0;
          wndclass.cbWndExtra = 0;
          wndclass.hInstance = hInstance;
          wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
          wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
          wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
          wndclass.lpszMenuName = szAppName;
          wndclass.lpszClassName = szAppName;

          RegisterClass(&wndclass);
     }
     hwnd = CreateWindow(szAppName, _T("~ Hello World ~"),
         WS_OVERLAPPEDWINDOW,
         CW_USEDEFAULT, CW_USEDEFAULT,
         CW_USEDEFAULT, CW_USEDEFAULT,
         NULL,NULL,hInstance, NULL);

     ShowWindow(hwnd, nCmdShow);
     UpdateWindow(hwnd);

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


     return msg.wParam;
}

LRESULT FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam){
     HDC hdc;
     PAINTSTRUCT ps;
     RECT rect;

     switch(message){
          case
WM_PAINT:
               hdc = BeginPaint(hwnd, &ps);
               GetClientRect(hwnd, &rect);
               DrawText(hdc, _T("
Hello, Windows!"), -1, &rect,
                    DT_SINGLELINE | DT_CENTER | DT_VCENTER);
               EndPaint (hwnd, &ps);
               return 0;

          case WM_DESTROY:
               PostQuitMessage(0);
               return 0;
     }
 return DefWindowProc(hwnd, message, wParam, lParam);
}