4.29k likes | 5.39k Vues
Win32 API. 강사 : 이준근 (egenie@korea.com). 1. 윈도우 프로그래밍의 이해. Application. MFC. VB. ATL/COM. owl. Delphi. DirectX OPEN/GL. API. Windows Kernel. HAL. HardWare. 1. API 의 Positioning. 2. Windows 의 구성. 한 시점에 도는 함수가 여러 개다 .!!. Windows 의 특징
E N D
Win32 API 강사 : 이준근 (egenie@korea.com)
1. 윈도우 프로그래밍의 이해
Application MFC VB ATL/COM owl Delphi DirectX OPEN/GL API Windows Kernel HAL HardWare 1. API의 Positioning
2. Windows의 구성 한 시점에 도는 함수가 여러 개다.!! • Windows의 특징 • 32bit 선점형 멀티태스킹과 멀티스레딩을 지원하는 그래픽 운영체제이다. • 비선점형 : • 프로그램이 스스로 제어를 다른 프로그램에게 넘겨 주어야 한다. • GUI환경이다. • “GUI는 개인용 컴퓨터 산업의 가장 중요하고 유일한 ‘대중적 합의’라는 점은 이제 명백해 졌다.” - Charles Simonyi • GUI의 특징 • 1. 더 이상 컴퓨터나 새로운 프로그램의 사용법을 배우는데 많은 시간을 소비하지 않아도 된다. • 2. 일관된 사용자 인터페이스를 이용한다는 것은 메뉴와 대화상자를 구성할 때 Windows에 내장된 루틴을 이용한다는 것을 의미한다. • ‘동적 연결’이라는 개념을 중심으로 동작한다. • Windows에서 실행되는 프로그램은 ‘동적 연결 라이브러리’라고 하는 파일에 존재하는 루틴을 공유한다. 타임 슬라이싱 기법!! A B A B A 2G 운영체제 Stack(1M) 코드영역(200k) 전역공간(1K) Heap 동적 연결 C => .obj + .Lib + .dll => Exe + .dll
2. Windows의 구성 • 프로그램은 시스템에 연결되어 있는 장치의 종류를 몰라도 된다. • 화면 및 프린터와 같은 그래픽 디스플레이 장치의 하드웨어를 직접 사용하지 않는다.
3. 첫 번째 API프로그램 #include <windows.h> int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance, PSTR szCmdLine, int CmdShow) { MessageBox (NULL, "Hello, Windows 98!","HelloMsg", MB_OK) ; return 0 ; } • #include <windows.h> • 다른 Windows헤더 파일을 포함하는 마스터 include 파일이다. • WINDEF.H 기본형식 정의 • WINNT.H 유니코드지원을 위한 형식 정의 • WINBASE.H Kernel함수 • WINUSER.H 사용자 인터페이스 함수 • WINGDI.H 그래픽 장치 인터페이스 함수
4. 프로그램 진입점 int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance, PSTR szCmdLine, int CmdShow) • WINAPI windef.h에 정의되어 있다. • #define WINAPI __stdcall • Parameters • HINSTANCE hInstance : • 프로그램의 인스턴스 핸들 • HINSTANCE hPrevInstance : • 항상 NULL이다. • PSTR szCmdLine : • 프로그램을 실행할 때 사용된 명령줄 • int iCmdShow : • 최대화할 것인지 또는 아이콘화 하여 작업 표시줄에 표시할 것인지 지정 __stdcall은 함수를 호출하면 호출된 함수쪽에서 리턴하기 전에 스텍에 저장된 인자들을 정리하는 방식으로 16비트시절의 PASCAL호출규약과 동일하다.
4. 프로그램 진입점 • MessageBox : • 메시지 박스를 나타내는 함수
4. 사고의 전환을 위하여 • 도스 프로그래밍과 윈도우 프로그래밍의 차이점 • 도스 프로그램 : 절차적 (또는 순차적) • 프로그램의 실행 흐름이 프로그래머가 기술한 코드의 순서에 따라 진행한다. • 사용자의 키보드 조작이나 마우스의 움직임을 프로그래머가 일일이 알아서 직접 제어해야 한다. • 외부에서 무슨 일(이벤트)이 일어났는지 프로그래머가 알아내야 하고이에 따른 처리까지 맡아서 해야 한다. • 윈도우 프로그램 : • 이벤트 구동(Event-Driven)방식 또는 메시지 처리 방식 • 프로그램의 실행 흐름을 윈도우 시스템과 일을 분담하여 처리한다. • 외부에서 일어나는 일을 윈도우 시스템이 감지하여 해당 프로그램에 메시지를 전달하여 알려준다. • 프로그램은 이에 대한 처리만 한다. • 프로그래밍이 한결 수월해 진다. • Ex) Spy++ Test
5. 윈도우 프로그래밍과 친해지자 이벤트(Event)와 메시지(Message) 메시지 루프(Message Loop) 메시지 큐 (Queue) 핸들(Handle) 윈도우 프로시져 리소스(Resource) 인스턴스(Instance) 하드웨어 운용 방식
5. 윈도우 프로그래밍과 친해지자 • 이벤트(Event)와 메시지(Message) • 사용자가 키보드의 특정 키를 누르거나 마우스의 좌측 버튼을 클릭하는 등의 일을 할 때 이벤트가 발생한다. • 이벤트가 발생하면 윈도우 OS는 이름 감지하여 해당 프로그램으로 메시지를 전달한다. • 메시지에는 마우스의 좌측 버튼을 눌렀을 때 커서의 위치등과 같은 부가 정보가 함께 포함되어 있다. • WinUser.h [마우스에 관련된 Message들] #define WM_MOUSEMOVE 0x0200 #define WM_LBUTTONDOWN 0x0201 #define WM_LBUTTONUP 0x0202 #define WM_LBUTTONDBLCLK 0x0203 #define WM_RBUTTONDOWN 0x0204 #define WM_RBUTTONUP 0x0205 ( Winuser.h)
5. 윈도우 프로그래밍과 친해지자 typedef struct tagMSG { HWND hwnd; // 메시지를 받을 윈도우의 핸들 UINT message; //전달되는 메시지 유형 WPARAM wParam; //메시지와 관련된 부가적인 정보 LPARAM lParam; //메시지와 관련된 부가적인 정보 DWORD time; // 메시지가 전달된 시간 POINT pt; //메시지가 큐에 저장될 때의 마우스 위치 } MSG; 윈도우 번호를 나타냄!! typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; }MSG; WM_LBUTTONDOWN Key Flag 32비트 LOWORD(lParam) X좌표(16비트) Y좌표(16비트) HIWORD(lParam)
5. 윈도우 프로그래밍과 친해지자 • 메시지 큐(Message Queue) • 사용자의 컴퓨터 조작에 의해 발생한 이벤트는 메시지형태로 만들어져 윈도우 OS가 관리하는 “메시지 큐”에 저장된다. • 윈도우 시스템 전체를 관리하기 위한 [시스템 메시지 큐]와 응용 프로그램마다 별도 갖고 있는 [프로그램 메시지 큐]가 있다. 자료구조를 저장하고 이를 처리 System Message Queue program Message Queue
5. 윈도우 프로그래밍과 친해지자 시스템 메시지 큐 윈도우 OS 시스템 분배기 Dispatch Thread (RIT:Raw Input Thread) 프로그램 메시지 큐 프로그램 메시지 큐 프로그램 A 프로그램 B
5. 윈도우 프로그래밍과 친해지자 • 메시지 루프 • OS로부터 전달된 메시지를 보관하는 큐에 어떤 메시지가 들어왔는지를 지속적으로 감시하고 분석해주는 부분이 필요하다. While( GetMessage( &msg,NULL,0,0) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } 값을 바꾸기 위해 Message 구조체의 주소를 보냄 wm_quit message x 를 누르면은 GetMessage의 리턴값이 0이 된다!!
5. 윈도우 프로그래밍과 친해지자 • 윈도우 프로시저(Window procedure) • 자신이 만든 함수이지만 자신이 직접 호출하지 않고 운영체제에서 호출하는 함수를 콜백함수라고 한다. • 함수 앞에 CALLBACK으로 선언 • 윈도우 프로시저는 콜백함수이다. • 모든 윈도우는 해당 윈도우 프로시저를 갖고 있다. • 메시지 루프에서 해석한 메시지를 구체적으로 처리하는 기능을 수행 • Call Back 함수는 윈도우에서 자동으로 불려지는 함수이다.그러므로 Language independent 해야 한다. • (호출형식을 통일해야 한다) • windef.h 윈도우의 특징을 규정 짓는다! LRESULT CALLBACK WndProc( HWND hWnd, UNIT uMgs, WPARAM wParam,LPARAM lParam); #define CALLBACK __stdcall #define WINAPI __stdcall WinMain에서 Message를 얻어와서 WndProc를 실행해준다!!
5. 윈도우 프로그래밍과 친해지자 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (iMsg) { case WM_CREATE : PlaySound ("hellowin.wav", NULL, SND_FILENAME | SND_ASYNC) ; return 0 ; case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, "Hello, Windows 95!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; }
5. 윈도우 프로그래밍과 친해지자 • 핸들 (Handle) • 핸들은 프로그램에서 현재 사용중인 객체들을 식별하기 위해 윈도우 OS가 부여하는 고유 번호이다. • 그러면 왜 포인터를 이용하지 않고 핸들을 이용할까? Ex) HWND 윈도우에 대한 핸들 HCURSOR 커서에 대한 핸들 HICON 아이콘에 대한 핸들 HMENU 메뉴에 대한 핸들 총 메모리가 80KB라고 가정하자. 이때 30KB의 그림판, 40KB를 차지 하는 Visual C++을 실행시키면 OS자체에서 조각모음을 하므로 핸들을 사용하는 것이 효율적임! 메모리의 주소만 바뀌고 핸들은 바뀌지 않음 그림판 (30KB) 비주얼 C++ (40KB) 여유공간 (10KB) 그림판을 종료하고 20KB를 필요로 하는 메모장을 실행시키면 메모장 (20KB) 여유공간 (10KB) 비주얼 C++ (40KB) 여유공간 (10KB)
5. 윈도우 프로그래밍과 친해지자 => 내부적으로 윈도우는 메모리 블록을 이리저리 이동시켜 필요 공간을 확보한다. (윈도우OS의 메모리 관리 기법) Ex) HGLOBAL GlobalAlloc( UINT uFlags, // allocation attributes DWORD dwBytes // number of bytes to allocate); GMEM_FIXED Allocates fixed memory. The return value is a pointer. GMEM_MOVEABLE Allocates movable memory. • 메모리 블록이 이리저리 이동되는 상황에서 도스에서처럼 포인터를 직접 활용한다면 OS가 할당된 메모리 블록을 함부로 이동시킬 수 없게 되고, 이동시킨다고 해도 프로그램쪽에서 이동되는 상황을 알 수 없기 때문에 엉뚱한 메모리 주소를 참조하게 될 것이다.
5. 윈도우 프로그래밍과 친해지자 • 인스턴스 • 프로그램은 명령들이 나열된 코드 영역(Code Segment)과 데이터를 보관하는 데이터 영역(Data Segment)으로 구분 • 동일한 프로그램에 코드 영역까지 별도의 메모리를 할당하면 메모리만 낭비하게 된다. • 실제 메모리 상에 할당된 객체를 인스턴스(Instance)라 한다. • 코드 영역에 대한 모듈 인스턴스(Module Instance) • 데이터 영역에 대한 데이터 인스턴스(Data Instance)두 개의 인스턴스가 있다. 코드영역 Read Only 코드 영역 공유 -> 메모리 아끼기 위해 코드영역 (모듈 인스턴스) 메모장1 메모장2 데이터 영역_1 (데이터 인스턴스) 데이터 영역_2 (데이터 인스턴스)
5. 윈도우 프로그래밍과 친해지자 메모리 관리상에서 콘솔과 차이가 확실한 차이 이때문에 리소스가 이를 관리한다. • 리소스(Resource) • 메뉴,아이콘,커서,비트맵 등 사용자 인터페이스를 구성하는 자원들의 정적 데이터를 말한다. • 프로그램 실행 중 변경되지 않는 정형화된 데이터로 C나 C++같은 언어로 기술하지 않고 리소스 스크립트에 의해 정의된다. 사용자가 필요하면 메모리에 남아 있고 필요 없으면 메모리에서 내려간다. IDR_MAINFRAME MENU PRELOAD DISCARDABLE BEGIN POPUP "파일(&F)" BEGIN MENUITEM "새 파일(&N)\tCtrl+N", ID_FILE_NEW MENUITEM "열기(&O)...\tCtrl+O", ID_FILE_OPEN MENUITEM "저장(&S)\tCtrl+S", ID_FILE_SAVE MENUITEM "다른 이름으로 저장(&A)...", ID_FILE_SAVE_AS MENUITEM SEPARATOR MENUITEM "인쇄(&P)...\tCtrl+P", ID_FILE_PRINT MENUITEM "인쇄 미리 보기(&V)", ID_FILE_PRINT_PREVIEW MENUITEM "인쇄 설정(&R)...", ID_FILE_PRINT_SETUP MENUITEM SEPARATOR MENUITEM "최근 파일", ID_FILE_MRU_FILE1,GRAYED MENUITEM SEPARATOR MENUITEM "종료(&X)", ID_APP_EXIT END END
5. 윈도우 프로그래밍과 친해지자 • 리소스는 프로그램 코드와 분리하여 작성되며 자체 컴파일과정을 갖는다. • 리소스 스크립트 파일(.RC)은 리소스 컴파일러(RC.EXE)에 의해 이진화된 리소스 파일 (.RES)이 만들어 진다. • 리소스를 별도로 정의하는 이유는 메모리를 효율적으로 사용하기 위함이다. • 리소스에는 정적인 데이터가 있기 때문에 일반 변수와는 다른 메모리 관리를 한다. • 보통 리소스 데이터는 필요한 시점에 파일로부터 로딩이 되며 여러 개의 프로그램이 실행되어 메모리가 부족시 리소스 데이터가 할당된 메모리 블록을 이동(Moveable)기키거나 폐기(Discardable)한다. 리소스가 따로 분리되어 나와 있다.
5. 윈도우 프로그래밍과 친해지자 GUI 아이콘,커서,다이얼로그등 중복/증가로 파일크기가 커진다. 리소스를 프로그램과 분리, 필요 시에 Call 링크 시 소스코드와 리소스가 결합 리소스는 메모리 부족 시 폐기 가능(DISCARDABLE) 필요 시EXE나 DLL파일로부터 로딩 프로그램이 차지하는 메모리가 감소되어 메모리 효율성이 높아지고 소스 코드와 분리되어 작성되므로 프로그램 작성이 편리하다.
5. 윈도우 프로그래밍과 친해지자 • 하드웨어 운용 방식(장치 독립적인 그래픽 인터페이스) • 도스에서는 비디오 메모리나 프린터 포트 등을 직접 제어함으로써 특정한 하드웨어 장치에 종속된 프로그램을 작성하였다. • 장치 종속적 • 비디오 카드나 프린터 등과 같은 장치의 종류나 모델에 따라 출력방법이 달라진다. • 특정 장치에서만 제한적으로 실행되기 때문에 프로그램에서 지원하지 않는 장치는 사용할 수 없다. • 프로그램에서 필요한 디바이스 드라이버를 제공해야 한다. • 장치 독립적 • 장치의 종류와 모델에 상관없이 일관된 처리 방법으로 하드웨어 장치들을 다룰 수 있다. • 출력하고자 하는 출력장치의 종류에 상관없이 출력 방법이 동일하다. • 필요한 디바이스 드라이버를 윈도우 OS가 내장하고 있으면 어떤 하드웨어 장치건 상관없이 동일하게 작동되기 때문에 프로그래머는 중요한 기능에 보다 많은 시간을 투자할 수 있다. • 출력 장치에 대한 정보를 포함하는 구조체 디바이스 컨텍스트를 가지고 GDI함수를 호출하여 출력 작업을 수행
5. 윈도우 프로그래밍과 친해지자 case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, "Hello, Windows 95!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; EndPaint (hwnd, &ps) ; return 0 ; Display.drv GDI32.DLL Printer.drv Keyboard.drv USER32.DLL 윈도우 프로그램 Mouse.drv Sound.drv Timer H/W System.drv Comm.drv RS-232 Ms-Dos file I/O KERNEL32.DLL Memory Management
2. Windows 와 메시지
1. 첫번째 API프로그램 #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; 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 = NULL ; • wndclass.lpszClassName = szAppName ; • if (!RegisterClass (&wndclass)) • { • MessageBox (NULL, TEXT ("This program requires Windows NT!"),szAppName, • MB_ICONERROR) ; • return 0 ; • }
hwnd = CreateWindow (szAppName, // window class name "The Hello Program", // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; }
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE: PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME |SND_ASYNC) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, "Hello, Windows 98!", -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) ; }
2. 첫 번째 API프로그램 분석 • 헝거리언 표기법 • MS사의 전설적인 프로그래머 Charles Simonyi를 기리는 뜻으로 붙여진 이름) • char szAddress[50]; 해당 변수의 데이터 타입을 나타내는 접두어 표기
2. 첫 번째 API프로그램 분석 • 접두어
2. 첫 번째 API프로그램 분석 • 새로운 데이터 형식들
2. 첫 번째 API프로그램 분석 • 새로운 데이터 형식들 • 윈도우 클래스 등록하기 • 윈도우는 항상 윈도우 클래스를 기반으로 하여 생성된다. • 모든 Button윈도우는 동일한 윈도우 클래스를 기반으로 하여 생성된다. • 윈도우 클래스는 윈도우의 특성들을 정의한다. • 응용 프로그램은 윈도우를 생성하기 전에 반드시 RegisterClass를 호출하여 윈도우 클래스를 등록해야 한다.
2. 첫 번째 API프로그램 분석 typedef struct { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS, * PWNDCLASS,NEAR * NPWNDCLASSA, FAR * LPWNDCLASSA; • wndclass.style=CS_HREDRAW|CS_VREDRAW; • 수평 또는 수직윈도우가 변경될 때마다 완전히 새로 클래스의 Brush로 다시 칠하게 된다. • winuser.h에 정의되어 있다.
2. 첫 번째 API프로그램 분석 /* Class styles */ #define CS_VREDRAW 0x0001 #define CS_HREDRAW 0x0002 #define CS_DBLCLKS 0x0008 #define CS_OWNDC 0x0020 #define CS_CLASSDC 0x0040 #define CS_PARENTDC 0x0080 #define CS_NOCLOSE 0x0200 #define CS_SAVEBITS 0x0800 #define CS_BYTEALIGNCLIENT 0x1000 #define CS_BYTEALIGNWINDOW 0x2000 #define CS_GLOBALCLASS 0x4000 #define CS_IME 0x00010000 • wndclass.lpfnWndProc = WndProc ; • 윈도우와 연결되는 윈도우 함수를 연결한다. • wndclass.cbClsExtra = 0; • wndclass.cbWndExtra = 0; • 윈도우 클래스에 여유공간을 두거나, 윈도우에 여유공간을 예약하는데 사용
2. 첫 번째 API프로그램 분석 • cbClsExtra • 윈도우 클래스에서 사용하고자 하는 여분의 메모리 양 • 바이트 수로 지정한다. • 운영체제는 윈도우 클래스를 등록할 때 이 멤버가 지정하는 만큼의 메모리를 추가로 할당해 준다 • SetClassLong, GetClassLong함수로 이 메모리를 사용한다. • cbWndExtra • 개별 윈도우에서 사용하고자 하는 여분의 메모리 양을 지정한다. • 운영체제는 개별 윈도우가 만들어질 때마다 이 멤버가 지정하는 만큼의 메모리를 추가로 할당해 준다. • GetWindowLong,SetWindowLong함수로 이 메모리를 사용한다.
2. 첫 번째 API프로그램 분석 • wndclass.hInstance = hInstance • 프로그램의 인스턴스 핸들 • wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION) • 이 윈도우 클래스를 기반으로 하여 생성된 모든 윈도우에 대한 아이콘을 설정한다. • 프로그램이 실행될 때 아이콘은 Windows작업 표시줄에 나타난다. • 프로그램에 있는 ICON을 지정하려면 NULL에 hInstance를 넣는다. • wndclass.hCursor = LoadCursor(NULL,IDI_APPLICATION) • 윈도우에서 사용하는 커서를 지정한다. • wndcalss.hbrBackground = GetStocObject(WHITE_BRUSH) ; • Window의 배경색을 지정한다. • Windows에는 여러 가지의 표준 혹은 ‘stock’브러쉬가 있다. • wndclass.hMenu = NULL; • 윈도우의 메뉴를 지정한다. • wndclass.lpszClassName=szAppName; • 클래스는 반드시 이름을 부여 받아야 한다. • RegisterClass를 호출하여 윈도우 클래스를 등록
2. 첫 번째 API프로그램 분석 if (!RegisterClass(&wndclass)) { MessageBox(NULL,TEXT(“This program requires Windows NT!”, szAppName,MB_ICONERROR); return 0; }
2. 첫 번째 API프로그램 분석 • 윈도우 생성하기 hwnd = CreateWindow ( szAppName, // window class name "The Hello Program", // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters • CreateWindow를 호출하여 윈도우 생성 • CreateWindow시에는 윈도우의 개별적인 특징을 지정한다. • 윈도우의 크기, 윈도우의 위치,…
2. 첫 번째 API프로그램 분석 • WS_OVERLAPPENDWINDOW • 제목표시줄,시스템메뉴,두꺼운 윈도우 크기 변경 경계, 제목표시줄의 최소화,최대화,닫기 단추 • (WINUSER.H에서 확인) #define WS_OVERLAPPEDWINDOW ( WS_OVERLAPPED | WS_CAPTION | \ WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | \ WS_MAXIMIZEBOX) • 부모 윈도우 핸들 • 부모 윈도우를 만드는 경우는 NULL • 자식 윈도우를 만드는 경우는 부모 윈도우의 핸들값 • 윈도우 메뉴 핸들 • 윈도우 클래스에서 지정한 메뉴를 사용하려면 NULL • 윈도우 클래스에서 지정한 메뉴를 사용하지 않으려면 메뉴의 핸들을 지정한다. • 프로그램 인스턴스 핸들 • WinMain의 매개변수로 프로그램에 전달되는 인스턴스의 핸들을 지정한다. • Return값 • 생성된 윈도우의 핸들
2. 첫 번째 API프로그램 분석 • CreateWindow()후에는 윈도우가 내부적으로 생성되어 있다. • 화면에는 보이지 않는 상태 • 화면에 출력하려면 • ShowWindow(hwnd,iCmdShow) • hwnd : CreateWindow()의 리턴 값. • iCmdShow : 초기에 화면에 윈도우가 어떻게 표시되는 지를 나타낸다. • 윈도우를 화면에 나타내며 지정된 브러쉬로 윈도우의 Client영역을 칠한다.
2. 첫 번째 API프로그램 분석 • 메시지 루프 • 메시지 루프는 세 개의 함수 호출로 이루어져 있으며 전체 루프는 while문으로 싸여져 있어 무한히 반복되는 구조를 가지고 있다. • 이벤트가 발생하면 Windows는 이벤트를 메시지로 변환하여 프로그램의 메시지 큐에 저장한다. • GetMessage( &msg,NULL,0,0) • 메시지 큐로부터 메시지를 읽어 온다. • 읽어들인 메시지는 첫 번째 인수가 지정하는 MSG 구조체에 저장된다. • WM_QUIT 메시지인 경우 0을 Return한다. 그 이외의 메시지이면 TRUE를 리턴한다. • 나머지 세 개의 인수는 읽어 들일 메시지의 범위를 지정한다. 잘 사용하지 않는다.
2. 첫 번째 API프로그램 분석 while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } typedef struct tagMSG { HWND hwnd; UINT message;//어떤 종류의 메시지인가를 나타낸다. WPARAM wParam; // 전달된 메시지의 부가적인 정보 LPARAM lParam; // DWORD time; // 메시지가 메시지 큐에 저장된 시간 POINT pt; //메시지 큐에 저장된 시간의 마우스 좌표 } MSG , * PMSG typedef struct tagPOINT { LONG x; LONG y; } POINT, * PPOINT;
2. 첫 번째 API프로그램 분석 • TranslateMessage(&msg); • 키보드 번역 • DisplatchMessage(&msg); • 메시지 큐에서 꺼낸 메시지를 윈도우 프로시저로 전달한다. • 윈도우 프로시저 LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam) • 윈도우 프로시저는 항상 RegisterClass를 호출하여 등록한 특정한 윈도우 클래스와 연결되어 있다. • SendMessage라는 함수를 통해서 자신의 윈도우 프로시저를 간접적으로 호출한다. • Message는 WINUSER.H에 define되어 있다. • 윈도우 프로시저가 메시지를 처리할 때에 반드시 윈도우 프로시저로부터 0이 반환되어야 한다. • 윈도우 프로시저가 처리하지 않는 모든 메시지들은 반드시 DefWindowProc라는 이름의 Windows함수에 전달되어야 한다.
2. 첫 번째 API프로그램 분석 • WM_PAINT 메시지 • 윈도우 클라이언트 영역의 일부가 무효화 영역이 되면 발생한다. • 윈도우가 다시 그려져야 함을 알린다. • CS_HREDRAW,CS_VREDRAW는 윈도우의 크기가 변경될 때WM_PAINT를 발생시킨다. • WM_PAINT는 항상 hdc=BeginPaint(hwnd,&ps) • EndPaint( hwnd, &ps)를 이용하여 처리한다. • BeginPaint는 dc의 handle를 반환한다. • BeginPaint호출중에 Windows는 클라이언트 영역의 배경을 윈도우 클래스에 지정한 브러쉬로 지운다. • GetClientRect(hwnd,&rect)는 클라이언트의 크기를 Return한다. • DrawText (hdc, "Hello, Windows 98!",-1, &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; • 텍스트를 그려준다. • 세 번째 인자 –1은 문자열이 NULL로 종료됨을 의미
2. 첫 번째 API프로그램 분석 • DC란 • 출력에 필요한 모든 정보를 가지는 데이터 구조체이다. • 어떤 폰트를 사용할 것이지, 선의 색상과 굵기, 채움 무늬와 색상, 출력방법 과 같은 정보를 담고 있다. • 모든 출력은 윈도우를 기준으로 하며 이러한 원점에 대한 정보도 DC에 있다. • 현재 상황에서 어떤 영역이 출력이 허가된 영역인가를 보고 허가된 영역에만 출력을 내 보낸다. • GDI모듈에 의해 관리된다. • DrawText(HDC uDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat);
2. 첫 번째 API프로그램 분석 • int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) • hWnd : 메시지 박스의 오너 윈도우 핸들
2. 첫 번째 API프로그램 분석 • WM_DESTROY메시지 • 윈도우가 종료되고 있음을 나타낸다. • 사용자가 종료단추를 클릭하거나 시스템 메뉴의 종료 메뉴를 선택하면 WM_DESTOROY를 발생시킨다. • PostQuitMessage(0); • 메시지큐에 WM_QUIT를 삽입한다. • GetMessage()는 메시지가 WM_QUIT면 0을 리턴한다. • 종료 버튼 클릭시 종료순서 • => WM_SYSCOMMAND • => WM_CLOSE • => DestoryWindow() • => WM_DESTORY • => PostQuitMessage()를 call • => 메시지큐에 WM_QUIT를 넣는다.