Windows Programming 시작하기 Department of Digital Contents Sang Il Park
Windows 프로그램의 개념 윈도우 프로그래밍이란? Windows 프로그램 vs. DOS 프로그램 ?? 사용자가 발생시키는 이벤트에 대한 메시지를 처리하는 것 메시지 기반 (Message Driven) 프로그래밍 이벤트 기반 (Event Driven) 프로그래밍 Windows 프로그램 vs. DOS 프로그램 ??
GUI Programming? 이벤트가 발생되었을 때 이를 처리하는 방법을 알려 주는 것 이벤트 핸들러 이벤트 발생
간단한 코딩 연습 C++를 사용하여, 사용자의 입력에 따라 ‘1’을 입력하면 “Sejong University”를 출력 ‘2’를 입력하면 “Digital Contents”를 출력 ‘3’을 입력하면 “Bye~”를 출력하고 종료 위의 과정을 무한 반복
코딩 예 #include <iostream> using namespace std; int main() { int i; while(true) cout<<"Input: "; cin>>i; switch(i) case 1: cout<<"Sejong University"<<endl; break; case 2: cout<<"Digital Contents"<<endl; case 3: cout<<"Bye!"<<endl; return 0; default: }
간단한 코딩 연습 C++를 사용하여, 사용자의 입력에 따라 ‘1’을 입력하면 “Sejong University”를 출력 Windows Procedure C++를 사용하여, 사용자의 입력에 따라 ‘1’을 입력하면 “Sejong University”를 출력 ‘2’를 입력하면 “Digital Contents”를 출력 ‘3’을 입력하면 “Bye~”를 출력하고 종료 위의 과정을 무한 반복 Message (Event) Message (Event) Handler Message Loop
코딩 예 Message Message Loop Message Handler #include <iostream> using namespace std; int main() { int i; while(true) cout<<"Input: "; cin>>i; switch(i) case 1: cout<<"Sejong University"<<endl; break; case 2: cout<<"Digital Contents"<<endl; case 3: cout<<"Bye!"<<endl; return 0; default: } Message Loop Message Message Handler
좀 더 멋있게… void procedure(int msg) { switch(msg) case 1: cout<<"Sejong University"<<endl; break; case 2: cout<<"Digital Contents"<<endl; case 3: cout<<"Bye!"<<endl; exit(0); default: } int main() { int i; while(true) cout<<"Input: "; cin>>i; procedure(i); } return 0;
Win32 Program의 구조
Win32 ? (= Windows API) 프로그래밍의 과정은 無에서 시작하지 않고 다른 사람들이 잘 만들어놓은 확장된 기능들을 이용하여 원하는 기능을 구현한다. 확장된 기능(데이터타입, 구조체, 함수들)을 모아놓은 것을 library라고 한다. EX.) 그림을 화면에 표시하기 위한 함수들 (Library) 소리를 내기 위한 함수들(Library)
Win32 ? ( = Windows API) API (Application Programming Interface) Win32 운영체제 등을 제어하기 위한 기능들을 모아놓은 Library의 일종 주로 C 함수의 형태로 되어 있음. Win32 Windows용 API의 이름 즉, 윈도우에서 돌아가는 프로그램을 만들기 위한 기능들을 모아놓은 가장 기본적인 library Ex.) 창만들기, 버튼 달기, 메뉴만들기 등…
Win32 Project 만들어 보기 FileNewProject Win32 Project 선택
실행결과
Code…. // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // PURPOSE: Processes messages for the main window. // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) case IDM_ABOUT: // MessageBox(hWnd, _T("haha"), _T("about"), MB_OK); DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); default: return DefWindowProc(hWnd, message, wParam, lParam); } case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... RECT rect; GetClientRect(hWnd, &rect); DrawText(hdc, _T("hello, Windows"), -1, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hWnd, &ps); case WM_DESTROY: PostQuitMessage(0); return 0; // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) UNREFERENCED_PARAMETER(lParam); case WM_INITDIALOG: return (INT_PTR)TRUE; if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)FALSE; // // FUNCTION: MyRegisterClass() // PURPOSE: Registers the window class. // COMMENTS: // This function and its usage are only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTWIN32)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TESTWIN32); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // FUNCTION: InitInstance(HINSTANCE, int) // PURPOSE: Saves instance handle and creates main window // COMMENTS: // In this function, we save the instance handle in a global variable and // create and display the main program window. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; // testWin32.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "testWin32.h" #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_TESTWIN32, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTWIN32)); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) TranslateMessage(&msg); DispatchMessage(&msg); return (int) msg.wParam;
Code in short BOOL InitInstance(…) { hWnd = CreateWindow(…); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(…) switch (message) case WM_COMMAND: break; case WM_PAINT: case WM_DESTROY: PostQuitMessage(0); default: return; return 0; int APIENTRY _tWinMain(…) { // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) return FALSE; } // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) if (!TranslateAccelerator(…)) TranslateMessage(&msg); DispatchMessage(&msg); return (int) msg.wParam;
Code in short BOOL InitInstance(…) { hWnd = CreateWindow(…); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(…) switch (message) case WM_COMMAND: break; case WM_PAINT: case WM_DESTROY: PostQuitMessage(0); default: return; return 0; int APIENTRY _tWinMain(…) { // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) return FALSE; } // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) if (!TranslateAccelerator(…)) TranslateMessage(&msg); DispatchMessage(&msg); return (int) msg.wParam;
약간 변경하기… (WinProc) switch문 속 변경하기: 또는 switch 문 속에 아래 것 추가: 추가! 추가! case IDM_ABOUT: MessageBox(hWnd, _T("haha"), _T(“Test!"), MB_OK); DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; 추가! 추가! case WM_LBUTTONDOWN: MessageBox(hWnd, _T("haha"), _T(“Test!"), MB_OK); break;
약간 변경하기… (WinProc) switch문 속 변경하기 2: 추가! case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... RECT rect; GetClientRect(hWnd, &rect); DrawText(hdc, _T("hello, Windows"), -1, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hWnd, &ps); break; 추가!
실행결과
Win32 프로그램 구조 WinMain(…) main 함수 { InitInstance(…) 초기화 (틀을 만들고 보여줌) while( GetMessage (…)) 메시지 루프 DispatchMessage(…) 메세지처리(WinProc) }
MFC ?
윈도우 응용 프로그램 개발 도구 (1/3) API(Application Programming Interface) 기반 장점 운영체제가 응용 프로그램을 위해 제공하는 각종 함수의 집합 장점 세부적인 제어가 가능하고, 윈도우 운영체제가 제공하는 모든 기능을 사용할 수 있다. 생성 코드의 크기가 작고 속도가 빠르다. 단점 생산성이 낮다.
윈도우 응용 프로그램 개발 도구 (2/3) RAD(Rapid Application Development) 장점 단점 시각적으로 화면을 디자인하고 코드를 추가하는 방법으로 프로그램을 빠르게 개발 Visual Basic, Delphi 등 장점 생산성이 높다. 단점 일반적으로 생성 코드의 크기가 크고 실행 속도가 느리다. 운영체제가 제공하는 모든 기능을 활용한 세부적인 제어가 어렵다.
윈도우 응용 프로그램 개발 도구 (3/3) MFC (Microsoft Foundation Class Library) 기반 장점 API 중 많이 사용되는 기능들을 사용하기 쉽게 잘 포장해 놓은 것 객체 지향 언어를 이용하여 클래스로 제공 장점 API 직접 이용 보다 생산성이 높다. RAD보다 생성 코드의 크기가 작고 실행 속도가 빠르다. 단점 초기 학습에 필요한 기간이 길다. 객체 지향 언어 클래스 라이브러리 구조와 기능, 각 클래스의 관계 파악
MFC 프로그램 만들어 보기
The simplest MFC application Single Document No Document/View architecture support No database support No ActiveX control No Docking toolbar No Initial status bar
MFC 응용 프로그램 생성 (1/8) 프로젝트 종류 선택
MFC 응용 프로그램 생성 (2/8) AppWizard 1단계
MFC 응용 프로그램 생성 (3/8) AppWizard 2단계
MFC 응용 프로그램 생성 (4/8) AppWizard 3단계
MFC 응용 프로그램 생성 (5/8) AppWizard 4단계
MFC 응용 프로그램 생성 (6/8) AppWizard 5단계
MFC 응용 프로그램 생성 (7/8) 생성된 프로젝트와 클래스들
MFC 응용 프로그램 생성 (8/8) 실행
MFC 응용 프로그램 작성 코드의 변경
정리 - Application Wizard AppWizard 기능 만들고자 하는 기본적인 프로젝트를 생성 해주고 그 안에 필요한 클래스 생성 클래스에 기본적인 내용을 코딩 기본적인 코딩시간을 절약 하므로 빠른 프로젝트 완성 AppWizard사용 도중 실수로 옵션을 선택하지 않았을 경우 소스에서 새로 추가할 수 있다.
정리 - Project Workspace 프로젝트 워크스페이스의 구성 MFC 클래스를 상속 받아 탄생된 새로운 클래스 클래스 소스가 설정되어 있는 파일들 소스파일 cpp 헤더 파일 h 프로그램에 필요한 메뉴, 아이콘, 문자열, 대화상자 같은 자원
정리 - Project Workspace 프로젝트 워크스페이스의 항목별 설명 프로젝트에 설정되어 있는 클래스별로 출력, 해당 항목을 선택하면 수정 가능 ClassView 프로젝트에 설정되어 있는 파일 리스트 출력, 해당 항목을 선택하여 수정 가능 Solution Explore (=FileView) 프로젝트에 설정되어 있는 메뉴, 대화 상자, 문자열, 아이콘, 비트맵 등 자원의 리스트 출력, 해당 항목 선택 수정 가능 ResourceView 내 용 항 목
정리 - Project Workspace Class View 화면 해당 항목을 더블 클릭하면 클래스 헤더가 나타나고 우측 버튼을 클릭하면 해당 클래스에 함수나 변수, 이벤트를 설정하도록 메뉴 등장 해당 클래스의 멤버 함수와 멤버 변수의 리스트 +버튼을 클릭한 상태에서 해당 항목(변수)을 클릭하면 해당 항목이 설정되어 있는 소스 파일로 이동 protected 형태로 설정되어 있을 경우(열쇠) protected 형태로 설정되어 있지 않을 경우는 열쇠 아이콘이 나타나지 않음
정리 - Project Workspace Resource View 화면 엑셀레이터(핫키 정의) 키값을 정의하는 항목 대화 상자(어떤 형태의 대화 상자의 출력할 폼을 만들어서 저장) 자원들 아이콘 자원 메뉴 자원 문자열 테이블 툴바
정리 - Project Workspace 솔루션 탐색기(File View) 화면 소스 파일 헤더 파일 자원 파일
VC++ Framework CFrameWnd CChildView 윈도우의 프레임(틀)을 관리 데이터를 보여주는 윈도우 CWinApp : 위의 두 오브젝트를 묶어 주고, 프로그램을 구동 시킴(눈에 안보임) 메시지 루프를 돌림
프로그램 내부 구조 theApp (CSimpleMFC : CWinApp) m_pMainFrame (CMainFrame : CFrameWnd) m_wndView (CChildView : CWnd)
응용 프로그램 실행순서 CSimpleMFC theApp; WinMain() // MFC 내부에 숨겨짐 { theApp.InitInstance(); // 초기화 theApp.Run(); // 메시지 루프 theApp.ExitInstance(); // 종료 }
응용 프로그램 클래스 (1/4) // Simple.h class CSimpleMFC : public CWinApp { virtual BOOL InitInstance(); afx_msg void OnAppAbout(); DECLARE_MESSAGE_MAP() };
응용 프로그램 클래스 (2/4) MFC 기본 header file을 모아놓음 #include "stdafx.h" #include "simpleMFC.h" #include "MainFrm.h“ // Simple.cpp BEGIN_MESSAGE_MAP(CSimpleMFC, CWinApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) END_MESSAGE_MAP() CSimpleMFC::CSimpleMFC() { } CSimpleApp theApp; MFC 기본 header file을 모아놓음 // 응용프로그램 자신에 해당하는 전역객체
응용 프로그램 클래스 (3/4) BOOL CSimpleMFC::InitInstance() { SetRegistryKey(_T("Local AppWizard-Generated Applications")); CMainFrame* pFrame = new CMainFrame; m_pMainWnd = pFrame; pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL); pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); return TRUE; }
응용 프로그램 클래스 (3/4) BOOL CSimpleApp::InitInstance() { SetRegistryKey(_T("Local AppWizard-Generated Applications")); CMainFrame* pFrame = new CMainFrame; m_pMainWnd = pFrame; pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL); pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); return TRUE; } 48
응용 프로그램 실행순서 CSimpleApp theApp; WinMain() // MFC 내부에 숨겨짐 { theApp.InitInstance(); // 초기화 theApp.Run(); // 메시지 루프 theApp.ExitInstance(); // 종료 }
응용 프로그램 클래스 (4/4) // 대화상자 관련 클래스 선언 및 정의 부분 - 생략 // ... void CSimpleApp::OnAppAbout() { CAboutDlg aboutDlg; aboutDlg.DoModal(); }
VC++ Framework CFrameWnd CChildView 윈도우의 프레임(틀)을 관리 데이터를 보여주는 윈도우 CWinApp : 위의 두 오브젝트를 묶어 주고, 프로그램을 구동 시킴(눈에 안보임) 메시지 루프를 돌림
프레임 윈도우 클래스 (1/5) // MainFrm.h class CMainFrame : public CFrameWnd { protected: DECLARE_DYNAMIC(CMainFrame) virtual BOOL PreCreateWindow(CREATESTRUCT& cs); virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo); virtual ~CMainFrame(); CChildView m_wndView; afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSetFocus(CWnd *pOldWnd); DECLARE_MESSAGE_MAP() };
프레임 윈도우 클래스 (2/5) // MainFrm.cpp IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() ON_WM_SETFOCUS() END_MESSAGE_MAP() CMainFrame::CMainFrame() { } CMainFrame::~CMainFrame()
프레임 윈도우 클래스 (3/5) int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL)) TRACE0("Failed to create view window\n"); } return 0;
프레임 윈도우 클래스 (4/5) BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; cs.dwExStyle &= ~WS_EX_CLIENTEDGE; cs.lpszClass = AfxRegisterWndClass(0); return TRUE; }
프레임 윈도우 클래스 (4/5) struct CREATESTRUCT{ LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; HWND hwndParent; int cy; int cx; int y; int x; LONG style; LPCTSTR lpszName; LPCTSTR lpszClass; DWORD dwExStyle; }; 56
프레임 윈도우 클래스 (5/5) void CMainFrame::OnSetFocus(CWnd* pOldWnd) { m_wndView.SetFocus(); } BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
VC++ Framework CFrameWnd CChildView 윈도우의 프레임(틀)을 관리 데이터를 보여주는 윈도우 CWinApp : 위의 두 오브젝트를 묶어 주고, 프로그램을 구동 시킴(눈에 안보임) 메시지 루프를 돌림
뷰 클래스 (1/4) // ChildView.h class CChildView : public CWnd { public: protected: virtual BOOL PreCreateWindow(CREATESTRUCT& cs); virtual ~CChildView(); afx_msg void OnPaint(); DECLARE_MESSAGE_MAP() };
뷰 클래스 (2/4) // ChildView.cpp CChildView::CChildView() { } BEGIN_MESSAGE_MAP(CChildView,CWnd ) ON_WM_PAINT() END_MESSAGE_MAP()
뷰 클래스 (3/4) BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) { if (!CWnd::PreCreateWindow(cs)) return FALSE; cs.dwExStyle |= WS_EX_CLIENTEDGE; cs.style &= ~WS_BORDER; cs.lpszClass = AfxRegisterWndClass ( CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL); return TRUE; } Style: http://msdn2.microsoft.com/en-us/library/ms632600(VS.85).aspx ExStyle: http://msdn2.microsoft.com/en-us/library/ms632680(VS.85).aspx System Color: http://msdn2.microsoft.com/en-us/library/ms724371.aspx
뷰 클래스 (4/4) void CChildView::OnPaint() { CPaintDC dc(this); dc.TextOut(100, 100, _T("안녕하세요.“)); }
요약 클래스 종류 베이스 클래스 이름 핵심 함수 - 주 역할 응용 프로그램 CWinApp InitInstance() - 프레임 윈도우를 생성한다. Run() - 메시지 루프를 제공한다. 프레임 윈도우 CFrameWnd OnCreate() - 뷰를 생성한다. 뷰 CWnd OnPaint() - 화면에 출력한다.
집에 가서… 교재 1장 읽어보기 특히 page 55~66