< DC를 얻는 방법 >

 

화면으로 출력을 하기 위해서는 반드시 DC가 있어야 하며 DC를 얻는 방법에는 두 가지가 있다.

 

방법 1.

 

GetDC 함수를 사용하여 DC를 얻고 사용 후 ReleaseDC로 해제하는 방법.

 

1
2
HDC GetDC(HWND hWnd);
int ReleaseDC(HWND hWnd, HDC hDC);
cs

 

DC는 주로 하나의 윈도우와 연관되는 출력 정보를 가진다.

GetDC는 hWnd가 가리키는 윈도우에 적당한 DC를 만들어 그 핸들을 리턴한다.

GetDC에 의해 얻어진 핸들은 사용 후에 반드시 ReleaseDC 함수로 해제해야 한다.

 

방법 2.

 

우선 해당 방법은 WM_PAINT 메시지 루틴에서만 사용할 수 있다.

WM_PAINT 메시지 처리 루틴에서는 DC 핸들을 GetDC로 얻지 않고 BeginPaint 함수로 얻으며 핸들을 해제할 때는 EndPaint 함수를

사용한다. GetDC는 DC 핸들을 얻는 일반적인 방법이며 BeginePaint는 WM_PAINT 메시지 내에서 그림 그리기 준비를 하는 좀 더

전문적인 함수이지만 그 외의 메시지에서는 절대로 사용할 수 없다.

 

1
2
HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
BOOL EndPaint(HWND hWnd, CONST PAINTSTRUCT* lpPaint);
cs

 

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

리턴한다. (페인트 정보 구조체는 주소값을 넘겨야 한다.)

 

1
2
3
4
5
6
7
8
typedef struct tagPAINTSTRUCT {
    HDC         hdc;
    BOOL        fErase;
    RECT        rcPaint;
    BOOL        fRestore;
    BOOL        fIncUpdate;
    BYTE        rgbReserved[32];
} PAINTSTRUCT;
cs

 

위의 3개 멤버(hdc, fErase, rcPaint)는 사용자가 사용하는 멤버이며 아래의 3개 멤버(fRestore, fIncUpdate, rgbReserved)는 윈도우즈가

내부적으로 사용하는 멤버이므로 사용자가 건드려서는 안 된다.

또한, PAINTSTRUCT 구조체에는 그리기 속도를 비약적으로 향상시킬 수 있는 정보들이 들어 있는데 이 정보를 활용하는 방법에 대해서는

다음에 설명한다.

김상형 저자님께서 작성하신 윈도우즈 API 정복 3장 출력에 대한 내용입니다.

 

< DC (Device Context) >

 

윈도우즈는 세 가지 동적 연결 라이브러리(DLL)로 구성되어 있다.

 - KERNEL : 메모리를 관리하고 프로그램을 실행시키는 DLL.

 - USER : 유저 인터페이스와 윈도우를 관리하는 DLL.

 - GDI : 화면 처리와 그래픽을 담당하는 DLL.

 

이 세 개의 DLL 중 화면에 원하는 정보를 출력하려면 GDI(Graphic Device Interface) 모듈을 통해야 하며, GDI 모듈은 출력에

필요한 모든 정보를 가지는 데이터 구조체인 DC(Device Context)를 관리한다.

 

DC의 필요성은 다음과 같다.

 - 화면에 그릴 정보를 함수 인자로 넘길 때 DC의 핸들만 넘겨주면 간편하게 사용할 수 있게 된다.

 - DC에는 생성된 윈도우를 기준으로 하는 원점 좌표를 가지고 있기 때문에 윈도우의 위치에 신경쓰지 않아도 된다.

 - DC는 출력이 가능한 영역에만 출력을 내 보내기 때문에 윈도우가 겹치는 문제에 대해 신경쓰지 않아도 된다.

 

이와 같이 DC가 그리기에 필요한 여러 가지 정보와 안전 장치 역할을 하기 때문에 모든 그리기 함수는 DC의 핸들을

첫 번째 인수로 전달받는다.

 

< WM_PAINT 메시지 >

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <Windows.h>
 
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
DWORD WINAPI ThreadFunc(LPVOID);
HINSTANCE g_hInst;
HWND hWndMain;
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,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_RBUTTONDOWN:
        hdc = GetDC(hWnd);
        TextOut(hdc, 100100, TEXT("Beautiful Korea"), 15);
        ReleaseDC(hWnd, hdc);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

 

오른쪽 버튼 클릭시 화면에 문자열을 출력하는 프로그램이다.

그러나 이 프로그램은 문자열을 다른 윈도우로 가리거나 문자열이 모니터 화면 밖으로 나가도록 윈도우를 움직이면, 가려진 문자열

부분은 화면상에서 완전히 지워지고 다시 그려지지 않는 문제점을 가지고 있다.

이유는 운영체제가 개별 윈도우의 화면을 보관 및 복구해 주지 않기 때문이며, 지워진 화면을 복구하는 것은 프로그램 자신이 직접

해야한다.

 

그래서 위와 같은 문제를 해결하기 위해서는 마우스 오른쪽 버튼이 클릭 될 때 출력하는 것이 아니라 화면이 지워질 때마다 문자열을

출력해야 한다. 그러므로 화면이 지워질 때 호출되는 WM_PAINT 메시지를 사용하면 된다.

운영체제는 개별 윈도우의 화면을 보관해 주지는 않지만 윈도우의 일부가 지워졌다는 정보는 개별 윈도우에게 알려주며 그 방법은

WM_PAINT 메시지를 보내주는 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LRESULT CALLBACK 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, 100100, TEXT("Beautiful Korea"), 15);
        EndPaint(hWnd, &ps);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

 

위와 같이 코드를 수정하면 출력한 문자열은 지워져도 항상 다시 복구된다.

 

 

 

+ Recent posts