Notice
Recent Posts
관리 메뉴

Hacking Arts

출력 / GDI / DC 본문

Programing/API Programing

출력 / GDI / DC

Rakehell 2014. 10. 10. 02:02

- 윈도우즈 운영체제 구성 요소

1) 커널 - 운영체제의 두뇌 역할

2) 유저 - 사용자 인터페이스 및 윈도우를 관리하는 역할

3) GDI(Graphic Device Interface) - 그래픽을 담당


-GDI란?

그래픽 장치와 인터페이스를 하는 모듈이다. 윈도우즈 내부에 설정되어 있는 그래픽 장치와 연결하여 제어하겠다는 의미이다. 그래픽 카드가 대표적이며 그래픽 카드를 설치하면 우리는 OS에 그에 맞는 드라이버를 설치하게 된다. 이 드라이버를 통해 윈도우와 그래픽 카드와 정보 교환이 이루어지며 윈도우 입장에서는 디바이스 드라이버를 통해서 현재 화면의 크기 및 컬러 수와 같은 정보를 얻어오기도 하고 반대로 디바이스 드라이버를 통해 그래픽 출력에 관한 옵션을 설정도 가능하다. 즉, 운영체제와 그래픽 카드 사이에는 디바이스 드라이버를 통해서 정보 교환이 가능하고, 또한 윈도우즈 입장에서는 제어도 가능하다. 그러므로 윈도우즈는 이 그래픽 제어 관련 인터페이스를 응용 프로그램에서 사용할 수 있도록 제공하는데 그것이 바로 GDI이다. 


[ 그림 1 GDI ]


- DC란?

DC(Device Context)에 대해서 알아보자. 윈도우는 여러가지의 윈도우가 여러 개가 실행된다. 그리고 각 응용프로그램의 윈도우 마다 화면 형태가 다르다 이 의미는 각 윈도우 마다 화면 메모리가 존재한다가 된다. 즉 윈도우가 연결되어 있는 화면은 실제 우리가 보고 있는 모니터 화면이 아니다. 각각 윈도우의 화면 메모리에 그리고 그것들은 윈도우 운영체제에서 조화롭게 출력해 주는 것이다. 이러한 메모리를 제어하는 것이 바로 DC라는 핸들이다. 모든 그래픽 출력에 있어서 각각의 윈도우는 모두 DC핸들(HDC)를 얻어야 한다. 정리하면 DC란 출력에 필요한 모든정보(선의 색상 및 굵기, 폰트 등..)를 가지고 있는 구조체라고 할 수 있으며, 윈도우는 각각의 윈도우에게 DC라는 핸들을 부여한다.


- DC를 얻는 법

1) WM_PAINT 메시지 처리 루틴에서만 얻어오는 방법으로 BeginPaint함수와 EndPaint 함수를사용하는 방법이다.


[ 그림 2 BeginPaint ]


[ 그림 3 EndPaint ]


[ 그림 4 PAINTSTRUCT ]


- BeginPaint의 인자는 윈도우와 연계되는 화면 출력 메모 핸들러를 받고 두번째 인자는 ps는 PAINTSTRUCT 구조체로 실제 화면 출력할 화면 메모리의 영역 정보를 가진다. EndPaint도 동일하다.

2) GetDC로 얻고 ReleaseDc로 해제하는 함수들이다. 주로 잠깐 DC를 얻을 때 사용하는 방법이다. 


[ 그림 5 GetDC ]

[ 그림 6 ReleaseDC ]


- GetDC는 윈도우 핸들러만 받는다. 화면에 한 번 그리고 , 지워진 영역에 대해서 보장을 해주지 않는다. 


- 여기까지 클라이언트 영역의 DC이다. 클라이언트 영역이란 타이틀 바 및 경계바 등을 제외한 출력할 수 있는 뷰 영역을 말한다. 

[ 그림 7 GetWindowDC ]


- GetWindowDC를 사용하면 윈도우 타이블바 및 경계를 포함한 윈도우의 전체 영역의 DC를 받을 수 있다.

[ 그림 8 타이틀 바 삭제 ]

이런식으로 윈도우 타이틀 바의 DC를 받아와 삭제가 가능하다.


-아래는 예제 실행 소스 코드

#include
#include

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPWSTR lpszClass = L"output";

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	g_hInst = hInstance;

	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	WndClass.hInstance = hInstance;
	WndClass.lpfnWndProc = (WNDPROC)WndProc;
	WndClass.lpszClassName = lpszClass;
	WndClass.lpszMenuName = NULL;
	WndClass.style = CS_HREDRAW | CS_VREDRAW;

	RegisterClass(&WndClass);

	hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);

	ShowWindow(hWnd, nCmdShow);

	while (GetMessage(&Message, 0, 0, 0)){
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}

	return Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	long style;

	switch (iMessage)
	{
	case WM_CREATE:
		//타이틀바 삭제
		style = ::GetWindowLong(hWnd, GWL_STYLE);
		style &= ~WS_CAPTION;
		::SetWindowLong(hWnd, GWL_STYLE, style);
		//메뉴바 삭제
		::SetMenu(hWnd, NULL);
		return 0;
	case WM_LBUTTONDOWN:
		//hdc = BeginPaint(hWnd, &ps);
		//hdc = GetDC(hWnd);
		hdc = GetWindowDC(hWnd);
		TextOut(hdc, 100, 50, L"GetWindowDC를 이용한 출력", 11);
		//EndPaint(hWnd, &ps);
		ReleaseDC(hWnd, hdc);
		return 0;
	/*case WM_PAINT:
		//hdc = BeginPaint(hWnd, &ps);
		//hdc = GetDC(hWnd);
		//TextOut(hdc, 100, 50, L"GetWindowDC를 이용한 출력", 11);
		//EndPaint(hWnd, &ps);
		ReleaseDC(hWnd, hdc);
		return 0;*/
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

-참고 자료

API Programing / 이창현 / 혜지원