해결된 질문
작성
·
159
·
수정됨
0
안녕하세요 선생님
강의에서 옛날 윈도우(XP)에서는 pOldPen = dc.SelectObject()를 안해주면 문제가 생길수 있고, 요즘 윈도우즈에서는 괜찮을거라고 하셨는데요.
이부분에 대해서 조금 더 자세하게 알고 싶습니다.
테스트용으로 코드를 작성했습니다.
void CPenBrushDemoView::OnPaint()
{
CPaintDC dc(this); // device context for painting
CBrush NewBrush;
//비트맵 클래스 객체를 선언하여 비트맵 리소스 로딩.
CBitmap Bmp;
Bmp.LoadBitmap(IDB_BITMAP1);
//로딩된 비트맵 리소스로 패턴 브러시 생성.
NewBrush.CreatePatternBrush(&Bmp);
CBrush* pOldBrush = dc.SelectObject(&NewBrush);
//클라이언트 뷰 클래스의 클라이언트 영역 크기를 알아내고
//그 크기에 해당하는 네모를 그림.
CRect Rect;
GetClientRect(&Rect);
dc.Rectangle(&Rect);
dc.SelectObject(pOldBrush);
DWORD style[] = {6, 3};
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = RGB(255, 0, 0);
// 여기서부터...
CPen* pOldPen;
CPen FirstPen;
{
FirstPen.CreatePen(PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT,
20, &lb, 2, style);
pOldPen = dc.SelectObject(&FirstPen);
dc.MoveTo(40, 40);
dc.LineTo(240, 40);
}
CPen SecondPen;
{
SecondPen.CreatePen(PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT,
40, &lb, 2, style);
dc.SelectObject(&SecondPen);
dc.MoveTo(40, 240);
dc.LineTo(240, 240);
}
{
CPen ThirdPen;
ThirdPen.CreatePen(PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT,
60, &lb, 2, style);
dc.SelectObject(&ThirdPen);
dc.MoveTo(40, 440);
dc.LineTo(240, 440);
}
dc.MoveTo(40, 640);
dc.LineTo(240, 640);
dc.SelectObject(pOldPen);
}
위 코드에서는 총 4개의 직선을 그리고 있습니다.
여기서, CPen ThirdPen은 스코프 안에서 소멸자가 불러질 때 DeleteObject()가 실행되면서 gdi는 없어집니다. 하지만 디바이스컨텍스트(dc)는 계속 해당 gdi를 가리키고 있습니다. 그런데 그 이후에 dc는 지워진 gdi의 방식대로 직선을 그리고 있습니다.(dc.MoveTo(40, 640); dc.LineTo(240, 640);) dc가 가리키고 있던 gdi가 지워졌는데도 불구하고 어떻게 기존의 방식대로 그릴수 있는지 이유를 모르겠습니다.
그리고 위의 코드에서,
dc.MoveTo(40, 440);
dc.LineTo(240, 440);
를 지우게 되면 ...
{
CPen ThirdPen;
ThirdPen.CreatePen(PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT,
60, &lb, 2, style);
dc.SelectObject(&ThirdPen);
// dc.MoveTo(40, 440);
// dc.LineTo(240, 440);
}
ThirdPen이 스코프를 벗어난 이후 마지막 직선은 ThirdPen의 방식이 아닌 SecondPen의 방식으로 그려지고 있습니다. 좀 전의 위에서 동작한 방식과 일관성이 맞지 않는것같아요.
질문글이 길어서 요약을 해보자면..
2개의 소스코드가 사소한 차이가 있는데 왜 DC가 동작하는 방식이 다를까요?
DC와 GDI에 대한 저의 생각에서 혹시 오류가 있을까요?
답변 1
1
저도 정확히는 알 수 없습니다. 그러려면 윈도우 GDI 관련 요소를 디버깅하고 분석해야 하기 때문입니다. 그러나 추정은 해볼 수 있을 것 같습니다. 조금 이상한(?) 실험용 코드입니다만...추정으로 말씀드리자면 아마도 지역변수로 선언된 CPen 클래스 인스턴스들이 아직 메모리에 남아있어서 발생한 문제로 보입니다.
모든 지역변수는 Stack 메모리를 사용합니다. 그리고 스택은 스코프를 벗어날 때 크기가 줄어듭니다. 하지만 그렇다고 기존 값을 모두 0으로 Clear하지도 않습니다. 그리고 우연히 위치가 맞는 지점에서 값을 읽는다면 기존의 값이 그대로 출력되기도 합니다. 이와 같은 문제는 자동변수인 지역변수의 주소나 참조를 반환했을 때 발생하는 문제와 매우 흡사합니다.
참고하시기 바랍니다. 😄