Windows Programming 2013. 3 출처 : 인터넷에서수집한 PT 자료
1. Overview
Getting Started (1) 관련도서 Visual C++/API 프로젝트따라하기, 오진환, 컴스페이스 Programming Windows, Charles Petzold, Microsoft Press Windows application Programming Interface, 김상형 Microsoft Visual C++ Bible 6.0, 이이표, 김병세, 삼양출판사 VC++ 와윈도우프로그래밍, 김주호 Visual C++ Programming Bible, 이상엽, 영진출판사 3
Getting Started (2) 프로그래밍환경 Microsoft Visual C++ 6.0/2008/2010 MSDN Platform SDK(Software development kit) or MFC OS 가제공하는서비스 User : shell service ex. 도스의 command.com 혹은유닉스나리눅스의 shell Programmer : API(Application Programming Interface) 응용프로그램을만들기위해서제공되는함수의집합 Win16( 윈도우즈 3.x) vs. Win32 API( 윈도우즈 95~) 4
Getting Started (3) 윈도우의구성 DLL Windows 의대부분 Kernel : KERNEL32.dll OS 의핵심부분으로메모리관리, 파일입출력, 프로그램의로드와실행등 OS 의기본기능수행 User : USER32.dll 윈도우, 다이얼로그, 메뉴등사용자인터페이스관리 GDI : GDI32.dll 화면, 프린터등에대한출력을담당하며, 펜, 브러시, 폰트등의 GDI 오브젝트를관리 5
Getting Started (4) Windows Programming Tools SDK(Software Development Kit) API 함수를이용 단점 : 프로그램의골격및 GUI 를위한코드를프로그래머가모두작성해야함 단순작업이반복되고프로그램이커질수록관리가어려움 6
Getting Started (5) RAD (Rapid Application Development) Visual Basic, PowerBuilder, Delphi 단점 : 저수준의제어가어려움 MFC(Microsoft Foundation Class Library) 함수가아니라유용한클래스의집합 기본적인프로그램골격및 GUI 클래스제공 WIN32 API를직접이용하여저수준의제어가능 7
2. 프로그램의구조와메시지
Dos Dos vs. Windows 절차적혹은순차적프로그램 프로그래머가프로그램진행을전적으로제어 원하는서비스가있으면프로그램이도스시스템을호출 int main(int argc, char * argv[]) {. while (1) { char ch = bioskey(); keycheck(ch); }. } void keycheck(char ch) {. switch (ch) { case X :. }. } 9
Windows Dos vs. Windows Event-driven or message-driven 윈도우시스템과프로그래머가프로그램의진행을분담해서처리 윈도우시스템은이벤트를감지하여프로그램에전달 프로그래머는관심있는메시지만처리하면됨 example 사용자입력 장치드라이버 메시지큐 응용프로그램 윈도우시스템 장치드라이버 출력 10
Dos vs. Windows 출력장치 device driver 프로그램 device driver message queue 프로그램 입력장치 device driver 프로그램 11
구성방식 꼭알아야할요소들 Event & Message Message queue Message loop Window Proc Handle Instance Resource Hardware 접근방식 비트연산자 12
필수적인이해요소 (1) Event & Message Event : 주로사용자의기계적인조작에의해발행되는것 윈도우 OS가감지, 해당프로그램으로메시지를전달 이때전달되는메시지는표준화되어있는상수값 (winuser.h) Message Queue Message가저장되는곳 FIFO System message Queue & Program message Queue RIT(Raw Input Thread) 해당프로그램의 Message Queue 로전달 13
메시지큐 입력장치 윈도우즈OS device driver 프로그램시스템시스템 device 분배기메시지큐 driver (RIT) device driver 프로그램메시지큐 ( 메모장 ) 프로그램메시지큐 ( 그림판 ) 메모장 그림판 14
필수적인이해요소 (2) Message Loop Message queue 에어떤 message 가들어왔는지를지속적으로감시하고분석해주는부분 Window Procedure Callback : 운영체제에서호출하는함수 Message loop 에서해석한 message 를구체적으로처리하는기능을수행 구조 : 간단한 switch.., case.. 문의집합 LRESULT CALLBACK WndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) { switch (umsg) { case WM_LBUTTONDOWN: case WM_DESTROY: } } 15
필수적인이해요소 (3) Handle Dos 데이터를참조하거나조작하기위해 pointer 를이용 ex) fopen() Windows 데이터를참조하거나조작하기위해 handle 사용 프로그램에서현재사용중인객체들을식별하기위해윈도우 OS 가부여하는고유번호 윈도우를만들거나, 파일을열면 OS 가부여 해당윈도우나파일을다시참조시핸들을사용 32 bit 정수형, 중복되지말아야된다. 핸들형변수를만들어핸들을대입받아사용 16
Handle 을사용하는이유 device driver 프로그램 device 윈도우핸들 driver device driver 핸들테이블 기존의참조대상 이동된참조대상 메모리주소 17
Handle 종류 Data Type HWND HCURSOR HICON HINSTANCE HDC HMENU 의미 윈도우에대한핸들커서에대한핸들아이콘에대한핸들프로그램자신의 인스턴스 에대한핸들장치컨택스트에대한핸들메뉴에대한핸들 18
필수적인이해요소 (4) Instance 프로그램 Code segment & Data segment 모든프로그램은같은코드를실행 프로그램에따라데이터는달라짐 Instance 실제메모리상에할당된객체 Module instance & Data Instance 모듈인스턴스 데이터인스턴스 1 데이터인스턴스 2 19
필수적인이해요소 (5) Resource 사용자인터페이스를구성하는자원들의정적 data 메뉴, 커서, 아이콘 Resource Scrip에의해정의 자체 compile 과정 (.res) 메모리를효율적으로사용하기위해사용 필요한시점에파일로부터로딩 DISCARDABLE 설정가능 20
필수적인이해요소 (6) 하드웨어운용방식 Dos 비디오나프린터에출력하기위해서는 Port, Bios, DMA 등을통해직접제어 하드웨어장치에종속된프로그램 장치의종류와모델에따른프로그래밍필요 Windows 디바이스드라이버를윈도우가내장 하드웨어에독립적인프로그램 DC를이용하여 GDI(Graphic Device Interface) 를호출 장치의종류나모델에상관없이 1번만프로그램을작성하면됨 21
필수적인이해요소 (7) 비트 OR 연산자 함수에인수전달시, 여러개의옵션을묶어전달 옵션들의실제값은 2 의제곱승으로정의 옵션별로비트자리가정해져있다. 사용자는매크로값만알고있으면된다. ex) 윈도우스타일, 문자열출력방식. WS_OVERLAPPEDWINDOW = WS_OVERLAPPED WS_CAPTION WS_SYSMENU WS_THICKFRAME WS_MINIMIZEBOX WS_MAXIMIZEBOX 22
Window Program 의파일구성 Code file : C header와 source file Resource file.res file 실행중에내용이변하지않는데이터저장 bitmap, icon, cursor, string, dialog box, menu,...def file code와 data의메모리속성 stack과 heap의크기지정 Makefile.dsw file, cf) Visual C++ 4.X 는확장자.mdp 23
표기법 Ex) Char szaddress[10]; 접두어 (Prefix) BM_ CB_ 의미 버튼메시지 콤보박스메시지 접두어 (Prefix) Data Type DM_ 다이얼로그메시지 a 배열 (array) EM_ 에디트컨트롤메시지 b bool LB_ 리스트박스메시지 ch 문자 WM_ 윈도우메시지 cb dw h 바이트개수부호없는 long 형정수핸들 접두어 (Prefix) BS_ CBS_ 의미버튼스타일콤보박스스타일 sz Null 로끝나는문자열 DS_ 다이얼로그스타일 I integer ES_ 에디트컨트롤스타일 p 포인터 LBS_ 리스트박스스타일 WS_ 윈도우스타일 24
Type Type BOOL : int로부터재정의 LPSTR : char* HWND : 윈도우식별자 HINSTANCE : 인스턴스식별자, UINT : 4 bytes HANDLE : UINT를재정의 WPARAM : 메시지의부가정보, UINT를재정의 LPARAM : 메시지의부가정보, LONG을재정의 25
Window Program 의구조 (1) MsgQueue WinMain 가져온메시지 WM_PAINT WM_KEYDOWN WM_SIZE WinProc Message Handler Message Handler 제일먼저전달된메시지 Message Handler Message Handler DefWindowProc 처리되지않은메시지 26
Window Program 의구조 (2) Int winapi WinMain( ) { } InitApplication(); // 클래스등록 InitInstance(); // 창생성 while (GetMessage(&msg,NULL,0,0) { TranslateMessage(&msg); DispatchMessage(&msg); } // 메시지를전송받으면실행, 실행이끝나면메시지를전송한곳으로되돌아간다. LRESULT WndProc( ) { } < 전송받은메시지에따른처리를수행 > 27
#include windows.h #include generic.h HINSTANCE hinst; HWND hmainwnd; // SDK의 API의각종상수, 구조체가정의된헤더파일 // 이프로그램에서사용한상수가정의되고함수선언 // 인스턴스핸들을기억 // 메인윈도우핸들을기억 int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { MSG msg; if(!hprevinstance) if(!initapplication(hinstance)) return FALSE; hinst = hinstance; if(!initinstance(hinstance, ncmdshow)) return FALSE; // 윈도우클래스를등록 // 인스턴스핸들을전역변수에저장 } // 메시지루프에진입한다. While(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wparam; 28
BOOL InitApplication(HINSTANCE hinstance) { WNDCLASS wc; // WNDCLASS는윈도우클래스의등록에필요한구조체 wc.lpfnwndproc = MainWndProc; // 윈도우프로시져 wc.cbclsextra = 0; // 클래스여분바이트 wc.cbwndextra = 0; // 윈도우여분바이트 wc.hinstance = hinstance; // 인스턴스핸들 wc.hicon = LoadIcon(NULL, IDI_APPLIATION); // 아이콘지정 wc.hcursor = LoadCursor(NULL, IDC_ARROW); // 커서지정 wc.hbrbackground = GetStockObject(WHITE_BRUSH); // 배경색지정 wc.lpszmenuname = EX1_1Menu ; // 메뉴지정 wc.lpszclassname = EX1_1WClass ; // 클래스이름지정 } return RegisterClass(&wc); // 윈도우클래스를등록한다. 29
BOOL InitInstance(HINSTANCE hinstance, int ncmdshow) { HWND hwnd; hmainwnd = hwnd = CreateWindow( EX1_1WClass, // 생성하려는윈도우클래스이름 EX 1-1, // 윈도우타이틀지정 WS_OVERLAPPEDWINDOW, // 윈도우스타일 CW_USEDEFAULT, // 시작 X좌표 CW_USEDEFAULT, // 시작 Y좌표 CW_USEDEFAULT, // 윈도우의폭 CW_USEDEFAULT, // 윈도우의높이 NULL, // 부모윈도우핸들 NULL, // 메뉴핸들 hinstance, // 응용프로그램인스턴스핸들 NULL // 윈도우작성일 ); if(!hwnd) // 윈도우가실패했으면, return FALSE; } ShowWindow(hWnd, ncmdshow); // 메인윈도우형태결정, WM_PAINT 발생 UpdateWindow(hWnd); // WM_PAINT 메시지를바로처리 return TRUE; 30
long APIENTRY MainWndProc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch(message) { case WM_COMMAND: { // 사용자가메뉴항목을선택할때발생하는메시지 switch(loword(wparam)) { // wparam 의하위워드에메뉴 ID case ID_FILE_EXIT: SendMessage(hWnd, WM_CLOSE, 0, 0); break; } break; } case WM_PAINT: { // 사용자영역이다시그려져야할때발생하는메시지 HDC hdc; PAINTSTRUCT ps; } hdc = BeginPaint(hWnd, &ps); TextOut(hDC, 10, 10, Hello, Everybody, 16); EndPaint(hWnd, &ps); break; } case WM_DESTROY: // 윈도우가없어지기직전에발생 default: PostQuitMessage(0); break; return DefWindowProc(hWnd, message, wparam, lparam); 31
WinMain 분석 WinMain 함수인자 함수인자 hinstance hprevinstance lpcmdline ncmdshow 의미 현재실행중인어플리케이션의인스턴스핸들 동일한어플리케이션이실행중일경우이전에실행된프로그램의인스턴스핸들을나타냄 (win32 의경우항상 NULL) 커맨드라인의문자열을가르키는포인터 메인윈도우를어떻게출력할것인지를결정하는인자로 ShowWindow() 함수호출시사용된다. (1) WNDCLASS 등록 앞으로사용할윈도우의특성을 OS 에알림 (2) Main Window 의생성 앞서등록한윈도우를메인윈도우로생성 (3) Message Loop 의진입 윈도우에서발생한메시지를처리하기위해서루프에들어감 32
(1) WNDCLASS 등록 WNDCLASS 구조체 : 윈도우클래스를 OS 에등록 lpfnwndproc - 메시지를처리할 Window Procedure의이름 hinstance - 이윈도우가속한 instance handle hicon - 아이콘을지정, LoadIcon hcursor - 커서를지정, LoadCursor hbrbackground - 배경색지정 lpszmenuname - 메뉴지정 lpszclassname - 윈도우이름 RegisterClass API 를이용해서 OS 에등록 클래스스타일 의미 CS_HREDRAW 사용자영역의폭이변경되면전체를다시그린다. CS_VREDRAW 사용자영역의높이가변경되면전체를다시그린다. CS_NOCLOSE 시스템메뉴의 Close 항목을사용할수없게한다. CS_DBCLICKS 윈도우프로시저에더블클릭메시지를보낸다. 33
(2) Main Window 의생성 & 출력 Window Style WS_OVERLAPPED WS_SYSMENU WS_CAPTION WS_MINIMIZEBOX WS_MAXMIZEBOX WS_CHILD WS_VISIBLE WS_BORDER WS_HSCROLL WS_VSCROLL WS_POPUP WS_CLIPSIBLINGS WS_CLIPCHILDREN. Popup & Child 34
WS_OVERLAPPEDWINDOW & Client Area WS_OVERLAPPEDWINDOW #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED \ WS_CAPTION \ WS_SYSMENU \ WS_THICKFRAME \ WS_MINIMIZE \ WS_MAXMIZE) Client Area window border, title bar, menu bar, scroll bar 를제외한영역 35
Title bar Menu bar Window border 사용자영역의원점 Client Area < 사용자영역 > 36
ShowWindow & UpdateWindow BOOL ShowWindow(HWND hwnd, // handle of window int ncmdshow // show state of window); WM_PAINT 메시지발생 SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOW SW_HIDE SW_MAXIMIZE SW_MINIMIZE SW_RESTORE SW_SHOW 윈도우를감춘다. 윈도우를전체화면크기로만든다. 윈도우를아이콘화한다. 이전상태로되돌린다. 윈도우를활성화시킨다. BOOL UpdateWindow( HWND hwnd ); ShowWindow 에서발생한 WM_PAINT 메시지를처리 37
(3) Message Loop 의진입 GetMessage Message queue로부터메시지를읽어온다. WM_QUIT메시지를받으면 0(False) 을리턴한다. Message loop를빠져나오면서, 프로그램을종료한다. TranslateMessage Message 중키보드와관련된 message에대해서특정작업수행 문자가입력되었다는 Message (WM_CHAR) 를생성 DispatchMessage Message를윈도우프로시저 (WndProc) 에전달하는역할을한다. OS에게윈도우프로시져의호출을요청 WM_QUIT Message 가오기전까지 Loop 38
MSG 구조체 Typedef struct tagmsg { HWND hwnd; UINT messgae; WPARAM wparam; LPARAM lparam; DWORD time; POINT pt; } 멤버의미 Hwnd 메시지를받을윈도우핸들 Message 어떤종류의메시지인가? wparam 전달된메시지의부가정보 lparam 전달된메시지의부가정보 time 메시지가발생한시간 Pt 메시지가발생했을때의마우스의위치마우스왼쪽버튼을누른경우 1 st parameter: hwnd 2 nd parameter: WM_LBUTTONDOWN 3 rd parameter: Ctrl key나 shift key가눌렸는지여부 4 th parameter: LOWOD(lPARAM) 은커서의 x좌표 HIWORD(lPARAM) 은커서의 y좌표 39
Window Procedure LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 해당윈도우에서발생한메시지를최종적으로처리 각메시지마다추가정보가 wparam, lparam 에온다. - help 참조 ex) WM_KEYDOWN 메시지 nvirtkey = (int) wparam; lkeydata = lparam; // virtual-key code // key data message handler 가없는메시지는 DefWindowProc 함수가처리한다. WM_CLOSE, WM_ACTIVATE, WM_SYSCOMMAND 등수십개의메시지를디폴트로처리해준다. 40
중요한메시지 (1) WM_PAINT 윈도우의모양에변화가생길때발생 가려졌다가복구 크기가변경될때 BeginPaint() 를호출함으로써시작 EndPaint() 를호출하여끝냄 (2) 에 WM_PAINT 메시지발생 (1) (1) (2) (2) 41
중요한메시지 (2) WM_SIZE 윈도우의크기가변경될때 wparam : 메시지가발생한이유 플래그 SIZE_MAXHIDE 값 다른윈도우가최대화되어이윈도우가가려졌다 SIZE_MAXMIZED 최대화되었다. SIZE_MAXSHOW 다른윈도우가원래크기로복구되어이윈도우가드러났다. SIZE_MINIMIZED 최소화되었다. SIZE_RESTORED 크기가변경되었다. lparam : 상위워드 : 변경된후의윈도우높이 하위워드 : 변경된후의윈도우폭 42
중요한메시지 (3) WM_MOVE 윈도우의위치가변경될때 wparam : 위치변경플래그 (SIZE_RESTORED) lparam 상위워드 : 윈도우의 x 좌표 하위워드 : 원도우의 y 좌표 43
중요한메시지 (4) WM_DESTROY 사용자의명령에의해 Windows 가원도우를종료하고있음을알려준다. 자원을 OS 에반환 PostQuitMessage() 를호출 프로그램의메시지큐에 WM_QUIT 를삽입 GetMessage 는 0 을반환 WinMain 이메시지루프를벗어나게함 윈도우가생성될때 : WM_CREATE -> WM_SIZE -> WM_PAINT 윈도우가종료될때 : WM_CLOSE -> WM_DESTROY -> WM_QUIT 44