김상형 저자님께서 작성하신 윈도우즈 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