Visual C download - Visual Studio Team System 2008 Team Suite (90-days Trial)

Slides:



Advertisements
Similar presentations
일정 관리 다이어리 제작 JSP Programming with a Workbook. 학습 목표  사용자의 일정을 관리할 수 있는 다이어리에 대하여 알아보자. JSP Programming with a Workbook2.
Advertisements

Message Process for SDI Chung-Buk HRD Institute of KCCI Dept. of Information & Communication PhD. Kang, Won-Chan.
Visual C++ Programming Document/View Architecture Department of Digital Contents Sang Il Park.
컴퓨터 공학 설계 및 실험 I MFC programming
메뉴 용어 (1/6) 최상위 메뉴 = 메뉴 바 최상위 메뉴 = 메뉴 바.
Windows XP SP2 문제해결 Windows XP SP2를 설치한 회원께서는 Pop-up차단 기능과 ActiveX 설치의 어려움 발생 아래의 예는 안철수 바이러스 설치 시 문제점을 해결 하는 방법의 설명. 1. ActiveX 컨트롤 설치 ① 주소 표시줄 아래의 '이.
2장. 윈도우즈 입출력 1/211 1.
윈도우 운영체제와 윈도우 응용 프로그램의 특징을 이해한다.
MFC Application Frameworks (AFX)
순차, 조건, 반복 이점숙 같은 문제 다르게 해결하기 순차, 조건, 반복 이점숙
Lecture 2 MFC and Application Frameworks
Lab 10 Guide: 프린터 출력 예제. 한 페이지의 그림 인쇄 (교재 24장, 쪽)
제1장 윈도우 프로그래밍 1.1 윈도우 프로그래밍의 개념 1.2 윈도우 프로그램의 기본 구조
컴퓨터프로그래밍 1주차실습자료 Visual Studio 2005 사용법 익히기.
Visual C++ Programming Document/View Architecture 3
제1장 윈도우 프로그래밍 1.1 윈도우 프로그래밍의 개념 1.2 윈도우 프로그램의 기본 구조
5장. 단축키와 비트맵 윈도우 프로그램에는 화면에서 사용자들의 입력을 받아 들이고 출력을 위한 코드 외 부분이 존재한다. 이 부분을 주로 리소스라고 부르고 이들은 주로 화면에 나타난다. 메뉴, 툴바, 비트맵, 단축키, 대화상자 등이 여기에 속한다. 이 부분들은 우리의 프로그램의.
윈도우의 화면 출력 원리를 이해한다. CDC 클래스를 이용한 화면 출력 기법을 배운다.
Image & Video processing
코크파트너 설치 가이드 Window 7.
윤 홍 란 다이알로그(대화상자) 윤 홍 란
제 9 장 구조체와 공용체.
윤 홍 란 MFC 기초 윤 홍 란
Windows Programming 시작하기
Lab 2 Guide: 교재 3장 그래픽 예제 ( 쪽) - 펜과 브러시로 그리기 - 튀는 공
공통 컨트롤의 종류와 특징을 개관한다. 각종 공통 컨트롤의 사용 방법을 익힌다..
Department of Digital Contents Sang Il Park
Visual C++ Programming How to draw 3
마우스(Mouse) 다루기 컴퓨터응용 및 실습 I.
Communication and Information Systems Lab. 황재철
1. C++ 시작하기.
Lecture 3 Graphics with GDI
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
SqlParameter 클래스 선문 비트 18기 발표자 : 박성한.
충북대학교 컴퓨터 그래픽스 연구실 3학기 김일수
메시지 큐[5] – test1.c 메시지 제어: msgctl(2) #include <sys/msg.h>
WinCE Device Driver 실습 #3
학습목표 학습목차 다른 홈페이지의 HTML 파일 코드를 보는 방법에 대해 알아봅니다.
컴퓨터 프로그래밍 : 실습3 2장 데이터와 식.
분할 윈도, 다중 뷰… 영상 통신 연구실 권 동 진 발표 일 : 04월 27일.
Windows Programming 시작하기
C#.
13. 연산자 오버로딩.
사용자 함수 사용하기 함수 함수 정의 프로그램에서 특정한 기능을 수행하도록 만든 하나의 단위 작업
3장 상수 변수 기본 자료형 키워드와 식별자 상수와 변수 기본 자료형 형변환 자료형의 재정의.
홀인원2.0 설치 메뉴얼.
영상처리 실습 인공지능연구실.
GUI 소켓 애플리케이션 Chapter 08. * 학습목표 윈도우 GUI 애플리케이션의 구조와 동작 원리를 이해
Lab 1 Guide: 교재 2장 DrawX ( 쪽)
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
SEOUL NATIONAL UNIVERSITY OF SCIENCE & TECHNOLOGY
3D 프린팅 프로그래밍 01 – 기본 명령어 강사: 김영준 목원대학교 겸임교수.
충북대학교 컴퓨터 그래픽스 연구실 3학기 김일수 작성
ASP.NET AJAX / AJAX Control Toolkit 응용 2008 컴퓨터공학실험( I )
Lab 8 Guide: 멀티스레딩 예제 2 * Critical Section을 이용한 멀티스레딩 동기화 (교재 15장, 쪽)
SEOUL NATIONAL UNIVERSITY OF SCIENCE & TECHNOLOGY
컴퓨터 프로그래밍 기초 [01] Visual Studio 설치 및 사용방법
( Windows Service Application Debugging )
Windows 프로그래밍 환경 및 MFC의 구조
영상처리 실습 (OpenCV + MFC) Chonbuk National University A.I. Lab.
05. 그래픽 빨간색 사각형 그리기 그래픽 그리기 발 표 자 : 07 정 경 오.
가장 많이 사용 Accelerator 최상위 WM_COMMAND, OLE 메시지 관련 이벤트 처리만 가능 이 클래스를 상속받아서 다른 이벤트 처리 이벤트 처리 관련 윈도우(창) 최상위 클래스 멀티 테스킹(모듈) CFrameWnd, Cview,
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
메뉴(Menu) 컴퓨터응용 및 실습 I.
01. 분산 파일 시스템의 개요 네트워크에 분산된 파일을 사용자가 쉽게 접근하고 관리할 수 있게 해준다.
기초C언어 제2주 실습 프로그래밍의 개념, 프로그램 작성 과정 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원
MFC 응용 프로그램 구조 두 개의 윈도우로 구성된 일반적인 MFC 프로그램 프레임 윈도우
그래픽 컨트롤 (Graphic Control)
MFC 기초 윈도우 응용프로그램 개발 간략한 역사 Microsoft Foundation Classes
BoardGame 보드게임 따라가기.
Presentation transcript:

Visual C++ 2008 download - Visual Studio Team System 2008 Team Suite (90-days Trial) http://www.microsoft.com/downloads/details.aspx?FamilyID=d95598d7-aa6e-4f24-82e3-81570c5384cb&DisplayLang=en - Service Pack 1 (Visual C++ 2008 Feature Pack 포함) http://www.microsoft.com/downloads/details.aspx?displaylang=ko&FamilyID=fbee1648-7106-44a7-9649-6d9f6d58056e MSDN Library for Visual Studio 2008 SP1 http://www.microsoft.com/downloads/details.aspx?FamilyID=7bbe5eda-5062-4ebb-83c7-d3c5ff92a373&DisplayLang=en - 저자가 운영하는 카페 http://cafe.naver.com/windev

Part 1 Windows programming basic

Chapter 1 Windows programming model

HelloWorld 20 int APIENTRY _tWinMain(HINSTANCE hInstance, 21 HINSTANCE hPrevInstance, 22 LPTSTR lpCmdLine, 23 int nCmdShow) 24 { 25 UNREFERENCED_PARAMETER(hPrevInstance); 26 UNREFERENCED_PARAMETER(lpCmdLine); 27 28 // TODO: Place code here. 29 MSG msg; 30 HACCEL hAccelTable; 31 32 // Initialize global strings 33 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 34 LoadString(hInstance, IDC_HELLOWORLD, szWindowClass, MAX_LOADSTRING); 35 MyRegisterClass(hInstance); 36 37 // Perform application initialization: 38 if (!InitInstance (hInstance, nCmdShow)) 39 { 40 return FALSE; 41 }

HelloWorld 43 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HELLOWORLD)); 44 45 // Main message loop: 46 while (GetMessage(&msg, NULL, 0, 0)) 47 { 48 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 49 { 50 TranslateMessage(&msg); 51 DispatchMessage(&msg); 52 } 53 } 54 55 return (int) msg.wParam; 56 }

Message queue 1 2 Key & mouse Message 3 System queue A B A B Windows procedure() Message loop Application queue Notepad.exe WindowProc() B B 6 5 4 Tackmgr.exe WindowProc() A A

Message queue/ “No response” / WM_SHOWWINDOW

HelloWorld 1623 typedef struct tagMSG { 1624 HWND hwnd; 1625 UINT message; 1626 WPARAM wParam; 1627 LPARAM lParam; 1628 DWORD time; 1629 POINT pt; 1630 #ifdef _MAC 1631 DWORD lPrivate; 1632 #endif 1633 } MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

HelloWorld 73 ATOM MyRegisterClass(HINSTANCE hInstance) 74 { 74 { 75 WNDCLASSEX wcex; 76 77 wcex.cbSize = sizeof(WNDCLASSEX); 78 79 wcex.style = CS_HREDRAW | CS_VREDRAW; 80 wcex.lpfnWndProc = WndProc; 81 wcex.cbClsExtra = 0; 82 wcex.cbWndExtra = 0; 83 wcex.hInstance = hInstance; 84 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HELLOWORLD)); 85 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 86 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 87 wcex.lpszMenuName = MAKEINTRESOURCE(IDC_HELLOWORLD); 88 wcex.lpszClassName = szWindowClass; 89 wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 90 91 return RegisterClassEx(&wcex); 92 } 93

HelloWorld 134 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 135 { 136 int wmId, wmEvent; 137 PAINTSTRUCT ps; 138 HDC hdc; 139 140 switch (message) 141 { 142 case WM_COMMAND: 143 wmId = LOWORD(wParam); 144 wmEvent = HIWORD(wParam); 145 // Parse the menu selections: 146 switch (wmId) 147 { 148 case IDM_ABOUT: 149 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 150 break; 151 case IDM_EXIT: 152 DestroyWindow(hWnd); 153 break; 154 default: 155 return DefWindowProc(hWnd, message, wParam, lParam); 156 } 157 break;

HelloWorld 158 case WM_PAINT: 159 hdc = BeginPaint(hWnd, &ps); 160 // TODO: Add any drawing code here... 161 EndPaint(hWnd, &ps); 162 break; 163 case WM_DESTROY: 164 PostQuitMessage(0); 165 break; 166 default: 167 return DefWindowProc(hWnd, message, wParam, lParam); 168 } 169 return 0; 170 } 171

CALLBACK & Call convention 124 // 125 // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 126 // 127 // PURPOSE: Processes messages for the main window. 128 // 129 // WM_COMMAND - process the application menu 130 // WM_PAINT - Paint the main window 131 // WM_DESTROY - post a quit message and return 132 // 133 // 134 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

CALLBACK & Call convention 122 #elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) 123 #define CALLBACK __stdcall 124 #define WINAPI __stdcall 125 #define WINAPIV __cdecl 126 #define APIENTRY WINAPI 127 #define APIPRIVATE __stdcall 128 #define PASCAL __stdcall 129 #else

실습문제 자신의 이름의 머리 글자로 지금까지 설명한 예제 프로젝트를 생성하고 코드를 확인합니다. _tWinMain( ) 함수에서 액셀러레이터 키와 관련한 코드를 삭제해 봅시다. WM_DESTROY 메시지가 발생했을 때 프로그램이 종료되지 않도록 메시지 프로시저 함수를 수정해 봅시다. [About] 메뉴를 선택하면 정보 화면이 나오지 않고 프로그램이 종료되도록 코드를 수정해 봅시다.

Chapter 2 MFC CWnd class

CWnd class CObject CCmdTarget CWnd

CWnd::Create() 102 103 int CCreateDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct) 104 { 105 if (CView::OnCreate(lpCreateStruct) == -1) 106 return -1; 107 108 m_wndChild.Create(TEXT("STATIC"), TEXT("DEMO"), 109 WS_CHILD | WS_VISIBLE | WS_BORDER, 110 CRect(30, 30, 180, 180), this, 1234); 111 112 return 0; 113 } 114

CWnd::Create() View window (CCreateDemoView class) Parent window Left top (0, 0) “WS_BORDER” window style Point A Left top (30, 30) “STATIC” class window Point B Right bottom (180, 180)

CWnd::Create() virtual BOOL Create( LPCTSTR lpszClassName, // 윈도우 클래스 이름 LPCTSTR lpszWindowName, // 윈도우 텍스트 DWORD dwStyle, // 윈도우 스타일 Const RECT& rect, // 윈도우 좌표 CWnd* pParentWnd, // 부모 윈도우 UINT nID, // 윈도우 리소스 ID CCreateContext* pContext = NULL // 생성 컨텍스트(Context) );

Window Message 2430 /* 2431 * Window Styles 2432 */ 2433 #define WS_OVERLAPPED 0x00000000L 2434 #define WS_POPUP 0x80000000L 2435 #define WS_CHILD 0x40000000L 2436 #define WS_MINIMIZE 0x20000000L 2437 #define WS_VISIBLE 0x10000000L 2438 #define WS_DISABLED 0x08000000L 2439 #define WS_CLIPSIBLINGS 0x04000000L 2440 #define WS_CLIPCHILDREN 0x02000000L 2441 #define WS_MAXIMIZE 0x01000000L 2442 #define WS_CAPTION 0x00C00000L /*WS_BORDER|WS_DLGFRAME */ 2443 #define WS_BORDER 0x00800000L

Windows coordination & position Width 150 Point A Left top (30, 30) Height 150 Point B Right bottom (180, 180)

Windows coordination & position

CCreateDemoView 예제를 스스로 만들어 봅시다. 실습문제 CCreateDemoView 예제를 스스로 만들어 봅시다. 2. 책의 예제와 동일하게 뷰 클래스에 CWnd 클래스 객체를 멤버로 선언하고 윈도우를 생성합니다. 생성할 윈도우의 클래스는 CButton 클래스로 하고 왼쪽 위의 좌표가 (50, 50)이고 폭과 높이는 각각 200, 100이 되도록 합시다. 3. 2번 실습이 끝났으면 새로운 CWnd 클래스 객체의 멤버를 뷰 클래스에 선언하여 CEdit 클래스를 가진 새로운 자식 윈도우를 생성해 봅시다. 그래서 뷰(View) 화면에 두 개의 자식 윈도우가 나타나도록 해봅시다. 4. 두 자식 윈도우 중 한 윈도우의 부모 윈도우를 바탕 화면이 되도록 코드를 추가해 봅시다.

Chapter 3 MFC UI framework basic

SDI Framework CMainFrame Top frame window Menu CMainFrame window CToolBar m_wndToolBar (CMainFrame class member) CCreateDemoView Default view window CStatusBar m_wndStatusBar (CMainFrame class member) CWnd m_wndChild (CCreateDemoView class member)

SDI Framework CCreateDemoApp CMainFrame m_wndToolBar m_wndToolBar Child & member CMainFrame m_wndToolBar m_wndToolBar Child CCreateDemoView CCreateDemoDoc Child & member m_wndChild

SDI Framework CFrameWnd CView CWinApp theApp CDocument AfxGetMainWnd() CFrameWnd::GetActiveView() CFrameWnd CWndThread::m_pMainWnd CMainFrame CFrameWnd:: GetActiveDocument() CWnd::GetParentFrame() AfxGetApp() CView CWinApp CSdiDemoVew CSdiDemoApp theApp CDocument::m_viewList.GetHead() CDocument CSdiDemoDoc CView::GetDocument()

Single Document Interface 76 77 // 응용 프로그램의 문서 템플릿을 등록합니다. 문서 템플릿은 78 // 문서, 프레임 창 및 뷰 사이의 연결 역할을 합니다. 79 CSingleDocTemplate* pDocTemplate; 80 pDocTemplate = new CSingleDocTemplate( 81 IDR_MAINFRAME, 82 RUNTIME_CLASS(CCreateDemoDoc), 83 RUNTIME_CLASS(CMainFrame), // 주 SDI 프레임 창입니다. 84 RUNTIME_CLASS(CCreateDemoView)); 85 if(!pDocTemplate) 86 return FALSE; 87 AddDocTemplate(pDocTemplate);

Single Document Interface CObject CCmdTarget CWinThread CWinApp

CWinApp 멤버 변수 기능 m_hInstance 현재 응용 프로그램의 인스턴스 핸들입니다. WinMain( ) 함수의 첫 번째 파라미터인 hInstance와 같은 것입니다. m_lpCmdLine WinMain( ) 함수의 lpCmdLine 파라미터와 같은 것입니다. 프로그램을 실행하였을 때 명령줄(Command-line) 정보가 들어 있습니다. m_nCmdShow WinMain( ) 함수의 마지막 파라미터인 nCmdShow와 같은 것입니다. m_pActiveWnd 응용 프로그램의 최상위 프레임 윈도우에 대한 포인터입니다. SDI 구조에서 이 값은 CMainFrame 클래스 객체의 포인터입니다. m_pszAppName 응용 프로그램의 제목에 해당하는 문자열의 포인터입니다. CreateDemo 예제의 경우 이 값이 CreateDemo였습니다. 문자열의 좀더 정확한 정보는 문자열 테이블(String Table)에 들어 있는 AFX_IDS_APP_TITLE에 해당하는 값입니다. m_pszExeName 빌드한 실행 파일에서 확장자( .exe)를 제외한 파일명입니다.

CreateDemo 46 BOOL CCreateDemoApp::InitInstance( ) 47 { 47 { 48 // 응용 프로그램 매니페스트가 ComCtl32.dll 버전6 이상을 사용하여 비주얼 스타일을 49 // 사용하도록 지정하는 경우, Windows XP 상에서 반드시 InitCommonControlsEx( )가 필요합니다. 50 // InitCommonControlsEx( )를 사용하지 않으면 창을 만들 수 없습니다. 51 INITCOMMONCONTROLSEX InitCtrls; 52 InitCtrls.dwSize = sizeof(InitCtrls); 53 // 응용 프로그램에서 사용할 모든 공용 컨트롤 클래스를 포함하도록 54 // 이 항목을 설정하십시오. 55 InitCtrls.dwICC = ICC_WIN95_CLASSES; 56 InitCommonControlsEx(&InitCtrls); 57 58 CWinApp::InitInstance( ); 59

CFrameWnd CObject CCmdTarget CWnd CFrameWnd

CFrameWnd & Control bar windows Menubar window Toolbar windows Controlbar windows

CreateDemo 41 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 42 { 43 if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 44 return -1; 45 46 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 47 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) 48 { 49 TRACE0("도구 모음을 만들지 못했습니다.\n"); 50 return -1; // fail to create 51 } 52 59 60 // TODO: 도구 모음을 도킹할 수 없게 하려면 이 세 줄을 삭제하십시오. 61 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); 62 EnableDocking(CBRS_ALIGN_ANY); 63 DockControlBar(&m_wndToolBar); 64 65 66 return 0; 67

CDocument CObject CCmdTarget CDocument

35 BOOL CCreateDemoDoc::OnNewDocument( ) 36 { CDocument 35 BOOL CCreateDemoDoc::OnNewDocument( ) 36 { 37 if (!CDocument::OnNewDocument( )) 38 return FALSE; 39 40 // TODO: 여기에 재초기화 코드를 추가합니다. 41 // SDI 문서는 이 문서를 다시 사용합니다. 42 43 return TRUE; 44 } 45

HelloSdi 35 BOOL CHelloSdiDoc::OnNewDocument( ) 36 { 36 { 37 if (!CDocument::OnNewDocument( )) 38 return FALSE; 39 40 reinterpret_cast<CEditView*>(m_viewList.GetHead( ))->SetWindowText(NULL); 41 42 AfxMessageBox(TEXT("새로운 빈 문서를 열었습니다.")); 43 44 return TRUE; 45 } 46

HelloSdi 74 //ChellosdiDoc 명령 75 76 BOOL CHelloSdiDoc::OnOpenDocument(LPCTSTR lpszPathName) 77 { 78 if (!CDocument::OnOpenDocument(lpszPathName)) 79 return FALSE; 80 81 AfxMessageBox(TEXT("사용자가 문서를 열었습니다.")); 82 83 return TRUE; 84 } 85

HelloSdi 35 BOOL CHelloSdiDoc::OnNewDocument( ) 36 { 36 { 37 if (!CDocument::OnNewDocument( )) 38 return FALSE; 39 40 reinterpret_cast<CEditView*>(m_viewList.GetHead( ))->SetWindowText(NULL); 41 42 // AfxMessageBox(TEXT("새로운 빈 문서를 열었습니다.")); 43 SetModifiedFlag(TRUE); 44 45 return TRUE; 46 } 47

Message map 14 // CMainFrame 15 16 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) 17 18 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 19 ON_WM_CREATE( ) 20 ON_WM_CLOSE( ) 21 END_MESSAGE_MAP( ) 22 94 95 // CMainFrame 메시지 처리기 96 97 void CMainFrame::OnClose( ) 98 { 99 AfxMessageBox(TEXT("WM_CLOSE 발생")); 100 CFrameWnd::OnClose( ); 101 } 102

실습문제 임의의 SDI 프로젝트를 만들고 CDocument 클래스에 OnOpenDocument( ), OnCloseDocument( ) 가상 함수를 재정의해 봅시다. 재정의한 함수에 AfxMessageBox( ) 함수를 이용하여 임의의 메시지 상자를 출력하도록 해봅시다. CMainFrame 클래스의 코드를 수정하여 도구 모음과 상태 표시줄을 제거해 봅시다. 응용 프로그램의 자체 객체(CWinApp 클래스를 상속받은 클래스)에 ExitInstance( ) 함수를 재정의하여 등록해 봅시다. char*형의 전역 변수를 선언하고 InitInstance( ) 함수에서 이 변수에 256바이트 길이의 메모리를 할당한 후 임의의 문자열을 저장하도록 하고 ExitInstance( ) 함수에서 메모리를 해제하도록 해봅시다. 5번 실습을 마친 상태에서 메인 프레임 윈도우가 화면에 나타나기 전에 문자열을 메시지 상자를 이용해서 출력해 봅시다. 너무나 다양한 곳에 코딩이 가능하겠지만 어디가 적합한 위치인지 스스로 고민해서 코딩해봅시다.

Chapter 4 MFC SDI application flow

01: Function: CSdiSeqApp::CSdiSeqApp( ) Initialization 01: Function: CSdiSeqApp::CSdiSeqApp( ) 02: Function: CSdiSeqApp::InitInstance( ) 03: Function: CSdiSeqDoc::CSdiSeqDoc(void) 04: Function: CMainFrame::CMainFrame(void) 05: Function: CMainFrame::LoadFrame( ) 06: Function: CMainFrame::PreCreateWindow( ) 07: Function: CMainFrame::PreCreateWindow( ) 08: Function: CMainFrame::OnCreate( ) 09: Function: CMainFrame::OnCreateClient( ) 10: Function: CSdiSeqView::CSdiSeqView( ) 11: Function: CSdiSeqView::Create( ) 12: Function: CSdiSeqView::PreCreateWindow( ) 13: Function: CSdiSeqView::OnCreate( ) 14: Function: CSdiSeqView::OnShowWindow( ) 15: CMainFrame::OnCreateClient( ) - Return 16: CMainFrame::OnCreate( ) - Return

17: Function: CSdiSeqDoc::OnNewDocument( ) Initialization & Run 17: Function: CSdiSeqDoc::OnNewDocument( ) 18: Function: CSdiSeqView::OnInitialUpdate( ) 19: Function: CMainFrame::OnActivateApp( ) 20: Function: CMainFrame::OnActivate( ) 21: Function: CMainFrame::OnShowWindow( ) 22: Function: CSdiSeqView::GetDocument( ) 23: Function: CSdiSeqApp::Run( )

24: Function: CMainFrame::OnClose( ) Close & Destruction 24: Function: CMainFrame::OnClose( ) 25: Function: CMainFrame::OnShowWindow( ) 26: Function: CMainFrame::OnActivate( ) 27: Function: CMainFrame::OnActivateApp( ) 28: Function: CMainFrame::DestroyWindow( ) 29: Function: CMainFrame::OnDestroy( ) 30: Function: CSdiSeqView::OnDestroy( ) 31: Function: CSdiSeqView::PostNcDestroy( ) 32: Function: CSdiSeqView::~CSdiSeqView( ) 33: Function: CMainFrame::OnNcDestroy( ) 34: Function: CMainFrame::PostNcDestroy( ) 35: Function: CMainFrame::~CMainFrame( ) 36: CMainFrame::OnNcDestroy( ) - Return 37: Function: CSdiSeqDoc::~CSdiSeqDoc( ) 38: CMainFrame::OnClose( ) - Return 39: Function: CSdiSeqApp::ExitInstance( ) 40: CSdiSeqApp::Run( ) - Return

Window area Client view window Client area Non-client area Frame window Client area Non-client area

Window message processing Message queue PostMessage() 2 1 A B C D SendMessage() Message loop CMainFrame 3 CMainFrame::PreTranslateMessage() 4 CMainFrame::WindowProc() 5 CMainFrame message handler function

Chapter 5 Keyboard & Message

WM_KEYDOWN & OnKeyDown() 115 116 void CKeyMoveView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 117 { 118 CPoint ptChild; //차일드 윈도우의 좌표. 119 CRect Rect; //차일드 윈도우의 좌표 및 크기. 120 121 //차일드 윈도우의 두 좌표 정보(스크린 기준)를 알아 온다. 122 m_wndChild.GetWindowRect(&Rect); 123 ptChild.x = Rect.left; 124 ptChild.y = Rect.top; 125 126 //스크린 기준 좌표를 클라이언트 뷰 기준의 좌표로 환산한다. 127 ScreenToClient(&ptChild); 128 129 switch(nChar) 130 { 131 case VK_LEFT: //왼쪽 화살표를 누른 경우. 132 ptChild.x -= 10; //10픽셀만큼 x좌표 값 감소. 133 break; 134

WM_KEYDOWN & OnKeyDown() 135 case VK_RIGHT: //오른쪽 화살표를 누른 경우. 136 ptChild.x += 10; //10픽셀만큼 x좌표 값 증가. 137 break; 138 } 139 140 //변경된 새 좌표로 차일드 윈도우를 이동시킨다. 141 m_wndChild.SetWindowPos(&CWnd::wndTop, ptChild.x, ptChild.y, 0, 0, 142 SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOSIZE); 143 144 CView::OnKeyDown(nChar, nRepCnt, nFlags); 145 } 146

Virtual key code 372 /* 373 * Virtual Keys, Standard Set 374 */ 372 /* 373 * Virtual Keys, Standard Set 374 */ 375 #define VK_LBUTTON 0x01 376 #define VK_RBUTTON 0x02 377 #define VK_CANCEL 0x03 378 #define VK_MBUTTON 0x04 /* NOT contiguous with L & RBUTTON */ 379 380 #if(_WIN32_WINNT >= 0x0500) 381 #define VK_XBUTTON1 0x05 /* NOT contiguous with L & RBUTTON */ 382 #define VK_XBUTTON2 0x06 /* NOT contiguous with L & RBUTTON */ 383 #endif /* _WIN32_WINNT >= 0x0500 */ 384

OnKeyDown() VK_RIGHT VK_NUMPAD6 VK_RIGHT + Control key + Alt key Transition code Previous key state Context code Extended Key VK_RIGHT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 OS Not use Scan code 0x01 0x4D VK_NUMPAD6 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 OS Not use Scan code 0x00 0x4D VK_RIGHT + Control key + Alt key 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 OS Not use Scan code 0x21 0x4D

Window coordination X Axis Y Axis A (0, 0) Y = 150 Y = 250 Y = 350 B C X = 300 X = 400 D VK_LEFT VK_RIGHT Y Axis

KeyMove 117 void CKeyMoveView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 118 { 119 CPoint ptChild; //차일드 윈도우의 좌표 120 CRect Rect; //차일드 윈도우의 좌표 및 크기 121 122 //차일드 윈도우의 두 좌표 정보(스크린 기준)를 알아 온다. 123 m_wndChild.GetWindowRect(&Rect); 124 ptChild.x = Rect.left; 125 ptChild.y = Rect.top; 126

KeyMove 126 127 //스크린 기준 좌표를 클라이언트 뷰 기준의 좌표로 환산한다. 127 //스크린 기준 좌표를 클라이언트 뷰 기준의 좌표로 환산한다. 128 ScreenToClient(&ptChild); 129 130 switch(nChar) 131 { 132 case VK_LEFT: //왼쪽 화살표를 누른 경우 133 ptChild.x -= 10; //10픽셀만큼 X좌표 값 감소 134 break; 135 136 case VK_RIGHT: //오른쪽 화살표를 누른 경우. 137 ptChild.x += 10; //10픽셀만큼 X좌표 값 증가 138 break; 139 } 140 141 //변경된 새 좌표로 차일드 윈도우를 이동시킨다. 142 m_wndChild.SetWindowPos(&CWnd::wndTop, ptChild.x, ptChild.y, 0, 0, 143 SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOSIZE); 144

const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags ::SetWindowPos() BOOL SetWindowPos( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags ); 값 의미 wndBottom Z-order를 최하위로 합니다. wndTop Z-order를 최상위로 합니다. wndTopMost Z-order를 최상위로 하고 시스템 윈도우 속성을 갖습니다. wndNoTopMost 일반 윈도우 중 최상위 윈도우가 되도록 합니다. 값 의미 SWP_HIDEWINDOW 윈도우가 화면에서 사라지도록 합니다. SWP_SHOWWINDOW 윈도우가 화면에 보이도록 합니다. SWP_NOACTIVATE 윈도우를 활성화하지 않습니다. SWP_NOMOVE 윈도우의 위치를 변경하지 않습니다. (x, y 무시) SWP_NOREDRAW 윈도우를 다시 그리지 않습니다. SWP_NOSIZE 윈도우의 크기를 변경하지 않습니다. (cx, cy 무시) SWP_NOZORDER 윈도우의 Z-order를 변경하지 않습니다. (pWndInsertAfter 무시)

KeyMove 151 void CKeyMoveView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 152 { 153 CString strText = TEXT(""); 154 strText.Format(TEXT("%c"), nChar); 155 156 //입력한 키가 Enter, Back Space, ESC 키가 아니면 157 //해당 ASCII 문자로 차일드 윈도우 텍스트를 변경한다. 158 if(nChar != VK_RETURN && nChar != VK_BACK && nChar != VK_ESCAPE) 159 { 160 m_wndChild.SetWindowText(strText); 161 } 162 163 CView::OnChar(nChar, nRepCnt, nFlags); 164 } 165

KeyMove 165 166 void CKeyMoveView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 167 { 168 CString strMessage = TEXT(""); 169 171 WORD wResult = ::GetKeyState(VK_SPACE); 172 BYTE byHigh = HIBYTE(wResult); 174 if(byHigh & 0x01) 175 { 176 strMessage += TEXT("Alt + Space, "); 179 wResult = ::GetKeyState(VK_CAPITAL); 180 //하위 바이트의 1번 비트가 1이면 토글 키가 켜진 상태 181 BYTE byLow = LOBYTE(wResult); 182 if(byLow & 0x01) strMessage += TEXT("CAPS LOCK ON"); 183 else strMessage += TEXT("CAPS LOCK OFF"); 184 185 AfxMessageBox(strMessage); 186 } 187 188 CView::OnSysKeyDown(nChar, nRepCnt, nFlags); 189 } 190

KeyMove 191 void CKeyMoveView::OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags) 192 { 193 if(nChar == VK_RETURN) 194 AfxMessageBox(TEXT("Alt + Enter")); 195 else if(nChar == 's' || nChar == 'S') 196 AfxMessageBox(TEXT("Alt + S")); 197 else if(nChar == 'x' || nChar == 'X') 198 AfxMessageBox(TEXT("Alt + X")); 199 200 CView::OnSysChar(nChar, nRepCnt, nFlags); 201 } 202

KeyMove 예제에서 자식 윈도우가 위아래로 이동할 수 있도록 코드를 추가해 봅시다. 실습안내 KeyMove 예제에서 자식 윈도우가 위아래로 이동할 수 있도록 코드를 추가해 봅시다. 2. KeyMove 예제를 수정하여 Control 키와 방향키를 함께 눌렀을 때는 윈도우의 이동 폭이 더 커지도록 해봅시다. 3. KeyMove 예제를 응용하여 방향키를 누르면 자식 윈도우의 위치가 바뀌는 것이 아니라 윈도우의 크기가 커지거나 작아지도록 해봅시다. 4. [Alt + F4] 키를 누르면 WM_CLOSE 메시지가 발생하고 프로그램이 종료됩니다. 유사하게 [Alt + X] 키를 누르면 프로그램을 종료하도록 예제를 작성해 봅시다.

Chapter 6 Mouse & Message

MouseMsg 100 // CmouseMsgView 메시지 처리기 101 102 void CMouseMsgView::OnPaint( ) 103 { 104 CPaintDC dc(this); // device context for painting 105 106 CString strData = _T(""); 107 strData.Format(_T("X:%03d, Y:%03d"), m_ptMouse.x, m_ptMouse.y); 108 109 dc.TextOut(10, 10, strData); 110 } 111 112 113 void CMouseMsgView::OnMouseMove(UINT nFlags, CPoint point) 114 { 115 m_ptMouse = point; 116 RedrawWindow( ); 117 118 CView::OnMouseMove(nFlags, point); 119 } 120

MouseMsg 155 156 BOOL CMouseMsgView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 157 { 158 CString strTmp = _T(""); 159 strTmp.Format(TEXT("OnMouseWheel( ) zDelta : %d\n"), zDelta); 160 TRACE(strTmp); 161 162 return CView::OnMouseWheel(nFlags, zDelta, pt); 163 } 164

MouseCombi – Click vs Double click

MouseCombi 106 107 void CMouseCombiView::OnLButtonDown(UINT nFlags, CPoint point) 108 { 109 // m_ptItemText 값을 기준으로 64픽셀 내에서 110 // 마우스 왼쪽 버튼이 클릭된 것인가? 111 if(point.x >= m_ptItemText.x - 32 && 112 point.x <= m_ptItemText.x + 32 && 113 point.y >= m_ptItemText.y - 32 && 114 point.y <= m_ptItemText.y + 32) 115 { 116 m_bDragFlag = true; 117 RedrawWindow( ); 118 } 119 120 CView::OnLButtonDown(nFlags, point); 121 } 122

MouseCombi 122 123 void CMouseCombiView::OnLButtonUp(UINT nFlags, CPoint point) 124 { 125 // 드래그 중이었는가? 126 if(m_bDragFlag) 127 { 128 // 버튼에서 손을 뗐으므로 드래그가 끝났다고 판단한다. 129 m_bDragFlag = false; 130 // 드래그가 끝난 이 좌표가 드롭된 좌표이다. 131 m_ptItemText = point; 132 RedrawWindow( ); 133 } 134 135 CView::OnLButtonUp(nFlags, point); 136 } 137

MouseCombi 154 155 void CMouseCombiView::OnMouseMove(UINT nFlags, CPoint point) 156 { 157 if(m_bDragFlag) 158 { 159 //드래그 중인 좌표로 아이템 텍스트를 이동시켜 출력한다. 160 m_ptItemText = point; 161 RedrawWindow( ); 162 } 163 164 CView::OnMouseMove(nFlags, point); 165 } 166

MouseCombi

MouseCombi 32 33 void CTrackWnd::OnMouseMove(UINT nFlags, CPoint point) 34 { 35 if(m_bTrack == FALSE) 36 { 37 TRACKMOUSEEVENT MouseEvent; 38 ::ZeroMemory(&MouseEvent, sizeof(MouseEvent)); 39 40 MouseEvent.cbSize = sizeof(MouseEvent); 41 MouseEvent.dwFlags = TME_LEAVE; 42 MouseEvent.hwndTrack = m_hWnd; 43 MouseEvent.dwHoverTime = 0; 44 45 m_bTrack = ::_TrackMouseEvent(&MouseEvent); 46 if(m_bTrack) 47 { 48 SetWindowText(TEXT("Tracking!")); 49 } 50 } 51 52 CWnd::OnMouseMove(nFlags, point); 53 } 54

MouseCombi 55 56 void CTrackWnd::OnMouseLeave( ) 57 { 57 { 58 TRACKMOUSEEVENT MouseEvent; 59 ::ZeroMemory(&MouseEvent, sizeof(MouseEvent)); 60 61 MouseEvent.cbSize = sizeof(MouseEvent); 62 MouseEvent.dwFlags = TME_CANCEL; 63 MouseEvent.hwndTrack = m_hWnd; 64 65 ::_TrackMouseEvent(&MouseEvent); 66 67 m_bTrack = FALSE; 68 SetWindowText(TEXT("WM_MOUSELEAVE")); 69 70 CWnd::OnMouseLeave( ); 71 } 72

실습안내 1. MouseCombi 예제를 개선하여 클라이언트 뷰 윈도우 영역 밖으로 드래그를 할 수 없도록 코드를 수정해 봅시다.   2. MouseCombi 예제의 클라이언트 뷰 클래스에 CTrackWnd 클래스처럼 마우스 이벤트를 추적하는 코드를 추가해 봅시다. 3. CWnd 클래스의 WindowFromPoint( ) 멤버 함수에 대해 알아보고 MouseCombi 예제에 새로운 기능을 추가하여 다른 윈도우의 핸들을 알아내는 코드를 추가해 봅시다. 참고로 이런 기능은 ShowMeToLoop 예제에서 이미 구현한 것입니다.

Chapter 7 Graphics Device Interface basic

GDI & DC Application GetDC() ReleaseDC() GDI 32 User mode DirectX Kernel mode Graphics Engine (GDI) VGA Driver Printer Driver

GDI & DC Redraw area

WM_PAINT & Redarw

WM_PAINT & OnPaint() 115 116 void CRedrawDemoView::OnPaint( ) 117 { 117 { 118 CPaintDC dc(this); // device context for painting 119 120 dc.Rectangle(120, 10, 220, 110); 121 } 122

WM_PAINT & OnPaint() 파생 클래스 의미 CClientDC 윈도우의 클라이언트 영역으로 한정되는 DC입니다. CWindowDC 윈도우의 모든 영역(비클라이언트 영역 포함)에 대한 DC입니다. 이 DC를 이용하면 다른 윈도우에 대해서 그리기가 가능합니다. CPaintDC CClientDC 클래스와 유사하지만, 내부적으로 BeginPaint( )/EndPaint( ) 함수를 호출하여 WM_ERASEBKGND 메시지가 발생한다는 것이 다릅니다. CMetaFileDC WMF(Window Meta File), EMF(Enhanced Meta File) 파일에 대한 DC입니다.

WM_PAINT & OnPaint() 115 116 void CRedrawDemoView::OnPaint( ) 117 { 117 { 118 CPaintDC dc(this); // device context for painting 119 120 // 두께가 3픽셀인 붉은 색 펜을 생성한다. 121 CPen NewPen(PS_SOLID, 3, RGB(192, 0, 0)); 122 // 생성한 펜을 DC의 현재 펜으로 변경하고 기존 펜 객체에 대한 123 // 포인터를 별도로 저장해둔다. 124 CPen* pOldPen = dc.SelectObject(&NewPen); 125 126 // 그리기 작업을 수행한다. 127 dc.Rectangle(120, 10, 220, 110); 128 129 // 예전 펜을 현재 펜으로 바꾼다. 130 dc.SelectObject(pOldPen); 131 } 132

MoveTo() / LineTo() 100 101 // CPenBrushDemoView 102 103 void CPenBrushDemoView::OnPaint( ) 104 { 105 CPaintDC dc(this); // device context for painting 106 107 CPen NewPen(PS_SOLID, 20, RGB(192, 192, 192); 108 CPen* pOldPen = dc.SelectObject(&NewPen); 109 110 // 두께가 20픽셀인 선을 긋는다. 111 dc.MoveTo(40, 40); // 시작 좌표 112 dc.LineTo(240, 40); // 끝 좌표 113 114 dc.SelectObject(pOldPen); 115 116 // 본래의 펜(두께1, 검정)으로 동일한 선을 겹쳐 긋는다. 117 dc.MoveTo(40, 40); // 시작 좌표 118 dc.LineTo(240, 40); // 끝 좌표 119 } 120

CPen A (40, 40) B (240, 40)

CPen 값 의미 PS_SOLID 일반 실선입니다. PS_DASH 대시(Dash)를 점선처럼 열거합니다. PS_DOT 점선. PS_DASHDOT 대시와 점 한 번씩을 번갈아서 출력합니다. PS_DASHDOTDOT 대시 한 번에 점을 두 번을 번갈아서 출력합니다. PS_INSIDEFRAME 도형을 그릴 때 두꺼운 펜(2픽셀 이상)이 도형의 경계 좌표를 벗어나지 않도록 합니다. (다음 절 각종 도형 그리기에 자세한 코드 예가 있습니다.) PS_NULL 투명한 선을 긋습니다. 따라서 화면에는 아무것도 보이지 않습니다. 도형을 그릴 때 테두리를 없애기 위해 의도적으로 사용하기도 합니다.

Geometric pen 101 // CpenBrushDemoView 메시지 처리기 102 103 void CPenBrushDemoView::OnPaint( ) 104 { 105 CPaintDC dc(this); // device context for painting 106 107 LOGBRUSH lb; 108 lb.lbStyle = BS_SOLID; 109 lb.lbColor = RGB(192, 192, 192); 110 111 CPen arNewPen[3]; 112 CPen* pOldPen = NULL; 113 arNewPen[0].CreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND, 20, &lb); 114 arNewPen[1].CreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE, 20, &lb); 115 arNewPen[2].CreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, 20, &lb); 116

Geometric pen 101 // CPenBrushDemoView 메시지 처리기 102 103 void CPenBrushDemoView::OnPaint( ) 104 { 105 CPaintDC dc(this); // device context for painting 106 // PS_USERSTYLE 예 107 DWORD style[] = {6, 3}; 108 LOGBRUSH lb; 109 lb.lbStyle = BS_SOLID; 110 lb.lbColor = RGB(255, 0, 0); 111 112 CPen NewPen; 113 NewPen.CreatePen(PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT, 114 10, &lb, 2, style); 115 CPen* pOldPen = dc.SelectObject(&NewPen); 116 117 // 두께가 20픽셀인 선을 긋는다. 118 dc.MoveTo(40, 40); // 시작 좌표 119 dc.LineTo(240, 40); // 끝 좌표 120 121 dc.SelectObject(pOldPen); 122 } 123

Geometric pen

Hatch brush 101 // CPenBrushDemoView 메시지 처리기 102 103 void CPenBrushDemoView::OnPaint( ) 104 { 105 CPaintDC dc(this); // device context for painting 106 107 CBrush NewBrush(HS_CROSS, RGB(192, 0, 0)); 108 CBrush* pOldBrush = dc.SelectObject(&NewBrush); 109 110 dc.Rectangle(20, 20, 140, 140); 111 112 dc.SelectObject(pOldBrush); 113 } 114

Bitmap brush 101 // CPenBrushDemoView 메시지 처리기 102 103 void CPenBrushDemoView::OnPaint( ) 104 { 105 CPaintDC dc(this); // device context for painting 106 107 CBrush NewBrush; 108 // 비트맵 클래스 객체를 선언하여 비트맵 리소스 로딩 109 CBitmap Bmp; 110 Bmp.LoadBitmap(IDB_BITMAP1); 111 // 로딩된 비트맵 리소스로 패턴 브러시 생성. 112 NewBrush.CreatePatternBrush(&Bmp); 113 CBrush* pOldBrush = dc.SelectObject(&NewBrush); 114 115 // 클라이언트 뷰 클래스의 클라이언트 영역 크기를 알아내고 116 // 크기에 해당하는 네모를 그림. 117 CRect Rect; 118 GetClientRect(&Rect); 119 dc.Rectangle(&Rect); 120 121 dc.SelectObject(pOldBrush); 122 } 123

TriangleDemo A Z C B

TriangleDemo 스타일 결과 화면 PS_JOIN_BEVEL PS_JOIN_ROUND PS_JOIN_MITER

TriangleDemo S (PieRect.CenterPoint().x, 20) A (20, 20) 270º E (140, PieRect.CenterPoint().y) PieRect.CenterPoint() S’ (PieRect.CenterPoint().x, 140) B (140, 140)

실습안내 1. 전형적인 SDI 형식의 예제를 생성하여 크기가 120 * 120인 정사각형을 화면에 출력하는 코드를 작성해 봅시다.   2. 앞에서 작성한 사각형의 테두리를 3픽셀의 붉은색으로 하고 내부는 회색으로 칠하도록 코드를 추가합시다. 3. 임의의 육각형을 출력하는 코드를 작성해 봅시다. 4. 다음 그림은 MSN 메신저 화면입니다. 클라이언트 뷰 영역을 보면 모서리가 둥근 형태입니다. 이와 같은 모양을 구현하되 RoundRect( ) 함수를 사용하지 않고 구현해 봅시다.

Font

LOGFONT 1197 typedef struct tagLOGFONTW 1198 { 1199 LONG lfHeight; 1198 { 1199 LONG lfHeight; 1200 LONG lfWidth; 1201 LONG lfEscapement; 1202 LONG lfOrientation; 1203 LONG lfWeight; 1204 BYTE lfItalic; 1205 BYTE lfUnderline; 1206 BYTE lfStrikeOut; 1207 BYTE lfCharSet; 1208 BYTE lfOutPrecision; 1209 BYTE lfClipPrecision; 1210 BYTE lfQuality; 1211 BYTE lfPitchAndFamily; 1212 WCHAR lfFaceName[LF_FACESIZE]; 1213 } LOGFONTW, *PLOGFONTW, NEAR *NPLOGFONTW, FAR *LPLOGFONTW; 1214 #ifdef UNICODE 1215 typedef LOGFONTW LOGFONT;

TabbedTextOut() Tab size : 40 Tab size : 40 * 2 CSize (244, 36)

VirtualButton

VirtualButton 100 101 // CVirtualButtonView 메시지 처리기 102 103 void CVirtualButtonView::OnLButtonDown(UINT nFlags, CPoint point) 104 { 105 // 버튼이 위치한 영역을 클릭하였는가? 106 if(m_BtnRect.PtInRect(point)) 107 { 108 // 플래그를 토글하고 윈도우를 다시 그린다. 109 m_bClicked = !m_bClicked; 110 RedrawWindow(&m_BtnRect); 111 } 112 113 CView::OnLButtonDown(nFlags, point); 114 } 115

VirtualButton 116 117 void CVirtualButtonView::OnLButtonUp(UINT nFlags, CPoint point) 118 { 119 // 버튼이 위치한 영역인가? 120 if(m_bClicked) 121 { 122 // 플래그를 토글하고 윈도우를 다시 그린다. 123 m_bClicked = !m_bClicked; 124 RedrawWindow(&m_BtnRect); 125 } 126 127 if(m_BtnRect.PtInRect(point)) 128 { 129 AfxMessageBox(L"버튼을 클릭했습니다."); 130 } 131 132 CView::OnLButtonUp(nFlags, point); 133 } 134

VirtualButton 135 136 void CVirtualButtonView::OnPaint( ) 137 { 137 { 138 CPaintDC dc(this); // device context for painting 139 // 시스템이 정의한 버튼 색상으로 버튼의 영역을 칠한다. 140 CRect Rect(m_BtnRect); 141 Rect += CRect(1, 1, 1, 1); 142 dc.Rectangle(&Rect); 143 dc.FillSolidRect(&m_BtnRect, ::GetSysColor(COLOR_BTNFACE)); 144 145 if(m_bClicked) // 눌려진 상태 146 { 147 dc.Draw3dRect(m_BtnRect, 148 ::GetSysColor(COLOR_3DSHADOW), // 왼쪽/위쪽이 어두운 색 149 ::GetSysColor(COLOR_3DLIGHT)); // 오른쪽/아래쪽이 밝은 색 150 } 151 else // 평상시 상태 152 { 153 dc.Draw3dRect(m_BtnRect, 154 ::GetSysColor(COLOR_3DLIGHT), 155 ::GetSysColor(COLOR_3DSHADOW)); 156 }

VirtualButton 157 158 // 시스템이 정하는 버튼 관련 색상으로 텍스트를 그린다. 158 // 시스템이 정하는 버튼 관련 색상으로 텍스트를 그린다. 159 dc.SetBkColor(::GetSysColor(COLOR_BTNFACE)); 160 dc.SetTextColor(::GetSysColor(COLOR_BTNTEXT)); 161 162 if(m_bClicked) 163 { 164 CRect Rect = m_BtnRect; 165 // 눌려진 상태면 글씨가 출력되는 위치를 1픽셀 조절한다. 166 Rect += CRect(0, 0, 2, 2); 167 dc.DrawText(L"Test button", &Rect, 168 DT_CENTER | DT_SINGLELINE | DT_VCENTER); 169 } 170 else 171 { 172 dc.DrawText(L"Test button", &m_BtnRect, 173 DT_CENTER | DT_SINGLELINE | DT_VCENTER); 174 } 175 } 176

VirtualButton – Draw3dRect() COLOR_3DSHADOW COLOR_3DLIGHT

실습안내 1. “\t이것은 실습을 위한\n문자열입니다.”라는 문자열을 TextOut( ), TabbedTextOut, DrawText( ) 함수를 이용하여 각각 출력하는 예제를 작성해 봅시다.   2. 1번 문자열을 출력할 때 이탤릭(Italic), 굵게(Bold), 밑줄이 들어가도록 글꼴을 변경해 봅시다. 3. 다음 버튼은 전형적인 윈도우 XP 스타일의 버튼 컨트롤입니다. VirtualButton 예제의 코드를 수정하여 다음과 같은 모양을 하도록 수정해 봅시다. 4. 바탕 화면이나 윈도우 탐색기의 파일 목록처럼 뷰(View) 영역을 선택(드래그)하면 해당 영역을 회색으로 채우고 그 중앙에 자신의 이름을 출력하는 예제를 작성해 봅시다. 참고로 3, 4번은 난이도가 비교적 높으므로 시간을 갖고 천천히 코드를 작성하기 바랍니다.

Chapter 8 Bitmap & Handling of image file

One pixel ( 4/8/16/24/32 bits RGB Color) Bitmap image 48 pixels 48 X 48 24 bits bitmap 48 pixels One pixel ( 4/8/16/24/32 bits RGB Color)

BmpDisplayDemo 103 void CBmpDisplayDemoView::OnPaint( ) 103 { 103 { 104 CPaintDC dc(this); // device context for painting 105 106 CDC MemDC; 107 BITMAP bmpInfo; 108 // 화면 DC와 호환되는 메모리 DC를 생성한다. 109 MemDC.CreateCompatibleDC(&dc); 110 // 비트맵 리소스를 로딩한다. 111 CBitmap bmp; 112 CBitmap* pOldBmp = NULL; 113 bmp.LoadBitmap(IDB_Test_Image); 114 // 로딩된 비트맵의 정보를 알아본다. 115 bmp.GetBitmap(&bmpInfo); 116 // 메모리 DC에 선택한다. 117 pOldBmp = MemDC.SelectObject(&bmp); 118 // 메모리 DC에 들어 있는 비트맵을 화면 DC로 복사하여 출력한다. 119 dc.BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, 120 &MemDC,0, 0, SRCCOPY); 121 122 MemDC.SelectObject(pOldBmp); 122 }

CDC::BitBlt() Memoy DC = CreateCompatibleDC( Display DC ) Memory DC Display DC 250 pixels S (350, 200) 250 pixels T (200, 200) 300 pixels 300 pixels dc.BitBlt(200, 200, 250, 300, &MemDC, 350, 200, SRCCOPY);

CDC::StretchBlt() Memory DC Display DC 250 pixels S (350, 200) &MemDC, 350, 200, 250, 300, SRCCOPY);

BmpDisplayDemo 117 118 dc.StretchBlt(20, 20, 119 bmpInfo.bmWidth * 2, bmpInfo.bmHeight * 2, 120 &MemDC, 121 0, 0, 122 bmpInfo.bmWidth, bmpInfo.bmHeight, 123 SRCCOPY); // 래스터 연산 값 124 125 //※마지막 인자를 제외하면 StretchBlt( ) 함수와 거의 동일 126 dc.TransparentBlt(20, 100, 127 bmpInfo.bmWidth * 2, bmpInfo.bmHeight * 2, 128 &MemDC, 129 0, 0, 130 bmpInfo.bmWidth, bmpInfo.bmHeight, 131 RGB(0, 0, 0)); // 투명 처리될 색상의 RGB 값 132 133 MemDC.SelectObject(pOldBmp); 134 } 135

BmpDisplayDemo

BmpDisplayDemo 125 //※마지막 인자를 제외하면 StretchBlt( ) 함수와 거의 동일 126 BLENDFUNCTION bf; 127 bf.BlendOp = AC_SRC_OVER; 128 bf.BlendFlags = 0; 129 bf.SourceConstantAlpha = 50; // 0: 투명255: 불투명 130 bf.AlphaFormat = 0; 131 // 반투명 이미지를 출력한다. 132 dc.AlphaBlend(20, 100, 133 bmpInfo.bmWidth * 2, bmpInfo.bmHeight * 2, 134 &MemDC, 135 0, 0, 136 bmpInfo.bmWidth, bmpInfo.bmHeight, 137 bf); // BLENDFUNCTION 구조체

Src.Red * (SCA/255.0) + Dst.Red * (1.0 - (SCA/255.0)) CDC::AlphaBlend() Source bitmap image Destination pixel Source pixel 24bits RGB( 192, 192, 192) 24bits RGB( 192, 0, 0) SAC(SourceConstantAlpha) = 50 New destination pixel Src.Red * (SCA/255.0) + Dst.Red * (1.0 - (SCA/255.0)) R (192) 192 * (50 / 255.0) + 192 * (1.0 – ( 50 / 255.0)) G (154) 0 * (50 / 255.0) + 192 * (1.0 – ( 50 / 255.0)) B (154) 0 * (50 / 255.0) + 192 * (1.0 – ( 50 / 255.0))

CDC::AlphaBlend() Opaque 48 pixels 48 pixels Transparent Alpha blend

ImgOutDemo 105 106 void CImgOutDemoView::OnPaint( ) 107 { 107 { 108 CPaintDC dc(this); // device context for painting 109 110 // 로드할 이미지 파일의 경로 111 CString strImagePath = _T("IMG_0076.jpg"); 112 // 이미지 파일을 로드 113 CImage Image; 114 HRESULT hResult = Image.Load(strImagePath); 115 if(FAILED(hResult)) 116 { 117 CString strtmp = _T("ERROR: Failed to load "); 118 strtmp += strImagePath + _T("\n"); 119 TRACE(strtmp); 120 return; 121 } 122 123 // 화면 DC에 출력 124 Image.BitBlt(dc.m_hDC, 0, 0); 125 } 126

ImgOutDemo 103 104 // CimgOutDemoView 메시지 처리기 105 106 void CImgOutDemoView::OnPaint( ) 107 { 108 CPaintDC dc(this); // device context for painting 109 110 CImage Image; 111 // 비트맵 리소스를 로드하여 출력한다. 112 Image.LoadFromResource(AfxGetInstanceHandle( ), IDB_Image_Test); 113 Image.BitBlt(dc.m_hDC, 0, 0); 114 } 115

ImgOutDemo 105 106 void CImgOutDemoView::OnPaint( ) 107 { 107 { 108 CPaintDC dc(this); // device context for painting 109 110 CImage Image; 111 // 비트맵 리소스를 로드하여 DIB를 만든다. 112 Image.LoadFromResource(AfxGetInstanceHandle( ), IDB_Image_Test); 113 114 // 비트맵 이미지에 대한 DC를 생성한다. 115 CDC* pDC = CDC::FromHandle(Image.GetDC( )); 116 // 이 이미지 DC에 문자열을 출력한다. 117 pDC->SetBkMode(TRANSPARENT); 118 pDC->TextOut(200, 30, TEXT("CImage sample!")); 119 Image.ReleaseDC( ); 120 121 // 이미지를 화면 DC에 출력한다. 122 Image.BitBlt(dc.m_hDC, 0, 0); 123 // 화면 DC에 문자열을 출력한다. 124 // dc.SetBkMode(TRANSPARENT); 125 // dc.TextOut(200, 30, TEXT("CImage sample!")); 126 } 127

CImage::BitBlt() - BOOL BitBlt(HDC hDestDC, int xDest, int yDest, DWORD dwROP = SRCCOPY) const throw( );   - BOOL BitBlt(HDC hDestDC, const POINT& pointDest, DWORD dwROP = SRCCOPY ) const throw( ); - BOOL BitBlt(HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, DWORD dwROP = SRCCOPY) const throw( ); - BOOL BitBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, DWORD dwROP = SRCCOPY ) const throw( );

Color space R C + Y M B G G B M Y C R RGB color CMYK color

SaveGrayDemo 300 300 200 300 200 300 Gray image

SaveGrayDemo 101 #endif //_DEBUG 102 103 inline void RGBtoGray(COLORREF& rgb) 104 { 105 BYTE byGray = (GetRValue(rgb) * 30 106 + GetGValue(rgb) * 59 107 + GetBValue(rgb) * 11) / 100; 108 109 rgb = RGB(byGray, byGray, byGray); 110 } 111

SaveGrayDemo 113 114 void CSaveGrayDemoView::OnLButtonDown(UINT nFlags, CPoint point) 115 { 116 // 바탕 화면 윈도우 객체에 대한 포인터를 얻음 117 CWnd* pWndDesktop = GetDesktopWindow( ); 118 CWindowDC ScrDC(pWndDesktop); // 바탕 화면 윈도우 DC 119 CClientDC dc(this); // 뷰 윈도우 DC 120 121 // 바탕 화면 크기 및 색상수와 동일한 비트맵 이미지를 만든다. 122 CImage Image; 123 Image.Create(300, 300, ScrDC.GetDeviceCaps(BITSPIXEL)); 124 125 // 이미지 DC와 화면 DC에 바탕 화면 윈도우 DC를 출력한다. 126 CDC* pDC = CDC::FromHandle(Image.GetDC( )); 127 pDC->BitBlt(0, 0, 300, 300, &ScrDC, 0, 0, SRCCOPY); 128 Image.ReleaseDC( ); 129

SaveGrayDemo 130 // 일부(200 * 200)를 흑백 이미지로 변환 131 COLORREF rgb; 130 // 일부(200 * 200)를 흑백 이미지로 변환 131 COLORREF rgb; 132 for(int x = 0; x < 200; x++) // 폭 133 { 134 for(int y = 0; y < 200; ++y) // 높이 135 { 136 rgb = Image.GetPixel(x, y); 137 // Gray RGB 값으로 변환 138 RGBtoGray(rgb); 139 Image.SetPixel(x, y, rgb); 140 } 141 } 142 143 // 흑백으로 변환된 이미지를 화면 DC에 출력 144 Image.BitBlt(dc.m_hDC, 0, 0); 145 146 CView::OnLButtonDown(nFlags, point); 147 } 148

SaveGrayDemo 148 149 void CSaveGrayDemoView::OnRButtonDown(UINT nFlags, CPoint point) 150 { 151 // 바탕 화면 윈도우 객체에 대한 포인터를 얻음 152 CWnd* pWndDesktop = GetDesktopWindow( ); 153 CWindowDC ScrDC(pWndDesktop); // 바탕 화면 윈도우 DC 154 CClientDC dc(this); // 뷰 윈도우 DC 155 156 // 바탕 화면 윈도우의 크기를 알아낸다. 157 CRect Rect; 158 pWndDesktop->GetWindowRect(&Rect); 159 160 // 바탕 화면 크기 및 색상 수와 동일한 비트맵 이미지를 만든다. 161 CImage Image; 162 int cx = Rect.Width( ); // 바탕 화면 폭 163 int cy = Rect.Height( ); // 바탕 화면 높이 164 Image.Create(cx, cy, ScrDC.GetDeviceCaps(BITSPIXEL)); 165

SaveGrayDemo 166 // 이미지 DC와 화면 DC에 바탕 화면 윈도우 화면을 출력한다. 167 CDC* pDC = CDC::FromHandle(Image.GetDC( )); 168 pDC->BitBlt(0, 0, cx, cy, &ScrDC, 0, 0, SRCCOPY); 169 dc.BitBlt(0, 0, cx, cy, pDC, 0, 0, SRCCOPY); 170 Image.ReleaseDC( ); 171 172 // JPEG 형식으로 바탕 화면 이미지를 저장한다. 173 Image.Save(TEXT("Desktop.jpg"), Gdiplus::ImageFormatJPEG); 174 // 저장된 이미지를 뷰어를 실행하여 보여준다. 175 ::ShellExecute( NULL, 176 TEXT("open"), TEXT("Desktop.jpg"), 177 NULL, NULL, SW_SHOW); 178 179 CView::OnRButtonDown(nFlags, point); 180 } 181

실습안내 1. 새 프로젝트를 만들고 임의의 BMP 파일을 리소스로 등록한 후 클라이언트 뷰 윈도우에 출력하는 프로그램을 작성해 봅시다.   2. 1번에서 작성한 예제에 사진과 함께 자신의 이름을 출력하도록 예제를 수정해 봅시다. 단, 반드시 화면 DC에 직접 이름을 출력하지 말아야 합니다. 3. 임의의 두 이미지 파일을 열어서 한 화면에 겹쳐서 출력하는 예제를 작성해 봅시다. 단, 겹쳐 있더라도 두 이미지가 어느 정도 식별할 수 있도록 반투명하게 처리해야 합니다. 4. 두 이미지를 겹쳐서 출력하되 다음 그림과 같이 문자열 부분을 투명하게 처리하도록 해봅시다.

Chapter 9 Using Graphics Device Interface

TextRgn 103 void CTextRgnView::OnPaint() 104 { 104 { 105 CPaintDC dc(this); // device context for painting 106 // 임의의 두 사각형을 107 // 각기 다른 색상(붉은색과 회색)으로 칠한다. 108 CRect rectLeft = CRect(50, 50, 250, 150); 109 CRect rectRight = CRect(250, 50, 450, 150); 110 dc.FillSolidRect(&rectLeft, RGB(192, 0, 0)); 111 dc.FillSolidRect(&rectRight, RGB(192, 192, 192)); 112 113 // 앞서 만든 두 사각형을 별도의 영역으로 만든다. 114 CRgn rgnLeft, rgnRight; 115 rgnLeft.CreateRectRgnIndirect(rectLeft); 116 rgnRight.CreateRectRgnIndirect(rectRight); 117 118 / /DC의 폰트를 Arial Black(높이72)으로 바꾼다. 119 LOGFONT lf; 120 ::ZeroMemory(&lf, sizeof(lf)); 121 lf.lfHeight = 72; 122 wsprintf(lf.lfFaceName, _T("%s"), _T("Arial Black")); 123 CFont NewFont; 124 NewFont.CreateFontIndirect(&lf); 125 CFont* pOldFont = dc.SelectObject(&NewFont);

TextRgn 126 127 dc.SetBkMode(TRANSPARENT); 128 // dc.TextOut(60, 65, TEXT("TEST STRING")); 129 130 // 왼쪽 영역을 선택하여 문자열을 출력한다. 131 dc.SetTextColor(RGB(192, 192, 192)); 132 dc.SelectClipRgn(&rgnLeft); 133 dc.TextOut(60, 65, TEXT("TEST STRING")); 134 135 // 오른쪽 영역을 선택하여 문자열을 출력한다. 136 dc.SetTextColor(RGB(192, 0, 0)); 137 dc.SelectClipRgn(&rgnRight); 138 dc.TextOut(60, 65, TEXT("TEST STRING")); 139 140 dc.SelectObject(pOldFont); 141 } 142

TextRgn

Ignored area TextRgn A (50, 50) C (250, 50) rectLeft rectRight B (250, 150) D (450, 150) rgnLeft rgnRight Ignored area

ImageRgn 118 119 void CImageRgnView::OnPaint( ) 120 { 120 { 121 CPaintDC dc(this); // device context for painting 122 // 반투명하게 배경 이미지를 출력 123 m_ImgSample.AlphaBlend(dc.m_hDC, 0, 0, 50); 124 // 원으로 된 윈도우 영역을 선택 125 CRgn Rgn; 126 Rgn.CreateEllipticRgn(m_rectVisible.left, 127 m_rectVisible.top, 128 m_rectVisible.right, 129 m_rectVisible.bottom); 130 dc.SelectClipRgn(&Rgn); 131 // 투명하지 않은 이미지를 다시 한번 출력 132 m_ImgSample.BitBlt(dc.m_hDC, 0, 0); 133 } 134

FrameRgn 64 65 // 두 영역 및 조합된 영역을 주어진 좌표로 생성한다. 65 // 두 영역 및 조합된 영역을 주어진 좌표로 생성한다. 66 m_RgnRect1.CreateRectRgn(0, 0, 100, 100); 67 m_RgnRect2.CreateRectRgn(70, 70, 170, 170); 68 //※ 이 영역은 조합된 결과가 저장될 영역이므로 좌표는 의미가 없다. 69 m_RgnTotal.CreateRectRgn(0, 0, 0, 0); 70 71 // 두 영역을 조합한 새로운 영역을 만든다. 72 m_RgnTotal.CombineRgn(&m_RgnRect1, &m_RgnRect2, RGN_XOR); 73 // 조합된 영역이 CMainFrame 윈도우의 영역이 되도록 한다. 74 SetWindowRgn((HRGN)m_RgnTotal, TRUE); 75 76 return 0; 77 } 78

DrawModeDemo m_ptDragEnd m_ptBegin m_ptEnd m_ptDragBegin

DrawModeDemo 150 151 void CDrawModeDemoView::DrawInvertLine(CPoint point) 152 { 153 CClientDC dc(this); 154 // 두께가 40인 펜을 생성한다. 155 CPen NewPen(PS_SOLID, 40, RGB(0, 128, 0)); 156 CPen* pOldPen = (CPen*)dc.SelectObject(&NewPen); 157 // 그리기 모드를 반전 모드로 변경한다. 158 dc.SetROP2(R2_NOT); 159 160 // 기존에 반전된 선이 그려진 좌표에 한번 더 반전된 선을 그린다. 161 // 따라서 반전된 이미지가 원래대로 복원된다. 162 dc.MoveTo(m_ptDragBegin); 163 dc.LineTo(m_ptDragEnd); 164 165 m_ptDragEnd = point; 166 167 // 새 좌표로 반전된 선을 그려서 이미지를 반전시킨다. 168 dc.MoveTo(m_ptDragBegin); 169 dc.LineTo(m_ptDragEnd); 170 171 dc.SelectObject(pOldPen); 172 } 173

DrawModeDemo 195 void CDrawModeDemoView::OnRButtonDown(UINT nFlags, CPoint point) 196 { 197 / /바탕 화면 윈도우에 대한 포인터를 얻는다. 198 CWnd* pWnd = GetDesktopWindow( ); 199 CWindowDC dc(pWnd); 200 CPen NewPen(PS_SOLID, 10, RGB(0, 0, 0)); 201 CPen* pOldPen = (CPen*)dc.SelectObject(&NewPen); 202 203 int nPrevMode = dc.SetROP2(R2_NOTXORPEN); 204 205 // 바탕 화면 윈도우에 그리기를 수행한다. 206 for(int i = 0; i < 300; i += 3) 207 { 208 dc.Rectangle(20, 10, 210 + i, 210 + i); 209 ::Sleep(5); 210 dc.Rectangle(20, 10, 210 + i, 210 + i); 211 } 212 213 dc.SelectObject(pOldPen); 214 dc.SetROP2(nPrevMode); 215 pWnd->RedrawWindow( ); 216 217 CView::OnRButtonDown(nFlags, point); 218 }

DrawModeDemo

Map mode m_nZoomRate == 50 m_nZoomRate == 100 A (-300, -300) B(0, 0)

MapModeDemo 101 102 // CMapModeDemoView 메시지 처리기 103 104 void CMapModeDemoView::OnPaint( ) 105 { 106 CPaintDC dc(this); // device context for painting 107 108 dc.SetMapMode(MM_ISOTROPIC); 109 // 논리적인 화면 DC의 크기를 100*100으로 고정한다. 110 dc.SetWindowExt(100, 100); 111 // 뷰 포트의 크기를 변경한다. 112 dc.SetViewportExt(m_nZoomRate, m_nZoomRate); 113 // 픽셀 단위 좌표로 (300, 300)이 논리적 좌표 (0, 0)이 되도록 한다. 114 dc.SetViewportOrg(300, 300); 115

MapModeDemo 116 // X, Y축을 교차하는 선을 그린다. 117 CPen NewPen(PS_SOLID, 15, RGB(192, 0 , 0)); 118 CPen* pOldPen = dc.SelectObject(&NewPen); 119 dc.MoveTo(-100, 100); 120 dc.LineTo(100, -100); 121 dc.SelectObject(pOldPen); 122 123 // X, Y축에 대한 선을 그린다. 124 dc.MoveTo(-1024, 0); 125 dc.LineTo(1024, 0); 126 dc.MoveTo(0, -1024); 127 dc.LineTo(0, 1024); 128 129 // 비트맵을 (20, 20) 좌표에 출력한다. 130 CImage Image; 131 Image.LoadFromResource(AfxGetInstanceHandle( ), IDB_Sample); 132 Image.BitBlt(dc.m_hDC, 20, 20); 133 134 // (0, 0)을 기준으로 각 분면에 문자열을 출력한다. 135 dc.TextOut(20, 30, _T("Test1")); 136 dc.TextOut(-50, 30, _T("Test2")); 137 dc.TextOut(-50, -30, _T("Test3")); 138 dc.TextOut(20, -30, _T("Test4")); 139 }

Viewport m_nZoomRate = 300 SetWindowExt(100, 100) A (-300, -300)

PrintDemo 49 void CPrintDemoView::OnDraw(CDC* pDC) 50 { 50 { 51 CPrintDemoDoc* pDoc = GetDocument( ); 52 ASSERT_VALID(pDoc); 53 if (!pDoc) 54 return; 55 56 // 화면 정보 출력 57 CString strtmp = _T(""); strtmp.Format( _T("Pixel (HORZRES:%d VERTRES:%d), mm(HORZSIZE:%d VERTSIZE:%d)"), 59 pDC->GetDeviceCaps(HORZRES), // 픽셀 단위 수평 해상도 60 pDC->GetDeviceCaps(VERTRES), // 픽셀 단위 수직 해상도 61 pDC->GetDeviceCaps(HORZSIZE), // mm 단위 수평 길이 62 pDC->GetDeviceCaps(VERTSIZE)); // mm 단위 수직 길이 63 64 pDC->TextOut(10, 10, strtmp); 65 pDC->MoveTo(0, 130); 66 pDC->LineTo(pDC->GetDeviceCaps(HORZRES), 130); 67 }

PrintDemo

for(int i = 0; i < MaxPage; ++i) PrintDemo OnPreparePrinting() SetMaxPage(3) Client View OnDraw() OnPaint() Document OnBeginPrinting() Page 1 for(int i = 0; i < MaxPage; ++i) OnDraw() OnPrint() Page 2 OnEndPrinting() Page 3 PRINT COMPLETE!

PrintDemo