반응형

장치 컨텍스트는 윈도우가 디스플레이와 프린터에 대한 액세스를 관리하는데 사용하는 도구이다.
윈도우즈 응용프로그램은 화면에 직접 쓰는 일이 절대로 없으며 DC의 핸들을 이용한다. 그러면 OS가 DC의 내용을 화면에 표현하는 내용을 처리해준다.
즉. DrawText (hdc, TEXT("Hello", -1, &rect, NULL);
에서 hdc 즉 device context에 쓰는것이지 화면에 쓰는게 아니다.

윈도우가 알아서 device context를 읽어서 화면에 쓰는것이다.
예) BITMAP그림 -> 메모리DC <-> 화면DC -> OS -> 화면출력

------------------------------------------------------------------------------------------------------

장치 문맥(Device context) 라는 것을 살펴보도록 하자.
본질적으로, 장치 문맥은 출력에 쓰이는 하나의 자료 구조라 할 수 있다.
윈도우 안에서의 그래픽 출력을 하기 위해선, 그래픽을 위한 장치 문맥을 사용하여야 한다.
그러나 프린터 출력의 경우에는 프린터를 위한 장치 문맥을 사용하게 된다.
윈도우로의 모든 출력은 그래픽 자치 문맥을 거치게 된다.
그래픽 장치 문맥은 GetDC() 함수를 통해서 얻는다. 예를 들면, 다음과 같다.

hDC = GetDC(hwnd);

이 문장은 hwnd가 가리키는 윈도우에 대한 그래픽 장치 문맥을 얻어서 그에 대한 핸들을 hDC에 넣는다.
이후에 윈도우에 뭔가를 출력할 때 이 hDC 를 사용하게 된다.
명심할 것은, 윈도우에 뭔가를 출력하려면 반드시 장치 문맥이 있어야 한다는 점이다.

------------------------------------------------------------------------------------------------------
KERNEL - 메모리를 관리하고 프로그램을 실행
   USER - 유저 인터페이스와 윈도우를 관리
   GDI - 화면 처리와 그래픽을 담당


   윈도우즈 API 함수의 대부분이 이 세 가지 DLL에 의해 제공되고 있다.
   화면으로 출력되는 모든 글자와 그림은 GDI를 통해야 하기 때문이다
  
   DC(Device Context)란 출력에 필요한 모든 정보를 가지는 데이터 구조체이며
   GDI 모듈에 의해 관리된다. 어떤 폰트를 사용할 것인가, 선의 색상과 굵기,
   채움 무늬와 색상, 출력 방법 등등이 모두 출력에 필요한 정보들이다.
   화면 출력에 DC가 필요한 이유들이다      


화면출력에 관여하는    DC(Device Context) 에 대하여 알아보자



#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPSTR lpszClass="TextOut";

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,"한군의창",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;
 switch(iMessage) {
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_LBUTTONDOWN:
  hdc=GetDC(hWnd);
  TextOut(hdc,100,100,"이렇게 문자열이 출력 된당~",26);

  //영문관 공백과 기호는 각각 1byte 차지하지만 한글은 2byte 이므로 26byte 공간이 필요하다
  //일단 실행하면 생성된 창 아무곳에서나 마우스 클릭을 하게되면 문자가 나타나게된다.

  ReleaseDC(hWnd, hdc);
  return 0;
 }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

/* WndClass 구조체의 윈도우 클래스명을 지정하는 lpszClass 전역 문자열을 textOut로 해준 후
   WndProc에 WM_LBUTTONDOWN 메시지를 처리하는 코드가 추가되었는데 보다시피 처리해야할 메시지가
   추가될 때마다 switch문의 case만 늘려주면 된다.
  
   문자열을 출력하기 전에 GetDC 함수로 DC를 얻고 TextOut 함수로 문자열을 출력한 후 ReleaseDC

   함수로 DC를 해제한다 */

 

문자열은 출력했지만 한가지 문제점이 있다

 

/*문자열이 출력된 윈도우를 다른 윈도우로 살짝 가렸다가 다시 드러나도록 하거나 윈도우의 크기를 변경시키면
  출력되어 있던 문자열이 사라져 버릴 것이다. 윈도우즈는 가려졌던 윈도우의 화면을 보관 및 복구해 주는 책임을
  지지 않으며 화면을 복구(Repaint)하는 책임은 전적으로 프로그램 자신에게 있다

  마우스 왼쪽 버튼을 누르면 문자열을 출력하는 것이 아니라 화면이 지워질 때마다 문자열을 출력하도록 해 주어야 한다
  윈도우는 개별 윈도우의 화면을 보관해 주지는 않지만 대신 윈도우의 일부가 지워졌다는 사실을 프로그램으로 알려주며
  알려주는 방법은 WM_PAINT 메시지를 보내주는 것이다. WM_PAINT 메시지는 "너의 작업 영역이 일부 지워졌으니까 빨리
  복구해"라는 뜻이다

  그르므로 이런 제어를 할 수있게문장을 밑에소스와 같이 바꿔주면 된다.
 
  long FAR PASCAL WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 switch(iMessage) {
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  TextOut(hdc,100,100,"이렇게 문자열이 재생 된당~",26);
  EndPaint(hWnd,&ps);
  return 0;
 }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
   
 
  문자열 출력문이 WM_PAINT 메시지 처리 루틴에 있으므로 여기서 출력한 문자열 출력은 지워져도 다시 복구되므로 항상
  그 자리에 있는 것처럼 보이게 된다. 모든 프로그램은 현재 화면에 그려진 내용을 철저하게 기억하거나 다시 그리기
  위한 준비를 해 놓아야 한다.*/

 

DC를 얻는 방법


화면으로 출력을 하기 위해서는 반드시 DC가 있어야 하며 DC를 얻는 방법에는 두가지 방법이 있다. 그 첫번째 방법은 앞의

예제에서 보인대로 GetDC함수를 사용하여 DC를 얻고 사용 후 ReleaseDC로 해제해 주는 것이다.

 

HDC GetDC(HWND hWnd);
int ReleaseDC(HWND hWnd,HDC hDC);

 

DC는 주로 하나의 윈도우와 연관되는 출력정보를 가진다. 그래서 인수로 어떤 윈도우에 대한 DC가 필요한가를 밝혀주어야 한다. GetDC는 hWnd가 가리키는 윈도우에 적당한 DC를 만들어 그 핸들을 반납한다. 앞의 예제에서는 이 핸들을 HDC형의 hdc변수에

대입한 후 이 핸들값을 TextOut 함수의 첫번째 인수로 사용하였다. GetDC에 의해 얻어진 핸들은 사용 후에 반드시 ReleaseDC 함수에

 의해 해제되어야 한다. DC도 메모리를 차지하므로 할당 후 해제 원칙이 반드시 준수되어야 한다.

 

DC를 얻는 두번째 방법은 WM_PAINT 메시지 루틴에서만 사용할 수 있다. WM_PAINT 메시지 처리 루틴에서는 DC 핸들을 GetDC로

얻지 않고 BeginPaint 함수로 얻으며 핸들을 해제할 때는 EndPaint 함수를 사용한다. GetDC는 DC 핸들을 얻는 일반적인 방법이며

BeginPaint는 WM_PAINT 메시지내에서 그림 그리기 준비를 하는 좀 더 전문적인 함수이다.

 

HDC BeginPaint(HWND hwnd, LPPAINTSTRUCT lpPaint);
BOOL EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint);

 

BeginPaint 함수는 윈도우 핸들 외에도 페인트 정보 구조체를 인수로 요구하며 이 구조체는 그림 그리기에 필요한 정보를 담는다.

 

typedef struct tagPAINTSTRUCT
{
    HDC         hdc;
    BOOL        fErase;
    RECT        rcPaint;
    BOOL        fRestore;
    BOOL        fIncUpdate;
    BYTE        rgbReserved[16];
} PAINTSTRUCT;

 

앞의 세 멤버는 사용자가 사용하는 멤버이며 나머지 세 멤버는 윈도우즈가 내부적으로 사용하므로 사용자가 건드려서는 안된다.

WndProc 선두에서 PAINTSTRUCT형의 구조체를 지역 변수로 선언하고 BeginPaint 함수를 호출한 후 그 리턴값을 hdc라는 변수에

대입받아 GDI 함수에 사용하고 EndPaint로 그리기를 종료하면 된다.
 


 

반응형
Posted by Real_G