4.7k likes | 5.58k Views
Windows Programming. 박 상 원 swpark@hufs.ac.kr 한국외국어대학교 정보통신공학과. 서론. 목차. 객체지향이란 ? MFC 의 역사 MFC 를 위한 C++ 의 기초. 객체지향 개념의 등장 배경. 프로그래밍 언어의 발전 기계어 -> 어셈블리어 -> 고급언어 함수 기반 프로그래밍 1970 년대 - 1980 년대 소프트웨어의 위기 생산성 향상의 한계 객체지향 개념의 등장 1980 년대. 객체지향이란 ?. 객체 메쏘드 호출. 메시지. 이벤트.
E N D
Windows Programming 박 상 원 swpark@hufs.ac.kr 한국외국어대학교 정보통신공학과
목차 • 객체지향이란? • MFC의 역사 • MFC를 위한 C++의 기초 MFC Tutorial
객체지향 개념의 등장 배경 • 프로그래밍 언어의 발전 • 기계어 -> 어셈블리어 -> 고급언어 • 함수 기반 프로그래밍 • 1970년대 - 1980년대 • 소프트웨어의 위기 • 생산성 향상의 한계 • 객체지향 개념의 등장 • 1980년대 MFC Tutorial
객체지향이란? 객체 메쏘드 호출 메시지 이벤트 MFC Tutorial
객체지향의 핵심 내용(1) • 객체란 • 데이타(자료구조; 상태변수)와 오퍼레이터(함수)가 하나로 묶여있는 형태 • 추상 데이타 타입(ADT;abstract data type) • 클래스를 이용하여 표현 • 계승(inheritance) • 동적 바인딩(dynamic binding) • cf) Static binding • 다형성(polymorphism) • Overloading : 동일한 함수의 이름 사용 가능 • Overriding : 상위 클래스에서 정의된 함수를 하위 클래스에서 재 정의 • Template : 타입을 인자로 하여 새로운 타입을 생성 MFC Tutorial
MFC를 위한 C++의 기초 • 클래스 • 계승 • 생성자 및 소멸자 • Virtual Function을 이용한 동적 바인딩 MFC Tutorial
클래스란? • 객체를 기술할 수 있는 수단을 제공 • 자료 구조 (member data) • 오퍼레이션 (member function) 모델링 실세계 컴퓨터세계 MFC Tutorial
클래스의 계승(1) • 계승을 통한 코드의 재 사용 가능 • 생산성 향상 • 이름 충돌(name conflict) 발생 • 다중 계승의 문제점 • virtual base class로 계승 MFC Tutorial
class B : virtual public A { ... }; class C : virtual public A { ... }; 클래스의 계승(2) A int x; B int y; C int z; D int z; MFC Tutorial
생성자(1) • 생성자(constructor) 호출 • 메모리 할당과 생성자는 별개 • 메모리 할당 • new : 힙(heap)에 객체 생성 • 지역변수 : 스택(stack)에 객체 생성 • 전역변수 : 프로그램 코드 영역에 객체 생성 • 생성자는 메모리 할당이 끝난 객체의 각 데이타 부분을 초기화하는 역할 MFC Tutorial
A::A(int n) : m_nNo(n) { } B::B(int i) : A( i ) { ptr = new char[ i ]; } 생성자(2) A int m_nNo B char* ptr A* pA = new B(3); 3 500 500 힙/스택/코드 영역 힙 (heap) 영역 MFC Tutorial
소멸자(1) • 소멸자(destructor)의 virtual 함수화 • 소멸자는 객체 자체의 메모리 영역을 없애는 것이 아님 • 그 객체가 new 등을 이용하여 실행중에 만든 객체를 메모리에서 없애는 역할을 한다. MFC Tutorial
소멸자(2) A* ptr = new A; delete ptr; ptr = new B(3); delete ptr; <- 문제 발생. A의 소멸자만 불린다. 3 500 500 접근못하는 메모리 (garbage) 힙/스택/코드 영역 힙 (heap) 영역 MFC Tutorial
Virtual Function(1) • 동적 바인딩(dynamic binding) • 프로그램의 수행 중에 실제 수행할 함수를 결정 • vitual function table(hidden pointer) • 정적 바인딩(static binding) MFC Tutorial
DrawObj* p_obj; p_obj = new Point; p_obj->Draw(); p_obj = new Line; p_obj->Draw(); p_obj = new PolyLine; p_obj->Draw(); Virtual Function(2) DrawObj int a virtual Draw() Point Line int x, y Point start, end virtual Draw() virtual Draw() virtual Calc() PolyLine Point[5] pt virtual Draw() MFC Tutorial
p_obj = new DrawObj; p_obj->Draw(); Virtual Function - 메모리 구조 p_obj = new PolyLine; p_obj->Draw(); 50 250 100 350 430 vtbl 50 vtbl 180 virtual function table int a int a 180 550 430 Point start Point end p_obj = new Line; p_obj->Draw(); Point[0] pt 250 DrawObj::Draw Point[1] pt pointer of virtual function table 350 Point[2] pt vtbl 100 Line::Draw Point[3] pt int a 430 Line::Calc Point[4] pt Point start Point end 550 PolyLine::Draw Code 영역 MFC Tutorial
Line Point Line PolyLine Virtual Function 사용 예 CObList list; DrawObj* p_obj; p_obj = new Line; list.AddTail(p_obj); p_obj = new Point; list.AddTail(p_obj); . . . . POSITION pos = list.GetHeadPosition(); while(pos != NULL) { p_obj = (DrawObj*)list.GetNext(pos); p_obj->Draw(); } List Point MFC Tutorial
목차 • SDK와 MFC의 비교 • MFC 클래스 종류 • AppWizard를 이용한 프로젝트 생성 • Develop Studio 사용법 • Hungarian 표기법 MFC Tutorial
Windows API • Applicatoin Programming Interface • Windows System Calls • Windows 3.1 • Win16 API • Windows 95/NT • Win32 API • C 라이브러리 MFC Tutorial
SDK 프로그래밍 • SDK(Software Development Kit) • 윈도우 프로그래밍을 위한 여러 가지 툴과 라이브러리로 구성되어 있는 마이크로소프트에 의해 발표된 소프트웨어 패키지 • 윈도우 프로그래밍시 호출하여 사용할 수 있는 함수들이 포함 (윈도우 API) • C 라이브러리 MFC Tutorial
메시지와 메시지 큐 • 메시지(message)? • 윈도우에서 발생하는 사건들의 표현 • 숫자 (winuser.h) • 메시지 큐(queue) • 하나의 프로그램에 하나씩 할당 윈도우에 사건이 발생하면 운영체제는 이를 메시지로 만들어 발생 순서대로 메시지 큐에 넣는다. MFC Tutorial
메시지 루프, 윈도우 프로시저 • 메시지 루프 • 메시지 큐에서 메시지를 하나씩 꺼내어 거기에 맞게 처리 • 윈도우 프로시저 • 메시지의 실제 처리 운영체제 응용 프로그랭 메시지를 하나씩 읽어다가 이를 처리할 윈도우의 윈도우 프로시저를 호출한다. MFC Tutorial
Message-driven operations int WinMain(HINSTANCE ......) { . . . InitApplication(hInstance); InitInstance(hInstance); . . . . . . while(GetMessage(....)) { . . . DispatchMessage(. . .); } . . . } 메시지에 의한 동작 윈도우에 사건이 발생하면 운영체제는 이를 메시지로 만들어 발생 순서대로 메시지 큐에 넣는다. msg 메시지 큐 함수 MFC Tutorial
SDK 프로그램의 예 #include “windows.h” // SDK의 API와 각종 상수, 구조체가 정의된 헤더 화일 #include “generic.h” // 이 프로그램 내에서 사용할 상수가 정의되고 함수가 // 선언된 헤더 화일 HINSTANCE hInst; // 인스턴스 핸들을 기억해둔다. HWND hMainWnd; // 메인 윈도우 핸들을 기억해 둔다. int PASCAL 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; MFC Tutorial
// 메시지 루프에 진입한다. while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } MFC Tutorial
InitApplication BOOL InitApplication(HINSTANCE hInstance) { WNDCLASS wc; // WNDCLASS는 윈도우 클래스의 등록에 필요한 구조체이다. wc.style = NULL; wc.lpfnWndProc=MainWndProc; // 윈도우의 윈도우 프로시저 이름을 지정한다 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; // 윈도우가 속한 인스턴스의 핸들을 지정한다. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);// 이 윈도우의 아이콘 지정 wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 이 윈도우의 커서 지정 wc.hbrBackground = GetStockObject(WHITE_BRUSH); // 배경색 지정 wc.lpszMenuName = “EX_Menu”; // 이 윈도우의 메뉴를 지정한다 wc.lpszClassName = “EX_WClass”; // 이 윈도우의 클래스 이름을 지정한다. return RegisterClass(&wc); // 이 윈도우 클래스를 등록한다. } MFC Tutorial
InitInstance BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hMainWnd = hWnd = CreateWindow( “EX_WClass”, // 생성하려는 윈도우의 윈도우 클래스 이름 “EX Program”, // 윈도우의 타이틀을 지정한다. 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; } MFC Tutorial
윈도우 스타일(1) WS_OVERLAPPED 겹쳐질 수 있는 윈도우를 생성한다. WS_SYSMENU 윈도우에 시스템 메뉴를 붙인다. WS_CAPTION 윈도우에 타이틀바를 사용한다. WS_THICKFRAME 윈도우의 테두리선을 굵은선으로 한다. WS_MINIMIZEBOX 축소 버튼을 윈도우 타이틀바 오른쪽에 붙인다. WS_MAXIMIZEBOX 확대 버튼을 윈도우 타이틀바 오른쪽에 붙인다. WS_CHILD 다른 윈도우의 자식 윈도우로 생성한다. WS_VISIBLE 윈도우의 생성과 동시에 윈도우를 보이게 한다. WS_BORDER 윈도우에 테두리를 긋는다. WS_MAXIMIZE 윈도우를 전체 화면 크기로 생성한다. WS_MINIMIZE 윈도우를 아이콘 모양으로 생성한다. WS_HSCROLL 윈도우에 수평 스크롤바를 붙여 생성한다. WS_VSCROLL 윈도우에 수직 스크롤바를 붙여 생성한다. MFC Tutorial
윈도우 스타일(2) WS_POPUP 팝업 윈도우를 생성한다. 이것은 WS_CHILD와 함께 사용될 수 없다. WS_CLIPSIBLINGS 같은 레벨의 자식 윈도우간에 겹치는 영역이 있을 때 각각의 자식 윈도우가 다른 겹치는 자식 윈도우 의 영역으로 넘어가지 못하도록 한다. 이 스타일을 주지 않았을 경우 자식 윈도우끼리 겹칠 때 이상하 게 그려지는 상황이 발생할 수 있다. WS_CLIPCHILDREN 자식 윈도우가 차지하는 영역은 부모 윈도우의 영 역에서 제외된다. 부모 윈도우를 생성할 경우 주어 야 한다. #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION \ | WS_SYSMENU | WS_THICKFRAME \ | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) MFC Tutorial
윈도우 프로시저 MainWndProc long APIENTRY MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: // 사용자가 메뉴 항목을 선택하면 발생하는 메시지 { case ID_FILE_EXIT: SendMessage(hWnd, WM_CLOSE, 0, 0); break; } case WM_PAINT: // 윈도우의 사용자 영역이 복구되어야 할 때 발생하는 메시지 { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd, &ps); TextOut(hDC, 10, 10, “Hello, everybody”, 16); EndPaint(hWnd, &ps); break; } MFC Tutorial
case WM_DESTROY: // 윈도우가 없어지기 직전에 발생하는 메시지 { PostQuitMessage(0); break; } default: // 처리하지 못한 메시지를 넘긴다. return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } MFC Tutorial
generic.h & resource.h • generic.h #include “resource.h” int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int); BOOL InitApplication(HANDLE); BOOL InitInstance(HANDLE, int); long APIENTRY MainWndProc(HWND, UINT, WPARAM, LPARAM); • resource.h #define ID_FILE_EXIT 100 MFC Tutorial
#include "resource.h" #define APSTUDIO_READONLY_SYMBOLS #include "afxres.h" #undef APSTUDIO_READONLY_SYMBOLS // Korean resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_KOR) #ifdef _WIN32 LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT #pragma code_page(949) #endif //_WIN32 // Menu EX_Menu MENU DISCARDABLE BEGIN POPUP "File" BEGIN MENUITEM "Exit", ID_FILE_EXIT END END #ifdef APSTUDIO_INVOKED #endif // Korean resources #ifndef APSTUDIO_INVOKED // Generated from the TEXTINCLUDE 3 resource. #endif // not APSTUDIO_INVOKED generic.rc MFC Tutorial
핸들(Handle) • 무엇인가를 구별하기 위해 붙인 번호 • 예) 윈도우 핸들 (HWND) • 윈도우가 여러 개 존재할 경우 이를 구별하기 위해 윈도우마다 번호를 하나씩 부여 • 핸들 타입 앞에는 H가 붙는다. • UINT로부터 재정의 • #define UINT HANDLE • #define HANDLE HWND MFC Tutorial
타입 BOOL 참, 거짓을 나타내는 타입으로 int로부터 재정의 되었으며 TRUE, FALSE 값을 갖는다. LPSTR char 타입에 대한 포인터, 즉 char * 와 같다. Long Pointer to STRing을 나타낸다. LPCTSTR는 const char * 와 같다. HWND 윈도우들을 구별하기 위해 윈도우에 붙여지는 핸들 타입 HINSTANCE 인스턴스의 구별을 위해 인스턴스마다 부여되는 핸들 타입 UINT unsigned int에 해당. Win32에서는 4 바이트 HANDLE 모든 핸들 타입의 원조에 해당하는 타입. UINT로 부터 typedef 문을 이용해 재정의. H로 시작되는 모든 핸들 타입은 모두 이것으로부터 typedef 문으로 재정의 됨. WPARAM UINT로부터 재정의. 메시지에 수반되는 부가 정보를 나타냄. LPARAM LONG으로부터 재정의. 메시지에 수반되는 부가 정보 표시 MFC Tutorial
주요 메시지(1) WM_CREATE 윈도우가 생성될 때 발생한다. 정확히 말하면 CreateWindow API가 호출되었을 때 발생한다. 이 메시지 처리부에서 초기화 작업을 수행하는 것이 일반적이다. 아직 윈도우가 보이지 않는다. WM_SIZE 윈도우의 크기가 변화하면 발생. 이 메시지가 발생하면 그 뒤에 WM_PAINT가 따라서 발생한다. WM_PAINT 윈도우의 사용자 영역이 가려졌다가 앞으로 나온다든가 해서 다시 그려질 일이 생기면 발생하는 메시지이다. InvalidateRect와 같은 API로 발생시키는 것도 가능하다. WM_COMMAND 사용자가 메뉴에서 명령을 선택하면 발생 WM_CLOSE 사용자가 윈도우의 시스템 메뉴에서 닫기(Close)를 택하면 발생. DefWindowProc 함수는 WM_CLOSE 메시지를 받으면 WM_DESTROY 메시지를 발생 MFC Tutorial
주요 메시지(2) WM_DESTROY 윈도우가 없어지기 직전에 발생한다. 여기서는 앞 서 윈도우 프로시저의 실행중에 할당한 자원들이 있다면 이를 운영체제에 반환하는 역할을 수행함. 메인 윈도우의 WM_DESTROY 메시지 처리부에서 는 끝부분에서 PostQuitMessage 함수를 호출하는 것이 일반적이다. WM_QUIT PostQuitMessage 함수를 호출하면 이 메시지가 만 들어져 메시지 큐에 들어가게 된다. 메시지 루프에 서 이 메시지를 읽어가면 GetMessage 함수의 리턴 값이 FALSE가 되기 때문에 메시지 루프가 끝나게 되고 프로그램이 종료된다. MFC Tutorial
MFC란 • 클래스 라이브러리 • 클래스의 집합 (함수의 집합이 아님) • 애플리케이션 프레임워크(application framework) • AppWizard • ClassWizard • Project Workspace MFC Tutorial
MFC 구조 • MFC는 SDK API의 기능을 구분하여 클래스 계층구조를 입힌 것 • 응용 프로그램은 SDK API를 직접 부를 수 있음 • “Handle”은 분류의 기준이 됨 응용프로그램 MFC SDKAPI 운영체제 MFC Tutorial
왜 MFC 인가? • 이해가 쉬움 • 연관된 함수와 데이타를 “클래스”를 이용하여 그룹화하였음 • 코드의 재사용성 향상 • 소프트웨어 개발의 용이성 • 애플리케이션 프레임워크(application framework) 제공 • 멤버 함수 나열 • 코드 삽입의 용이성 MFC Tutorial
Handle을 이용한 분류 - SDK(1) RECT rc; GetClientRect(hWnd, &rc); MoveWinodw(hWnd, x, y, x2, y2, TRUE); MFC Tutorial
Handle을 이용한 분류 - MFC(1) class CWnd : public CCmdTarget { HWND m_hWnd; ... BOOL GetClientRect(LPRECT lpRect); BOOL MoveWindow(int x,int y,int width,int height,BOOL bDraw=TRUE); ... } BOOL CWnd::GetClientRect(LPRECT lpRect) --> inline 함수를 이용하여 성능 저하를 막는다 { ::GetClientRect(m_hWnd, lpRect); } BOOL CWnd::MoveWindow(int x, int y, int width, int height, BOOL bDraw) { ::MoveWindow(m_hWnd, x, y, width, height); } MFC Tutorial
Handle을 이용한 분류 - SDK(2) HDC hDC = GetDC(hWnd); Rectangle(hDC, 10, 10, 100, 100); TextOut(hDC, 10, 10, “Sample”, 6); ReleaseDC(hWnd,hDC); MFC Tutorial
Handle을 이용한 분류 - MFC(2) class CDC : public CObject { HDC m_hDC; . . . . BOOL Rectangle(int x1, int y1, int x2, int y2); BOOL TextOut(int x, int y, LPSTR lpStr, int size); } BOOL CDC::Rectangle(int x1, int y1, int x2, int y2) { ::Rectangle(m_hDC, x1, y1, x2, y2); } BOOL CDC:: TextOut(int x, int y, LPSTR lpStr, int size) { ::TextOut(m_hDC, x, y, lpStr, size); } MFC Tutorial
SDK - 자원 획득 및 반환 • SDK { HDC hDC; hDC = GetDC(hWnd); // 자원 획득 Rectangle(hDC,10,10,100,100); TextOut(hDC,10,10,“Sample”,6); ReleaseDC(hWnd, hDC); // 반드시 자원을 반환해야 한다. } MFC Tutorial
C++의 장점(생성자/소멸자) - MFC { CClientDC dc(this); dc.Rectangle(10, 10, 100, 100); dc.TextOut(10,10,“Sample”,6); } // 소멸자 불림 CClientDC::CClientDC(CWnd* pWnd) { m_hWnd = pWnd->GetSafeHwnd(); // 윈도우 핸들을 얻는다. m_hDC = ::GetDC(m_hWnd); // 윈도우의 Device Context를 얻음 } CClientDC::~CClientDC() { ::ReleaseDC(m_hWnd, m_hDC); // Device Context를 해제한다. } MFC Tutorial
C++의 장점 - 부재인자 • SDK int MessageBox(HWND hWnd, LPCSTR lpszText, LPCSTR lpszTitle, UNIT flag); InvalidateRect(HWND hWnd, LPCRECT lpRect, BOOL bErase); • MFC int AfxMessageBox(LPCSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0); void InvalidateRect(LPCRECT lpRect, BOOL bErase = TRUE); MFC Tutorial
C++의 장점 - 중복 정의 • 함수 중복 정의(function overloading) BOOL Rectangle(int x1, int y1, int x2, int y2); BOOL Rectangle(LPCRECT lpRect); • 연산자 중복 정의(operator overloading) CRect a, b, c; c.left = a.left + b.left; c = a + b; c.right = a.right + b.right; c.top = a.top + b.top; c.bottom = a.bottom + b.bottom; MFC Tutorial