void CEngine::progress()
{
HPEN hRedPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
};
첫번쨰 인자로는 펜의 형태의 매크로를 준다
PS_SOLID
직선을 긋는 가장 기본적인 펜이다. 펜스타일 솔리드두번쨰 인자로는 펜의 두께 설정하는 인자
세번쨰 인자로는 펜의 색깔
// 매크로
((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
// 컴파일 되면 입력된 인자로 바뀐다.
((COLORREF)(((BYTE)(255) | ((WORD)((BYTE)(0)) << 8)) | (((DWORD)(BYTE)(0)) << 16)))
RGB는 컴파일될떄 저런식으로 컴파일되서 바뀐다.
R은 8바이트에 채워넣고 G은 8칸을 비트 쉬프트 연산을 해서 채우고 B는 16칸을 비트 쉬프트 연산을해서 채운다.
R->G->B 역순으로 잡았다.
|(합연산)을 통해 합쳐진다.
펜도 커널 오브젝트이다.
CreateCompatibleBitmap(/*인자 생략*/);
m_hDC = GetDC(m_hMainWnd);
GetDC 로 생성되는 DC 의 정보
목적지 비트맵 - 입력 원도우의 비트맵
펜
브러쉬
필요한 정보가 DC안에 있다.
void CEngine::progress()
{
//Ellipse(m_hDC, 50, 50, 150, 150);
HPEN hRedPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
// 1
//HPEN hPrevPen = (SelectObject)(m_hDC, hRedPen);
// 1.1
HPEN hPrevPen = (HPEN)(SelectObject)(m_hDC, hRedPen);
Rectangle(m_hDC, 50, 50, 150, 150);
}
SelectObject
함수로 오브젝트를 DC가 선택한다.DC가 선택을 해서 그 오브젝트에 렌더링 가능해졌다.
첫번째 인자로는 DC값
두번째 인자는 펜을 적어준다.(지금은 빨간펜)
기본의 검은펜을 빨간펜으로 바꾸면 원래 들고있던 검은색 펜을 반환한다.
1번은 오류가 나서 1.1번처럼 핸들값으로 강제 캐스팅해서 오류 안나게 한다.
SelectObject
는 펜과 브러쉬 둘다 넣을수 있다 펜을 브러쉬랑 전부다 핸들이긴 하지만 종류가 달라서 핸들타입이 다르다.
SelectObject
함수는 입력으로 펜을 넣으면 펜을 줘야되고 브러쉬를 넣으면 브러쉬를 줘야한다.
반환타입을 통합으로 써야해서 HGDIOBJ를 쓰지만 그냥 무시하고 펜을 넣었으니 HPEN으로 캐스팅해서 쓴다.
void CEngine::progress()
{
// RedPen 생성
HPEN hRedPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
// DC 에 RedPen 입력, 원래 Black Pen 되돌려받아둠
HPEN hPrevPen = (HPEN)SelectObject(m_hDC, hRedPen);
// 사각형 그림
Rectangle(m_hDC, 50, 50, 150, 150);
// 1
// BlackPen 입력
SelectObject(m_hDC, hPrevPen);
// 2
// RedPen 삭제
DeleteObject(hRedPen);
}
1번처럼 블랙펜을 입력을 받는다.
2번처럼 레드펜을 삭제요청을 한다.(커널오브젝트라 요청)
레드펜 생성 -> 블랙펜받아두고 레드펜 입력 -> 사각형 그림 -> 레드펜에 블랙펜 덧씌우고 -> 레드펜 삭제
비효율적이다.
// CEngine.h의 CEngine클래스
private:
HWND m_hMainWnd; // 메인 윈도우 핸들
POINT m_Resoulution; // 메인 윈도우 해상도
HDC m_hDC; // 메인 윈도우 DC
// 1
HPEN m_arrPen[];
//enum.h 내부
enum PEN_TYPE
{
PEN_RED, // 0
PEN_GREEN, // 1
PEN_BLUE, // 2
// 1
PEN_END, .// 3
};
열거형은 4바이트로 정수로 취급하지만 enum_type을 이용하면 특정 케이스별로 원래라면 숫자를 줘야하는데 enum값에 명시된 타입명으로 숫자를 특정 문자로 전환해서 사용할수 있다.
#define이랑 다른점 별도의 타입처럼 취급한다.
1번처럼 END를 끝에 선언해 놓으면 배열의 갯수로 야무지게 사용가능하다.
HPEN m_arrPen[/*PEN_TYPE::*/PEN_END];
// pch.h 내부
#include "define.h"
#include "enum.h"
// CEngine.cpp 의 내부
m_arrPen[PEN_RED] = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
// 1
//m_arrPen[0] = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
m_arrPen[PEN_GREEN] = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
m_arrPen[PEN_BLUE] = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
초기화를 해둔다.
3개짜리 배열이니까 첫번쨰 배열에는 빨간색 두번째는 초록색 세번째는 파란색 펜을 넣을것이다.
배열에다가 이니셜 라이저 할떄 미리 펜을 생성해둘수 있다.
1번처럼 0으로 적어두면 0이 무슨 의미인줄 모르기 때문에 가독성 좋게 RED_PEN
으로 적어둔다.
// 레드펜
HPEN hPrevPen = (HPEN)SelectObject(m_hDC, m_arrPen[PEN_RED]);
// 사각형그림
Rectangle(m_hDC, 50, 50, 150, 150);
// 블랙펜 입력
(SelectObject)(m_hDC, hPrevPen);
미리 펜을 만들었으니 펜을 코드마다 일일이 만들필요없이 가져오기만 하면된다.
프로그램 돌아갈때는 이제 삭제할 필요가 없다.
// CEngine.cpp 내부
CEngine::~CEngine()
{
// DC 삭제
ReleaseDC(m_hMainWnd, m_hDC);
// 1
// Pen 삭제
for (int i = 0; i < PEN_END; ++i)
{
DeleteObject(m_arrPen[i]);
}
}
// CEngine.h의 CEngine 클래스 내부
public:
HPEN GetPen(PEN_TYPE _type) { return m_arrPen[_type]; }
CEngine.cpp파일말고 다른데에서 Pen이 필요하면 Pen을 달라고해야되서 펜달라는 GetPen
인라인 함수를 만들었다.
PEN_TYPE으로 명시해두면 enum.h안에 PEN_TYPE에 명시된 아이들만 들어올 수 있다.
자료형이랑 비슷하다 컴파일러는 4바이트 정수로 취급을 하지만 여기에다가 20(enum안에 없다)을 이렇게 숫자를 넣을 수는 없다.
펜타입으로 선언했기 떄문에 정수로 타입으로 보이긴하지만 문법상 enum값으로 타입을 선언하면 변수안에는 enum값만 넣을수 있다.
// main.cpp
// Engine 초기화
if (FAILED(CEngine::GetInst()->init(g_hWnd, POINT{ 1280, 768 })))
{
// Engine 초기화 실패 ==> 프로그램 종료
MessageBox(nullptr, L"엔진 초기화 실패", L"에러 발생", MB_OK);
return 0;
}
// 1
HPEN Green = CEngine::GetInst()->GetPen(PEN_GREEN);
펜을 어쨋건 가져다 써야한다. 갖다 쓰고 렌더링하고 원래 핸들로 돌려놓아야한다.
이런것도 하기 귀찮다.
까먹지 않고 안돌려놓으면 내가 썻던 사각형을 DC가 들고있으니까 다른 물체가 렌더링할떄 당연히 검은색 물체가 있을줄 알고 렌더링하는데 저 DC를 갖다 썻는데 파란색으로 써졌다면 아 파란색 안돌려놨네 하고 왔다갔다하면서 코드 수정해야한다.(귀찮다는 소리)
원래 꼭 해줘야하는것은 실수의 여지가 생기고 귀찮아 진다.
class CSelectObj
{
private:
HDC m_DC;
HGDIOBJ m_hPrev;
public:
// 1
CSelectObj(HDC _dc, HGDIOBJ _SelectedObj);
~CSelectObj();
};
모듈이라 모든 클래스는 CEntity를 상속받아야하지만 애는 간단하게 쓰일 클래스
라 상속받지 않겠다.
CSelectObj클래스 맴버 변수
기본 생성자는 아무것도 없으면 생성되지만 오버로딩된 생성자가 하나라도 잇으면 기본 생성자 안만들어 준다.
역발상으로 기본생성자를 호출을 불가능하게 막을 수 있다.
클래스의 객체를 생성할떄 실수로라도 기본 생성자를 만들어지는것 막는다.
두가지 인자는
// CSelectObj.cpp
#include "pch.h"
#include "CSelectObj.h"
CSelectObj::CSelectObj(HDC _dc, HGDIOBJ _SelectedObj)
// 1
: m_DC(_dc)
, m_hPrev(nullptr)
{
// 2
m_hPrev = SelectObject(m_DC, _SelectedObj);
}
// 3
CSelectObj::~CSelectObj()
{
SelectObject(m_DC, m_hPrev);
}
1번처럼 초기화는 입력으로 들어온 _dc는 넣어주고 m_hPrev에는 아무것도 안넣을것이다.
2번 대입은 SelectObject
함수는 입력으로 들어온 m_DC와 _SelectedObj의 입력으로 들어온 dc를 선택하게 한다.
3번의 소멸자에서는 SelectObject
함수로 m_DC한테 예전에 들고잇던걸 돌려준다.
// pch.h 내부
#include "CSelectObj.h"
// CEngine.cpp 내부
void CEngine::progress()
{
// 1
//CSelectObj select(m_hDC, m_arrPen[BLUE_PEN]);
// 2
//CSelectObj (m_hDC, m_arrPen[PEN_BLUE]);
// 3
USE_PEN(m_hDC, PEN_BLUE);
// 4
Rectangle(m_hDC, 50, 50, 150, 150);
}
CSelectObj
가 dc가 선택할 블루펜을 넣어줘서 생성자에서 SelectObject
함수를 호출해서 DC가 입력으로 들어간 펜을 고른다.
m_hPrev
에는 전에 DC가 들고있던 대응되는 같은 타입의 원래 물체가 들어온다.중단 걸고 보면 입력으로 들어가서 입력으로 들어온 DC로 입력으로 들어온 블루펜을 선택하면서 원래 DC가 나오고 사각형 그리고 소멸자 와서 이전에 받아뒀던 걸로 다시 선택을 한다.(사진 요약)
CSelectObj
클래스를 알고있어야하고 변수를 선언하면서 ()인자를 넣어줘야하니까 귀찮다.2번은 임시객체를 해서 하면 경고를 준다.
2번보다는 3번처럼 변수명을 주긴주데 자주 반복 사용될거같은 구문이니까 매크로로 바꾼다.
//define.h 의 내부
#define USE_PEN(DC, PEN_TYPE) CSelectObj select(DC, CEngine::GetInst()->GetPen(PEN_TYPE))
USE_PEN
매크로를 만든다.
DC랑 PEN_TYPE타입 명시해주면을 인자로 주고했다.
펜의 타입이라 생각을 하고 두번쨰 인자는 PEN_TYPE으로 주고 그 펜타입을 받아오게
엔진 밖에서도 써야해서 요런식으로 매크로.
펜사용하는게 간단해 졌다. 펜타입만 알려주면 된다.
void CEngine::progress()
{
USE_PEN(m_hDC, BLUE_PEN);
// 1
HBRUSH hRedBrusg = CreateSolidBrush(RGB(255, 0, 0));
// 2
HBRUSH hPrevBrush = (HBRUSH)SelectObject(m_hDC, hRedBrusg);
// 3
Rectangle(m_hDC, 50, 50, 150, 150);
// 4
SelectObject(m_hDC, hPrevBrush);
// 5
DeleteObject(hRedBrusg);
}
CreateSolidBrush
함수를 통해 만들수 있다.SelectObject
함수를 통해 현재 빨간색브러쉬 dc주고 이전 dc를 hPrevBrush
변수에 받아둔다.SelectObject
함수로 오브젝트해서 dc가 원래 브러쉬 선택하고 한다. void CEngine::progress()
{
Ellipse(m_hDC, 50, 50, 150, 150);
USE_PEN(m_hDC, BLUE_PEN);
// 1
//HBRUSH hHollowBrush = GetStockObject(HOLLOW_BRUSH);
// 2
HBRUSH hHollowBrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
HBRUSH hPrevBrush = (HBRUSH)SelectObject(m_hDC, hRedBrusg);
HBRUSH hPrevBrush = (HBRUSH)SelectObject(m_hDC, hHollowBrush);
// 사각형 그림
Rectangle(m_hDC, 50, 50, 150, 150);
SelectObject(m_hDC, hPrevBrush);
// 3
//DeleteObject(hRedBrusg);
}
1번은 오류나서 HBRUSH
로 강제 캐스팅한 2번은 오류 안난다.
정말로 내부가 비어있는 브러쉬다. 색칠하지 않는 브러쉬
GetStockObject
함수는 이미 저장되어 있는 물체를 가져온다는 함수다.
OS가 미리미리 만들어둔 가져와서 쓸수 있다.
보이드 포인터처럼 아무핸들이나 받는다. 정확히 브러쉬를 캐스팅해서 가져온다.
3번은 이제 원래 OS가 만들어둔 브러쉬를 사용하니까 내가 직접 지울 필요가 없다.
저게 안이 정말로 내부가 비어있는 건지 아님 흰색으로 칠한지 몰르니까 Ellipse(m_hDC, 50, 50, 150, 150);
추가해서 테스트해서 깜빡깜빡 안하면 HOLLOW_BRUSH
를 사용한것이다.
void CEngine::progress()
{
USE_PEN(m_hDC, PEN_RED);
USE_BRUSH(m_hDC, BRUSH_BLACK);
Rectangle(m_hDC, 50, 50, 150, 150);
}
// enum.h 내부이다.
enum PEN_TYPE
{
// 생략
};
enum BRUSH_TYPE
{
BRUSH_RED,
BRUSH_GREEN,
BRUSH_BLUE,
BRUSH_HOLLOW,
BRUSH_BLACK,
BRUSH_END,
};
// CEngine.h CEngine클래스 내부
private:
HWND m_hMainWnd; // 메인 윈도우 핸들
POINT m_Resoulution; // 메인 윈도우 해상도
HDC m_hDC; // 메인 윈도우 DC
HPEN m_arrPen[PEN_END];
// 1
HBRUSH m_arrBrush[BRUSH_END];
// CEngine.cpp 내부
CEngine::CEngine()
: m_hMainWnd(nullptr)
, m_Resoulution{}
, m_hDC(nullptr)
// 1
, m_arrPen{}
// 2
, m_arrBrush{}
{}
// CEngine.cpp 내부
// 자주 사용할 펜 생성
m_arrPen[RED_PEN] = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
m_arrPen[GREEN_PEN] = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
m_arrPen[BLUE_PEN] = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
// 5.6 자주 사용할 브러쉬 생성.
m_arrBrush[BRUSH_RED] = CreateSolidBrush(RGB(255, 0, 0));
m_arrBrush[BRUSH_GREEN] = CreateSolidBrush(RGB(0, 255, 0));;
m_arrBrush[BRUSH_BLUE] = CreateSolidBrush(RGB(0, 0, 255));;
m_arrBrush[BRUSH_HOLLOW] = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
m_arrBrush[BRUSH_BLACK] = (HBRUSH)GetStockObject(BLACK_BRUSH);
// CEngine.cpp의 소멸자 안
for (int i = 0; i < 3; ++i)
{
DeleteObject(m_arrBrush[i]);
}
// CEngine.h
HBRUSH GetBrush(BRUSH_TYPE _type) { return m_arrBrush[_type]; }
GetBrush
함수가 다른곳에서 브러쉬 가져갈수있게 인라인 함수를 만들어둔다. {
USE_PEN(m_hDC, PEN_RED);
// 1
CSelectObj select (m_hDC, CEngine::GetInst()->GetBrush(BRUSH_BLACK));
// 2
USE_BRUSH(m_hDC, BRUSH_BLACK);
Rectangle(m_hDC, 50, 50, 150, 150);
}
// 1
#define USE_PEN(DC, PEN_TYPE) CSelectObj select(DC, CEngine::GetInst()->GetPen(PEN_TYPE))
// 2
#define USE_PEN(DC, TYPE) CSelectObj SelectPen(DC, CEngine::GetInst()->GetPen(TYPE))
// 3
#define USE_BRUSH(DC, TYPE) CSelectObj select(DC, CEngine::GetInst()->GetBrush(TYPE))
// 4
#define USE_BRUSH(DC, TYPE) CSelectObj selectBrush(DC, CEngine::GetInst()->GetBrush(TYPE))
{
USE_PEN(m_hDC, PEN_RED);
USE_BRUSH(m_hDC, BRUSH_BLACK);
Rectangle(m_hDC, 50, 50, 150, 150);
}
// 위 생략
// Engine 초기화
if (FAILED(CEngine::GetInst()->init(g_hWnd, POINT{1280, 768})))
{
// Engine 초기화 실패 ==> 프로그램 종료
MessageBox(nullptr, L"엔진 초기화 실패", L"에러 발생", MB_OK);
return 0;
}
// 추가
HPEN Green = CEngine::GetInst()->GetPen(PEN_GREEN);
// 아래 생략
// 위 생략
while (true)
{
// Peek 엿보다
// 메세지가 있던 없던, 리턴된다.
// 메세지가 있었으면 true, 메세지가 없었으면 false
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
// 꺼내온 메세지가 WM_QUIT 이면 프로그램 종료
if (msg.message == WM_QUIT)
break;
// 꺼내온 메세지 처리
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
// 추기
// 메세지가 큐에 없을 때에는 게임 코드 실행
CEngine::GetInst()->progress();
}
}
// 아래 생략
#pragma once
// 위의 생략
// 추가된 놈들
#include "define.h"
#include "enum.h"
#include "CSelectObj.h"
#pragma once
#define SINGLE(type) public:\
static type* GetInst()\
{\
static type mgr;\
return &mgr;\
}\
private:\
type();\
type(const type& _other) = delete;\
public:\
~type();
#define USE_PEN(DC, TYPE) CSelectObj SelectPen(DC, CEngine::GetInst()->GetPen(TYPE))
#define USE_BRUSH(DC, TYPE) CSelectObj SelectBrush(DC, CEngine::GetInst()->GetBrush(TYPE))
#pragma once
enum PEN_TYPE
{
PEN_RED,
PEN_GREEN,
PEN_BLUE,
PEN_END,
};
enum BRUSH_TYPE
{
BRUSH_RED,
BRUSH_GREEN,
BRUSH_BLUE,
BRUSH_HOLLOW,
BRUSH_BLACK,
BRUSH_END,
};
#pragma once
// 게임 최고 관리자
class CEngine
{
SINGLE(CEngine)
private:
HWND m_hMainWnd; // 메인 윈도우 핸들
POINT m_Resoulution; // 메인 윈도우 해상도
HDC m_hDC; // 메인 윈도우 DC
HPEN m_arrPen[PEN_END];
HBRUSH m_arrBrush[BRUSH_END];
public:
int init(HWND _hWnd, POINT _Resolution);
void progress();
HPEN GetPen(PEN_TYPE _type) { return m_arrPen[_type]; }
HBRUSH GetBrush(BRUSH_TYPE _type) { return m_arrBrush[_type]; }
};
#include "pch.h"
#include "CEngine.h"
CEngine::CEngine()
: m_hMainWnd(nullptr)
, m_Resoulution{}
, m_hDC(nullptr)
, m_arrPen{}
, m_arrBrush{}
{
}
CEngine::~CEngine()
{
// DC 삭제
ReleaseDC(m_hMainWnd, m_hDC);
// Pen 삭제
for (int i = 0; i < PEN_END; ++i)
{
DeleteObject(m_arrPen[i]);
}
// Brush 삭제
for (int i = 0; i < 3; ++i)
{
DeleteObject(m_arrBrush[i]);
}
}
int CEngine::init(HWND _hWnd, POINT _Resolution)
{
m_hMainWnd = _hWnd;
m_Resoulution = _Resolution;
// 윈도우 해상도 변경
SetWindowPos(m_hMainWnd, nullptr, 0, 0, m_Resoulution.x, m_Resoulution.y, 0);
// DC(Device Context) 생성
// DC 란? 렌더링과 관련
// 비트맵에 렌더링하기 위해 필요한 필수 정보 집합체
m_hDC = GetDC(m_hMainWnd);
// DC 보유 정보
// GetDC 로 생성되는 DC 의 정보
// 목적지 비트맵 - 입력 윈도우의 비트맵
// 펜 - BlackPen(Default)
// 브러쉬 - White Brush(Default)
// 자주 사용할 펜 생성
m_arrPen[PEN_RED] = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
m_arrPen[PEN_GREEN] = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
m_arrPen[PEN_BLUE] = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
// 자주 사용할 브러쉬 생성
m_arrBrush[BRUSH_RED] = CreateSolidBrush(RGB(255, 0, 0));
m_arrBrush[BRUSH_GREEN] = CreateSolidBrush(RGB(0, 255, 0));;
m_arrBrush[BRUSH_BLUE] = CreateSolidBrush(RGB(0, 0, 255));;
m_arrBrush[BRUSH_HOLLOW] = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
m_arrBrush[BRUSH_BLACK] = (HBRUSH)GetStockObject(BLACK_BRUSH);
return S_OK;
}
void CEngine::progress()
{
//{
// // RedPen 생성
// HPEN hRedPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
// // DC 에 RedPen 입력, 원래 Black Pen 되돌려받아둠
// HPEN hPrevPen = (HPEN)SelectObject(m_hDC, hRedPen);
// // 사각형 그림
// Rectangle(m_hDC, 50, 50, 150, 150);
// // BlackPen 입력
// SelectObject(m_hDC, hPrevPen);
// // RedPen 삭제
// DeleteObject(hRedPen);
//}
//{
// // DC 에 RedPen 입력, 원래 Black Pen 되돌려받아둠
// HPEN hPrevPen = (HPEN)SelectObject(m_hDC, m_arrPen[BLUE_PEN]);
// // 사각형 그림
// Rectangle(m_hDC, 50, 50, 150, 150);
// // BlackPen 입력
// SelectObject(m_hDC, hPrevPen);
//}
//{
// Ellipse(m_hDC, 50, 50, 150, 150);
// USE_PEN(m_hDC, BLUE_PEN);
// //HBRUSH hRedBrush = CreateSolidBrush(RGB(255, 0, 0));
// HBRUSH hHollowBrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
// HBRUSH hPrevBrush = (HBRUSH)SelectObject(m_hDC, hHollowBrush);
// // 사각형 그림
// Rectangle(m_hDC, 50, 50, 150, 150);
// SelectObject(m_hDC, hPrevBrush);
// //DeleteObject(hRedBrush);
//}
{
USE_PEN(m_hDC, PEN_RED);
USE_BRUSH(m_hDC, BRUSH_BLACK);
Rectangle(m_hDC, 50, 50, 150, 150);
}
}
#pragma once
class CSelectObj
{
private:
HDC m_DC;
HGDIOBJ m_hPrev;
public:
CSelectObj(HDC _dc, HGDIOBJ _SelectedObj);
~CSelectObj();
};
#include "pch.h"
#include "CSelectObj.h"
CSelectObj::CSelectObj(HDC _dc, HGDIOBJ _SelectedObj)
: m_DC(_dc)
, m_hPrev(nullptr)
{
m_hPrev = SelectObject(m_DC, _SelectedObj);
}
CSelectObj::~CSelectObj()
{
SelectObject(m_DC, m_hPrev);
}
1차 24.01.23
2차 24.01.24
3차 24.01.25
4차 24.01.26