본문 바로가기

C/C++

[winapi] DC에 대해서...(GetDC / BeginPaint)

### DC (Device Context) ###

 

** DC란?

cairo로 windows에 그림을 그릴때도 Windows DC가 필요하다.

때문에 WinAPI의 DC에 대해서 알 필요가 있다.

 

 

# 기초부터 짚고 넘어가보자

Windows는 3개의 DLL(동적 연결 라이브러리)로 구성되어 있다.

 - KERNEL : 메모리 관리 및 프로그램 실행

 - USER : 유저 인터페이스와 윈도우 관리

 - GDI : 화면 처리와 그래픽 담당

 

Windows API 함수 대부분은 이 세가지 DLL에 의해 제공되는 것이다.

 

즉, Windows의 클라이언트 영역에 그리기를 하려면 이 GDI(Graphics Device Interface) 함수를 사용해야 한다.

그리고 HDC는 'Handle to a Device Context' 로 GDI의 중요한 부분이다.

다시 말해, DC 개체를 참조하는데 사용되는 번호라는 의미다.

 

 

# DC란,

출력에 필요한 모든 정보를 가진 데이터 구조체이며, GDI (Graphic Device Interface) 모듈에 의해 관리된다.

즉 LintTo함수를 만들려면 색상, 굵기, 모양, 시작 좌표, 끝 좌표 등의 많은 정보가 필요하며,

LintTo(hDC, X, Y)처럼 간단히 함수를 만들려면 DC에 모든 정보를 담아서 간편하게 사용할수 있어야 한다.

 

그리고, 윈도우즈 같은 멀티 태스킹 시스템에서는,

다른 윈도우가 내 영역을 일부 가렸을 경우는 그리지 말아야 하는데

이런 복잡 미묘한걸 해결하기 위해 DC를 사용한다.

아님, 직접 구현하등가 -0-

 

** DC 얻기와 해제 (두가지 방법)

① HDC GetDC (HWND hWnd);

    int   ReleaseDC (HWND hWNd, HDC hDC)

 

: GetDC로 DC를 얻고, DC를 사용한후에 ReleaseDC로 해제한다.

DC도 메모리를 차지하므로 반드시 해제해야 한다. 

 

② HDC BeginPaint (HWND hWnd, LPPAINTSTRUCT lpPaint);

    BOOL EndPaint(HWND hWnd, CONST PAINTSTRUCT *lpPaint);

 

: WM_PAINT 메시지 루틴에서만 사용 가능하다. (다른 메시지에서는 절대 사용 불가능)

(WM_PAINT는 작업 영역중 일부가 지워지면(이를 '무효화 영역이'라 함) 다시 그릴때 발생하는 이벤트)

BeginPaint함수는 윈도우 핸들 외에 PAINTSTRUCT(페인트 정보 구조체)가 필요한데

이 PAINTSTRUCT 구조체에 그리기 속도를 비약적으로 향상시킬 수 있는 정보가 있다.

 

 

 

*** GetDC() vs BeginPaint() 

GetDC로 그렸을 경우 cpu 사용률이 17%까지 올라가더라 -0-

BeginPaint로 그렸을 경우는 cpu 사용률이 1%정도

 

왜 그럴까?

WM_PAINT에서 무조건 BeginPaint()를 사용해야 하는 이유가 있다.

WM_PAINT 메시지는 해당 윈도우가 다른 윈도우에 가려지거나, 최소화되거나, 최대화되거나 등의

'무효화 영역'이 발생하면 메시지 큐 맨 끝에 부쳐진다.

그런데 이 '무효화 영역' 때문에 BeginPaint()로 DC를 얻어 출력한 다음 EndPaint()로 그리기를 마치면,

해당 윈도우에 설정된 무효화 영역이 해제된다.

즉, 윈도우 전체가 '유효화' 된다.

 

그런데 GetDC()/ReleaseDC()는 무효화 영역은 상관하지 않고, DC만 얻었다가 돌려주게 된다.

즉, 무효화 영역은 그대로 무효화 영역인 상태가 되는 것이다.

어?? 응???

'무효화 영역'이 발생하면 메시지 큐 맨 끝에 부쳐진다.

그런데 이 '무효화 영역'.....어쩌고저쩌고....

무한 반복이다.

 

(이 내용 출처 : 여기(www.winapi.co.kr))

 

 

**  지금까지 이론내용이고, 구현 내용을 보면,

GetMessage()는 메시지 큐에서 메시지를 가져온 후에 해당 메시지를 지운다.

그러나, WM_PAINT 메시지는 큐에서 지우지 않는다.!@!#

이 메시지를 BeginPaint()에서 지우는 것이다.....

 

만약 WM_PAINT에서 GetDC()를 사용하면 이 메시지를 지우지 않고,

큐에서 무한 반복으로 WM_PAINT 메시지를 가져와서 클라이언트 영역을 그릴 것이다.

 

(이 내용 출처 : 이블로그 참조)

 

 

그러니 cpu 사용률이 올라갈수 밖에...

 

 <출처 : 도서 - Windows API 정복>