Overview 윈도우프로그래밍기초 윈도우운영체제와윈도우응용프로그램의특징이해 SDK 응용프로그램작성과정, 기본구조, 동작원리이해 MFC 응용프로그램작성과정, 기본구조, 동작원리이해 HCI Programming 2 (321190) 2007년가을학기 9/13/2007 박경신 2 윈도우운영체제특징 그래픽사용자인터페이스 (Graphical User Interface, GUI) 일관성있는사용자인터페이스 윈도우운영체제특징 메시지구동구조 (Message-driven Architecture) 이벤트발생 대기 윈도우시스템메시지큐 응용프로그램메시지큐 #3 처리 응용프로그램메시지큐 #2 응용프로그램메시지큐 #1 처리 3 4
윈도우운영체제특징 멀티태스킹 (Multi-Tasking) 하나의윈도즈시스템에서여러개의응용프로그램을수행 응용프로그램사이의상호작용가능 멀티스레딩 (Multi-Threading) 하나의응용프로그램에여러개의실행흐름을생성 장치에독립적 장치드라이버 (Device Driver) 에의해주변장치들을제어 윈도우운영체제 윈도우시스템구성모듈구분 Win32 API 커널모듈 KERNEL32.DLL GDI 모듈 GDI32.DLL 역할 윈도우시스템의주요부분으로메모리관리, 파일입출력, 프로그램의로드와실행등운영체제의기본기능수행 화면이나프린터와같은장치의출력을관리. ( 펜, 브러쉬, 폰트, 비트맵, 팔레트등관리 ) 사용자인터페이스모듈 USER32.DLL 윈도우, 다이얼로그, 메뉴, 커서, 아이콘등과같은사용자인터페이스객체들을관리 5 6 윈도우운영체제 & 윈도우응용프로그램 Windows Application Program Windows Operating System (Win32 API) GDI32.DLL USER32.DLL KERNEL32.DLL 윈도우응용프로그램특징 API 호출문집합 API(Application Programming Interface) - 윈도우운영체제가응용프로그램을위해제공하는각종함수집합 응용프로그램 display.drv printer.drv keyboard.drv mouse.drv Device Driver Hardware 7 call API#1 call API#2 call API#3 call API#4 call API#n 8
윈도우응용프로그램특징 메시지핸들러집합 메시지핸들러 (Message Handler) - 메시지를받았을때동작을결정하는코드 윈도우응용프로그램특징 실행파일과 DLL 집합 DLL(Dynamic-Link Library): 프로그램이실행중에호출할수있는함수 ( 코드 ) 와리소스 응용프로그램 메시지핸들러 #1 메시지핸들러 #2 메시지핸들러 #3 메시지핸들러 #4 메시지핸들러 #5 메시지핸들러 #6 윈도우프로시저 : 메시지핸들러집합 응용프로그램 실행파일 DLL #1 DLL #2 DLL #3 DLL #4 DLL #5 9 10 윈도우응용프로그램특징 장치독립적 윈도우시스템의 API를사용하여간접적으로주변장치들을제어응용프로그램 API 장치드라이버주변장치 윈도우응용프로그램개발도구 SDK (Software Development Kit) C 언어로윈도우 API 를직접호출해서프로그램을구현 예, WIN32 API 장점 API 를직접다루기때문에세부적인제어가가능하고, 윈도우운영체제가제공하는모든기능을사용할수있다. 생성코드의크기가작고속도가빠르다. 단점 생산성이낮다. 11 12
윈도우응용프로그램개발도구 윈도우응용프로그램개발도구 RAD (Rapid Application Development) 시각적으로화면을디자인하고코드를추가하는방법으로프로그램을빠르게개발 예, Visual Basic, Delphi 장점 생산성이높다. 단점 일반적으로생성코드의크기가크고실행속도가느리다. 운영체제가제공하는모든기능을활용한세부적인제어가어렵다. 13 RAD 예 -Visual Basic 클래스라이브러리 (Class Library) 윈도우응용프로그램개발에필수적인기능을객체지향언어를이용하여클래스로제공 예, MFC (Microsoft Foundation Class library), 볼랜드 OWL (Object Windows Library) 장점 SDK보다생산성이높다. RAD보다생성코드의크기가작고실행속도가빠르다. 단점 초기학습에필요한기간이길다. 객체지향언어 클래스라이브러리구조와기능, 각클래스의관계파악 14 윈도우응용프로그램, 윈도우시스템, 도구 Application Program ( 메모장 ( 메모장,, 계산기계산기..)..) MFC MFC (C++ (C++ class class library) Win32 Win32 API API (C (C library) Operating System(Windows XP, XP,..)..) Device Device Driver Driver (drv, (drv, dll, dll,..)..) H/W H/W (monitor, printer, keyboard,..)..) Win32 SDK 윈도우프로그램구조 WinMain 함수 윈도우클래스구조정의및등록 윈도우클래스 (WNDCLASS) - 윈도우기본틀에대한정보 ( 배경화면, 커서모양, 아이콘, 메뉴등 ) 을정의하기위한구조체 메인윈도우생성및출력 윈도우클래스로부터인스턴스생성 메시지루프 윈도우시스템으로부터들어오는메시지를분석하고처리 메시지큐에서메시지를하나씩꺼내어처리하기위한반복문 응용프로그램이종료될때까지반복 WinProc 함수 윈도우시스템으로부터받은메시지를처리하는함수 윈도우시스템에서호출하는함수 (call back) 15 16
Event & Message Event 사용자의물리적조작에의해발생 ( 마우스클릭, 키보드입력 ) 윈도우시스템, 응용프로그램자체에서발생 Message 이벤트발생시윈도우시스템이감지하여메시지로변환 윈도우시스템은해당응용프로그램으로메시지전달 메시지는각이벤트에대한표준화된상수값 winuser.h 에정의 Handle 사용중인객체를식별하는고유번호 (32비트정수형 ) 윈도우시스템에서부여 데이터타입 의미 HINSTANCE 프로그램에대한핸들 HWND 윈도우에대한핸들 HDC 디바이스컨텍스트에대한핸들 HCURSOR HICON HMENU 커서에대한핸들 아이콘에대한핸들 메뉴에대한핸들 17 18 Instance 인스턴스는실제메모리상에할당된객체 윈도우프로그램에는코드영역에대한모듈인스턴스와데이터영역에대한데이터인스턴스존재 Device Context 출력에필요한정보를위한구조체 출력정보 : 폰트, 색상, 무늬, 굵기, 출력방법등 출력장치를제어하는 GDI(Graphic Device Interface) 함수호출시사용 Module instance Data instance1 Data instance2 //DC 사용예 HDC hdc= getdc(hwnd); // 현재윈도우로부터 DC 얻어옴 // 각종출력문 TextOut(hdc, 100,100, Beautiful world, 20); // 문자열출력 Rectangle(hdc, 30,40,60,70); // 사각형그리기 LineTo(hdc, 0, 200); // 라인그리기 Memory 19 ReleaseDC(hWnd, hdc) //DC 해제 20
Resource 사용자인터페이스를구성하는자원들의정적데이터 메뉴, 아이콘, 커서, 다이얼로그등 리소스스크립트 (Resource Script) 에의해정의 (.RC) 리소스는프로그램코드와분리하여작성되며자체컴파일 (RC.exe) 과정으로생성된리소스파일 (.RES) 은링크시통합 HelloSDK 예제작성 프로젝트생성 *.h *.cpp *.obj *.ico *.bmp *.rc resource.h *.res *.exe 21 22 HelloSDK 예제작성 1 단계옵션설정 HelloSDK 예제작성 1 단계옵션설정 23 24
HelloSDK 예제작성 소스파일추가 HelloSDK 예제작성 코드입력 25 26 HelloSDK 예제작성 코드입력 #include <windows.h> // WinMain( ) 함수에서참조하므로함수원형을선언한다. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) // 윈도우클래스를초기화하고운영체제에등록한다. wndclass.style = CS_HREDRAW CS_VREDRAW; wndclass.lpfnwndproc = WndProc; wndclass.cbclsextra = 0; wndclass.cbwndextra = 0; wndclass.hinstance = hinstance; 27 HelloSDK 예제작성 wndclass.hicon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hcursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrbackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszmenuname = NULL; wndclass.lpszclassname = "HelloClass"; if(!registerclass(&wndclass)) return -1; // 윈도우를생성하고화면에보이게한다. hwnd = CreateWindow("HelloClass", "HelloSDK Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance, NULL); ShowWindow(hwnd, ncmdshow); UpdateWindow(hwnd); 28
HelloSDK 예제작성 HelloSDK 예제작성 // 메시지대기열에서메시지를하나씩꺼내처리한다. while(getmessage(&msg, NULL, 0, 0) > 0) TranslateMessage(&msg); DispatchMessage(&msg); return msg.wparam; LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) HDC hdc; PAINTSTRUCT ps; char *str = "Hello, SDK"; // 메시지종류에따라응용프로그램이적절히처리한다. switch(message) case WM_CREATE: return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 100, 100, str, lstrlen(str)); EndPaint(hwnd, &ps); return 0; case WM_LBUTTONDOWN: MessageBox(hwnd, " 마우스를클릭했습니다.", " 마우스메시지 ", MB_OK); return 0; 29 30 HelloSDK 예제작성 HelloMFC 예제작성 프로젝트설정변경 case WM_DESTROY: PostQuitMessage(0); return 0; // 응용프로그램이처리하지않으면윈도우운영체제가처리한다. return DefWindowProc(hwnd, message, wparam, lparam); 31 32
HelloSDK 예제 F7 (Build Solution) -> F5 (Start Debugging) 실행화면 HelloSDK 예제분석 헤더파일 윈도우 API 함수의원형 Data type, 구조체, MACRO 상수들이선언 #include <windows.h> 33 34 HelloSDK 예제분석 메인함수 WinMain WinMain() 프로그램을시작하는시작점 windef.h 안에 #define APIENTRY WINAPI 라고지정되어있음 int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) HelloSDK 예제분석 메인함수 WinMain HINSTANCE 는 Process ID ( 즉, Instance Handle) hinstance Win32 프로그램이실행될때시작되는주소값을가지고있는포인터변수 리소스를로드하는함수들이이주소값을참조해서리소스를참조 메모장을 2 개실행하는예 같은프로그램이지만할당되는 hinstance 는다름. 각각고유의값인 hinstance 로구분 hprevinstance 16-bit 윈도우의잔재로사용하지않음. NULL 처리 int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) 35 36
HelloSDK 예제분석 메인함수 WinMain LPSTR 는 32-bit pointer to a character string ( 즉, char *) lpcomline Commend Line 명령행인자를담고있는문자열 HellowSDK TEST1.TXT TEST2.TXT 처럼프로그램을실행하면, lpcomline 은 TEST1.TXT TEST2.TXT 값을가짐 ncmdshow 프로그램이시작될때윈도우모양 ( 최대화면, 아이콘표시등 ) 결정 윈도우의최대, 최소, 정상상태로실행 ShowWindow() 함수호출시사용 int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) 37 HelloSDK 예제분석 메인함수 WinMain HWND Win32 프로그램안에서생성되거나사용되는모든윈도우를구별하거나사용하는데쓰임 WNDCLASS 윈도우를생성하는데필요한다양한정보를담고있는구조체 CreateWindow() 함수를사용하기전에윈도우클래스를커널 (kernel) 에등록 hinstance 가프로그램에하나씩할당하는반면, HWND 는프로그램안의윈도우를다루기위하여다수의 HWND 가존재 int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) HWND hwnd; MSG msg; WNDCLASS wndclass; 38 HelloSDK 예제분석 윈도우클래스초기화와등록 WNDCLASS GetStockObject() 이용 StockObject 은윈도우가기본적으로제공해주는 GDI (Graphic Device Interface) object. 주로브러쉬와펜이사용됨. 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 = "HelloClass"; HelloSDK 예제분석 윈도우생성 CreateWindow 윈도우핸들 = CreateWindow( 지정된클래스이름, 윈도우캡션바에표시되는문자열, 윈도우스타일, 윈도우수평위치, 윈도우수직위치, 윈도우폭, 윈도우높이, 부모윈도의핸들, 메뉴핸들, 인스턴스핸들, WM_CREATE 메시지가윈도우프로시저에보내질때의 parameter); hwnd = CreateWindow("HelloClass", "HelloSDK Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance, NULL); ShowWindow(hwnd, ncmdshow); // 윈도우가화면에나타나게함 UpdateWindow(hwnd); // 윈도우프로시저가 WM_PAINT 메시지를처리하게함 if(!registerclass(&wndclass)) return -1; 39 40
HelloSDK 예제분석 메시지루프 메시지대기열 (Message Queue) 에서메시지를하나씩꺼내서처리 GetMessage - 메시지관리를위한구조체 Message Queue 에서메시지하나를꺼내서메시지변수에저장 Message 가 WM_QUIT 이면 0 을 return 하고 while loop 종료 GetMessage message 관리를위한구조체, 메시지핸들, 최소, 최대 TranslateMessage Keyboard 관련메시지를처리 DispatchMessage 해당메시지를 Window procedure 에보냄 while(getmessage(&msg, NULL, 0, 0) > 0) TranslateMessage(&msg); DispatchMessage(&msg); return msg.wparam; HelloSDK 예제분석 윈도우프로시저 WndProc 윈도우메시지를처리하는핵심함수 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) hwnd 윈도우핸들. 어느윈도우가 window procedure 를호출했는지구분 message 구체적인메시지종류, WM_ 으로시작 wparam, lparam 메시지종류에따라부가적인정보전달 CALLBACK OS 나컴파일러환경에따라서파라미터나리턴값을넘겨주고넘겨받는방식을정하는 MACRO LRESULT long type 과동일 41 42 HelloSDK 예제분석 윈도우프로시저 WndProc LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) HDC hdc; PAINTSTRUCT ps; char *str = "Hello, SDK"; // 메시지종류에따라응용프로그램이적절히처리한다. switch(message) case WM_CREATE: return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); 43 HelloSDK 예제분석 TextOut(hdc, 100, 100, str, lstrlen(str)); EndPaint(hwnd, &ps); // Device Context 해제 return 0; case WM_LBUTTONDOWN: MessageBox(hwnd, " 마우스를클릭했습니다.", " 마우스메시지 ", MB_OK); return 0; case WM_DESTROY: PostQuitMessage(0); // 메시지큐에 WM_QUIT가들어간다 return 0; // 응용프로그램이처리하지않으면윈도우운영체제가처리한다. return DefWindowProc(hwnd, message, wparam, lparam); 44
HelloSDK 예제분석 WIN32 API 와 MFC 요약 MFC 이벤트발생 응용프로그램 #1 메시지루프 Win32 API 를이용해서프로그램을작성할경우코드의길이가매우길어지게되며, 어떠한부분에있어서는모든프로그래머들이반복적으로작성해야하는부분도있음. 이러한단점을보완하기위해서 Microsoft 의수많은개발자들이클래스기반의견고한코드를클래스화해서만든라이브러리임. 시스템메시지큐 응용프로그램메시지큐 #3 응용프로그램메시지큐 #2 응용프로그램메시지큐 #1 윈도우프로시저 메시지핸들러 #1 메시지핸들러 #2 메시지핸들러 #3 DefWindowProc C API C++ Class, OOP MFC 45 46 MFC (Microsoft Foundation Class) SDK (Windows API) 의 WinMain() 함수의기능과 Window Procedure 기능을적절히분할하여 2 개의클래스제공 HelloMFC 예제작성 프로젝트생성 CWinApp 응용프로그램의초기화코드메시지루프, 종료코드등을제공 MFC CFrameWnd Frame window 의기능정의 응용프로그램자신만의특징을갖기위하여위의 2 클래스를그대로사용하지않고, OOP 의 inheritance 기능을이용 47 48
HelloMFC 예제작성 1 단계옵션설정 HelloMFC 예제작성 1 단계옵션설정 49 50 HelloMFC 예제작성 소스파일추가 HelloMFC 예제작성 코드입력 51 52
HelloMFC 예제작성 HelloMFC 예제작성 코드입력 #include <afxwin.h> // 클래스선언부 class CHelloApp : public CWinApp public: virtual BOOL InitInstance(); ; class CMainFrame : public CFrameWnd public: CMainFrame(); protected: afx_msg void OnPaint(); afx_msg void OnLButtonDown(UINT nflags, CPoint point); DECLARE_MESSAGE_MAP() ; // 응용프로그램객체 CHelloApp theapp; // 클래스정의부 BOOL CHelloApp::InitInstance() m_pmainwnd = new CMainFrame; m_pmainwnd->showwindow(m_ncmdshow); 53 54 HelloMFC 예제작성 HelloMFC 예제작성 m_pmainwnd->updatewindow(); return TRUE; CMainFrame::CMainFrame() Create(NULL, "HelloMFC Application"); void CMainFrame::OnPaint() char *msg = "Hello, MFC"; CPaintDC dc(this); dc.textout(100, 100, msg, lstrlen(msg)); void CMainFrame::OnLButtonDown(UINT nflags, CPoint point) MessageBox(" 마우스를클릭했습니다.", " 마우스메시지 "); // 메시지맵 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_PAINT() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() 55 56
HelloMFC 예제작성 프로젝트설정변경 HelloMFC 예제작성 F7 (Build Solution) -> F5 (Start Debugging) 실행화면 57 58 HelloMFC 예제분석 헤더파일 HelloMFC 예제분석 클래스선언부 #include <afxwin.h> 클래스선언부 SDK 에서 #include <windows.h> 를 MFC 에서는 #include <afxwin.h> 로 class CMainFrame : public CFrameWnd public: CMainFrame(); class CHelloApp : public CWinApp public: virtual BOOL InitInstance(); ; protected: afx_msg void OnPaint(); afx_msg void OnLButtonDown(UINT nflags, CPoint point); DECLARE_MESSAGE_MAP() ; 59 60
HelloMFC 예제분석 응용프로그램객체 모든 MFC 프로그램은 CWinApp 클래스에서하나의클래스를파생하고이클래스로부터하나의객체를전역변수로생성 WinMain 함수는 MFC 에서제공 CHelloApp theapp; MFC 응용프로그램의구조 하나의응용프로그램객체 여러종류의클래스선언및정의 61 HelloMFC 예제분석 클래스정의부 숨겨진 WinMain() 은프로그램이시작되면처흠으로 InitInstance 함수를호출 초기화에사용 Virtual 함수로선언해야함 재정의하지않으면 CWinApp 에있는 InitInstance 가수행됨 ShowWindow() 에는윈도우핸들이존재하지않음 윈도우핸들을내부에숨기고있기때문에 BOOL CHelloApp::InitInstance() m_pmainwnd = new CMainFrame; m_pmainwnd->showwindow(m_ncmdshow); m_pmainwnd->updatewindow(); return TRUE; Class CHelloApp: public CWinApp public: virtual BOOL InitStance(); ; 62 HelloMFC 예제분석 클래스정의부 SDK 의 CreateWindow() 함수에상응하는역할 CMainFrame::CMainFrame() Create(NULL, "HelloMFC Application"); // 윈도우생성 HelloMFC 예제분석 클래스정의부 void CMainFrame::OnPaint() char *msg = "Hello, MFC"; CPaintDC dc(this); dc.textout(100, 100, msg, lstrlen(msg)); // SDK 에서 WM_PAINT 역할 // SDK 에서 WM_LBUTTONDOWN 역할 void CMainFrame::OnLButtonDown(UINT nflags, CPoint point) MessageBox(" 마우스를클릭했습니다.", " 마우스메시지 "); 63 64
HelloMFC 예제분석 메시지맵 윈도우메시지와해당메시지핸들러를연결시키는 MFC 방법 ON_WM_PAINT() WM_PAINT 와 OnPaint() 를연결 ON_WM_LBUTTONDOWN() WM_LBUTTONDOWN 과 OnLButtonDown 를연결 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_PAINT() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() HelloMFC 예제분석 숨겨진 MFC 의 WinMain WinMain( ) // MFC 의내부에숨겨진프로그램실행의시작점 // ptr 은포인터로서응용프로그램객체의주소값을가지고있다. ptr->initinstance( ); // 초기화 : 프레임윈도우객체를생성한다. // 프레임윈도우객체의생성자에서 // 실제윈도우가만들어진다. ptr->run( ); // 메시지루프 : 프레임윈도우에게메시지를보낸다. // 프레임윈도우가받은메시지의종류에따라 // 해당메시지핸들러가적절히호출된다. ptr->exitinstance( ); // 종료 : 각종청소작업을수행한다. 65 66 MSDN Reference Windows API Reference 67 68
MFC Reference 69