1. 이벤트 시스템 큐
이벤트가 발생하면 이를 시스템 메시지 큐로 전달
전달된 메시지는 각 응용 프로그램 메시지 큐로 할당되는데,
이 때 이미 실행중인 응용 프로그램 메시지 큐에 각 적용시킨다.

계산기는 입력이 없으면 변화가 없기에, 메시지 큐가 비어있는 것 볼 수 있다.
뮤직 플레이어는 노래가 나와야 하기에 다른 응용 프로그램이 맨 위에 있어도 처리가 된다.
메모장의 경우는 입력을 현재 하고 있으므로 메시지 큐에 적용되어 처리되는 걸 볼 수 있다.

2. 멀티테스킹과 멀티스레딩
멀티태스킹: 운영체제가 여러 개의 응용 프로그램을 동시에 실행하는 것
멀티스레딩: 응용 프로그램 내부에서 여러 개의 실행 흐름(=스레드)을 동시에 진행하는 것

3. SDK 프로그램 개발환경
WM_CREATE : CreateWindow() 함수 호출
WM_LBUTTONDOWN : 클라이언트 영역에서 마우스 왼쪽 버튼을 누를 때
WM_PAINT : 클라이언트 영역에서 일부 또는 전체를 다시 그릴 필요가 있을 때
WM_DESTROY : 종료 버튼을 눌렀을 때

4. 디바이스 컨텍스트(DC, Device Context)
- GDI가 생성하고 관리하는 데이터 구조체
- 멀티태스킹 GUI 환경에서 발생할 수 있는 복잡한 상황들을 신경쓰지 않고 장치에 자유롭게 출력 가능

5. 무효 영역에서 WM_PAINT 메시지 발생 상황
- 윈도우가 생성될 때
- 윈도우의 크기가 변경될 때
- 윈도우가 최소화, 최대화 되었을 때

6. 명령어 - 8. 기본 입출력에서 중복됨

7. 펜, 브러쉬 그리기
CPen pen(PS_SOLID, 2, RGB(255, 0, 0));	// 폭이 2인 빨간색 펜
CPen* oldPen = pDC->SelectObject(&pen);	// 펜 선택, 이전 펜 저장
pDC->Rectangle(100, 100, 200, 200);		// 직사각형 그리기.
pDC->SelectObject(oldPen);				// 이전 펜 복원

CBrush brush = brush.CreateSolidBrush(RGB(255, 0, 0)); // 빨간색 브러쉬
CBrush *oldBrush = pDC->SelectObject(&brush);          // 브러쉬 선택, 이전 브러쉬 저장
pDC->Rectangle(100, 100, 200, 200); // 직사각형 그리기
pDC->SelectObject(oldBrush);
brush.DeleteObject();

8. 기본 입출력
pDC->Rectangle(100, 100, 200, 200); // 도형 출력
pDC->Ellipse(100, 100, 200, 200);
pDC->RoundRect(100, 100, 200, 200, 20, 20);

TextOut(100, 100 ,_T("Hello World")); // 텍스트 출력
CRect rect; // {left:100, right:100, top:200, bottom:200}
pDC->DrawText(_T("Hello World"), &rect, DT_CENTER | DT_VCENTER);

MoveTo(100, 100); // 100, 100 좌표로 이동
LineTo(200, 200); // 200, 200 좌표로 이동하면서 선 그리기

--------------------
View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { // 키보드 처리
	if (nChar == VK_BACK) // Back 키 클릭 시
		m_str.Delete(m_str.GetLength() - 1); // 내용 한 개씩 지우기
	else
		m_str.AppendChar(nChar); // 입력하기
	Invalidate(); // 화면 동기화
	CView::OnChar(nChar, nRepCnt, nFlags);
}

View::OnDraw(CDC* pDC) {
	pDC->TextOutW(0, 0, m_str, m_str.GetLength());
}
--------------------

--------------------
View::OnLButtonDown(UINT nFlags, CPoint point) { // 마우스 클릭
	m_ptStart = point;
	CView::OnLButtonDown(nFlags, point);
}

View::OnMouseMove(UINT nFlags, CPoint point) { // 마우스 이동
	if (nFlags & MK_LBUTTON) // 왼쪽 버튼 누르면
	{
		m_ptEnd = point; 
		Invalidate();
	}
	CView::OnMouseMove(nFlags, point);
}

View::OnLButtonUp(UINT nFlags, CPoint point) {
	m_ptEnd = point;
	Invalidate();
	CView::OnLButtonUp(nFlags, point);
}
--------------------
SetROP2(int nDrawMode); // 래스터 연산
계산 방법: NOTXOR
흰색    = 11111111 11111111 11111111 (255, 255, 255)
빨간색  = 11111111 00000000 00000000 (255,   0,   0)
===================================
빨간색  = 11111111 00000000 00000000 (255,   0,   0)

9. 타이머
View::OnLButtonDown() {
	SetTimer(1, 700, NULL);
	SetTimer(2, 1000, &CProjectView::TimerProc);
	CView::OnLButtonDown();
}

View::OnTimer(UINT nIDEvent) {
	// 0.7초마다 수행
	CView::OnTimer(nIDEvent);
}

CALLBACK CProjectView::
TimerProc (HWND hWnd, UINT nMsg, UINT_PRT nIDEvent, DWORD dwTime) {
	// 1초 마다 수행
}

KillTimer(1); // 1번 타이머 정지
KillTimer(2); // 2번 타이머 정지

10. 비트맵
1. 비트맵을 읽어온다
2. LoadBitmap() 함수로 CBitmap 객체에 비트맵을 로드한다.
3. SelectObject() 함수로 사용할 비트맵을 memDC에서 선택한다.
4. memDC에 있는 비트맵을 BitBlt() 를 통해 전송하고, CreateCompatibleDC()로 반환한다.
5. pDC에서 화면으로 비트맵을 출력한다.

11. BitBlt, StretchBlt로 비트맵 화면에 띄우기
BitBlt(
	int nXD,   // 화면 출력 x 위치 number X Display
	int nYD,   // 화면 출력 y 위치 number Y Display
	int nW,  // 출력 너비 사이즈 number Width
	int nH,  // 출력 높이 사이즈 number Height
	CDC memDC, // 이미지 사진 memory Device Context
	int nXS, // 이미지 x 위치 number X Start
	int nYS, // 이미지 y 위치 number Y Start
	DWORD dwRop // SRCCOPY, SRCAND, SRCPAINT
);
StretchBlt(
	int nXD,   // 화면 출력 x 위치 | number X Display
	int nYD,   // 화면 출력 y 위치 | number Y Display
	int nW,  // 출력 너비 사이즈 | number Width
	int nH,  // 출력 높이 사이즈 | number Height
	CDC memDC, // 이미지 사진 | memory Device Context
	int nXS, // 이미지 x 위치 | number X Start 
	int nYS, // 이미지 y 위치 | number Y Start
	int nWS, // 이미지 너비 사이즈 | number Width Size
	int nHS, // 이미지 높이 사이즈 | number Height Size
	DWORD dwRop // SRCCOPY, SRCAND, SRCPAINT
);

12. 더블 버퍼링
더블 버퍼링 없이 화면을 띄우면 기존에 있던 화면을 먼저 지우고, 하나씩 하나씩 그리게 된다.
하지만, 더블 버퍼링을 띄우면, 기존의 화면에서 새로운 화면(오프 스크린)을 새로 만들어,
모든 화면을 다 그려낸 후 기존 화면에 옮겨 그리는 방식이다.
CDC mdc; // DC 생성
CBitmap s_bit, l_bit, *oldbit; 
mdc.CreateCompatibleDC(pDC); // 새 DC 생성
s_bit.LoadBitmap(IDB_BITMAP1); // 비트맵1 로드
l_bit.LoadBitmap(IDB_BITMAP2); // 비트맵2 로드
oldbit = mdc.SelectObject(&s_bit); // 비트맵1 선택
pDC->BitBlt(0, 0, 48, 48, &mdc, 0, 0, SRCCOPY); // 비트맵1 띄우기
mdc.SelectObject(&l_bit); // 비트맵2 선택
pDC->BitBlt(60, 0, 546, 331, &mdc, 0, 0, SRCCOPY); // 비트맵2 뜨위기
mdc.SelectObject(oldbit);
mdc.DeleteDC();

13. 옵션
- SRCAND: AND 연산자를 사용하여 대상 비트 맵과 소스 비트맵의 픽셀을 결합
- SRCCOPY: 소스 비트 맵을 대상 비트 맵에 복사
- SRCPAINT: OR 연산자를 사용하여 대상 비트맵과 소스 비트 맵의 픽셀을 결합

14. Document
데이터만 따로 관리하는 파일이라고 일단 이해함.
이를 통해 파일을 저장해서 값을 보관하고 있다 가 View로 불러올 수도 있다.

15. 데이터 View - Docu 교환
// View의 OnDraw 에서 Doc 선언을 통해 값을 불러올 수 있다.
MyDoc* pDoc = GetDocument(); // Doc 선언
for (int i = 0; i < pDoc->m_nCount; i++) {
		pDC->Ellipse(pDoc->m_ptData[i].x - 10,
			pDoc->m_ptData[i].y - 10,
			pDoc->m_ptData[i].x + 10,
			pDoc->m_ptData[i].y + 10); // Doc에 있는 x, y 좌표 불러옴
		pDC->MoveTo(pDoc->m_ptData[i].x - 10, pDoc->m_ptData[i].y - 10);
		pDC->LineTo(pDoc->m_ptData[i].x + 10, pDoc->m_ptData[i].y + 10);
		pDC->MoveTo(pDoc->m_ptData[i].x - 10, pDoc->m_ptData[i].y + 10);
		pDC->LineTo(pDoc->m_ptData[i].x + 10, pDoc->m_ptData[i].y - 10);
}
// View에서 Docu로 값 교환하는건 선언을 반대로 하면 된다.
pDoc->m.ptData[i].y = 10;

16. 파일 저장/로딩
Doc::Serialize(CArchive& ar) {
	if (ar.IsStoring()) {
		// TODO: 여기에 저장 코드를 추가합니다.
		ar << m_nCount;
		for (int i = 0; i < m_nCount; i++) {
			ar << m_ptData[i];
		}
	}
	else {
		// TODO: 여기에 로딩 코드를 추가합니다.
		ar >> m_nCount;
		for (int i = 0; i < m_nCount; i++) {
			ar >> m_ptData[i];
		}
	}
}