Programming Windows

FrontPage|FindPage|TitleIndex|RecentChanges| UserPreferences P RSS

요약본

1장 시작하기

API공부 세가지 조건
  1. MicrosoftWindows 구성 알기
  2. CLanguage를 알아야 한다.
  3. Windows 프로그래밍에 적합한 32bit C 컴파일러와 개발 환경이 설치되어 있어야 한다.

2장 UniCode


3장 Windows와 메시지

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("HelloWin");
	HWND		hWnd;
	MSG		msg;
	WNDCLASS	  wndClass;

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

	if(!RegisterClass(&wndClass))                 // 1. 윈도우 클래스 등록
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
		return 0;
	}

	hWnd = CreateWindow(szAppName,                // 2. 윈도우 생성
					    TEXT("The Hello Program"),
						WS_OVERLAPPEDWINDOW,
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						NULL,
						NULL,
						hInstance,
						NULL);

	ShowWindow(hWnd, iCmdShow);                   // 3. 윈도우를 보여준다
	UpdateWindow(hWnd);                           // 4. 윈도우 갱신

	while(GetMessage(&msg, NULL, 0, 0))           // 5. 메세지를 받는다
	{
		TranslateMessage(&msg);              // 6. 키보드 메시지를 번역
		DispatchMessage(&msg);               // 7. 윈도우 프로시저에 메시지를 보낸다.
	}                                             // 8. 5,6,7 반복

	return msg.wParam;
}

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

	switch(message)
	{
	         case WM_CREATE:
		     return 0;
	         case WM_PAINT:
		     hdc = BeginPaint(hWnd,&ps);
		     TextOut(hdc,100,100,"Hello, Windows!",15);
		     EndPaint(hWnd,&ps);
		     return 0;
	         case WM_DESTROY:
		     PostQuitMessage(0);
		     return 0;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

  • 함수들을 순서대로 나열해 보았다.
    RegisterClass();                     // 1. 윈도우 클래스 등록
    CreateWindow();                      // 2. 윈도우 생성
    ShowWindow(hWnd, iCmdShow);          // 3. 윈도우를 보여준다
    UpdateWindow(hWnd);                  // 4. 윈도우 갱신
    GetMessage()                         // 5. 메세지를 받는다
    TranslateMessage(&msg);              // 6. 키보드 메시지를 번역
    DispatchMessage(&msg);               // 7. 윈도우 프로시저에 메시지를 보낸다.
     

  • 윈도우 클래스
윈도우는 항상 윈도우 클래스를 기반으로 하여 생성된다. 윈도우 클래스는 윈도우에 대한 메시즐 처리해 주는 윈도우 프로시저를 식별한다.
하나 이상의 윈도우가 하나의 윈도우 클래스를 기반으로 생성될 수 있다. 예를 들어 모든 단추 윈도우는 동일한 윈도우 클래스를 기반으로 하여 생성된다.

typedef struct
{
	UINT 		style;
	WNDPROC 	         lpfnWndProc;
	int 		cbClsExtra;
	int 		cbWndExtra;
	HINSTANCE 	hInstance;
	HICON 		hIcon;
	HCURSOR 	         hCursor;
	HBRUSH 		hbrBackground;
	LPCSTR 		lpszMenu;
	LPCSTR 		lpszClassName;
}WNDCLASS, *PWNDCLASS;
 

  • 윈도우 생성하기
윈도우 클래스는 윈도우의 일반적인 특성들을 정의하여 줌으로써 동일한 윈도우 클래스가 여러 개의 다른 윈도우를 생성하는 데 사용될 수 있도록 허용한다. 앞으로 CreateWindow를 호출하여 원도우를 생성할 때 사용자는 윈도우에 대한 상세한 정보를 지정하게 된다.

  • 메시지 루프
    while(GetMessage(&msg, NULL, 0, 0))           // 5. 메세지를 받는다
    {
    	TranslateMessage(&msg);              // 6. 키보드 메시지를 번역
    	DispatchMessage(&msg);               // 7. 윈도우 프로시저에 메시지를 보낸다.
    }                                             // 8. 5,6,7 반복
     
프로그램은 스스로 사용자로부터의 키보드와 마우스 입력을 읽을 수 있도록 해야 한다.
Windows는 현재 Windows에서 실행되고 있는 각각의 Windows 프로그램에 대해 메시지 큐를 유지한다.

  • 메시지
    typedef struct tagMSG
    {
        HWND     hwnd;
        UINT     message;
        WPARAM   wParam;
        LPARAM   lParam;
        DWORD    time;
        POINT    pt;    
    }
     

  • 윈도우 프로시저(를 호출하는 WIndows)
일반적으로 프로그램은 윈도우 프로시저를 직접 호출하지 않는다. 윈도우 프로시저는 거의 항상 Windows로부터 호출된다.

  • 메시지 큐 (message queue)
큐에 저장된 메시지는 윈도우에 의해 프로그램의 메시지 큐에 저장된 것들이다. 프로그램의 메시지 루프에서 메시지가 얻어져 윈도우 프로시저에 할당된다.
큐에 저장되지 않는 메시지는 윈도우에 의한 윈도우 프로시저에 대한 직접적인 호출의 결과이다.
  • CreateWindow를 호출할때 윈도우 프로시저에게 WM_CREATE 메시지를 보낸다.
  • ShowWindow를 호출할 때 윈도우 프로시저에게 WM_SIZE, WM_SHOWWINDOW 메시지를 보낸다.
  • UpdateWindow를 호출할 때 윈도우 프로시저에게 WM_PAINT 메시지를 보낸다.
윈도 프로시저는 윈도우에 대한 모든 메세지-큐에 저장된 메시지와 그렇지 않은 메시지를 얻게 된다.

4장 문자출력

  • 클라이언트 영역 - 프로그램이 자유로이 그릴 수 있고 사용자에게 시각적인 정보를 제공 해 주는 윈도우 한 부분이다.
  • 장치독립적 프로그래밍 - 출력 장치와 상관없이(출력 장치의 시스템 메카니즘을 모르고도) GDI 통하여 프로그래밍 한다.

WM_PAINT 메시지

  • 문자 모드환경 - 프로그램 출력은 그대로 유지되고, 갑작스럽게 사라지지도 않을 것이다. 따라서 프로그램은 표시된 화면을 다시 그리기 위한 정보를 버릴 수 있다.
  • 그래픽 모드환경 - 윈도우 창이 다른 창에 의해 지워 질 수 가 있다. 이 처럼 정보가 손실되므로 정보를 출력 정보는 저장하여야 한다.

UpdataWindow 첫 번째 WM_PAINT메시지 전달.

  • 사용자가 윈도우를 옮기거나 제거했을 때 이전에 감추어졌던 윈도우 영역이 보이게 될때
  • 사용자가 윈도우의 크기를 조정했을 때
  • 프로그램이 클라이언트 영역의 일부를 스크롤 하기 위해 ScrollWindowScrollDC함수를 사용하는 경우
  • 프로그램이 InvalidateRectInvalidateRgn함수를 사용하여 WM_PAINT메시지를 생성할 때
  • Windows가 윈도우의 일부가 겹친 대화상자나 메시지 상자를 제거할 때
  • 메뉴가 나타났다가 사라질 때
  • 풍선 도움말이 나타났을 때

클라이언트 영역이 일부분이 일시적으로 겹쳤을 경우 Windows는 화면의 영역을 저장하고 나중에 복구
  • 마우스커서가 클라이언트 영역을 지나갈 때
  • 아이콘이 클라이언트 영역을 지나서 드래그 될 때

유효영역과 무효영역
  • 무효영역(Invalid region) - 다시그리기위한 영역. 대화상자가 제거되었을 때 대화상자가 있던 영역만 복원
  • InvalidateRect함수 - 자기자신의 클라이언트 영역에서 사각형을 무효로 만들 수 있다.

GDI(Graphics Device Inerface) : 윈도우의 클라이언트 영역에 그리기를 하려면 Windows의 GDI함수를 사용해야 한다.
hdc(handle to a device context) : 모든 GDI함수의 첫 인자

장치 컨텍스트

  • 핸들은 단순히 Windows가 내부적으로 개체를 참조하는 데 사용하는 번호라는 것을 기억할 것이다.
  • 장치 컨텍스트 핸들은 GDI함수들에 대한 윈도우의 패스포트이다.
  • GDI에 의해 내부적으로 관리되는 데이터 구조체이다.
  • 비디오 디스플레이나 프린터 같은 특정 디스플레이 장치와 연결되어 있다.

장치 컨텍스트 핸들 얻기
방법1. WM_PAINT 메시지를 처리할 때 이 방법 사용.
case WM_PAIN:
 hdc = BeginPaint(hwnd,&ps);
 //GDI 함수사용
 EndPaint(hwnd,&ps);
 return 0;
방법2. WM_PAINT이외의 다른 메시지, 장치 컨텍스트에 대한 정보를 얻는 등의 다른 목적으로.
hdc = GetDC(hwnd);
//GDI 함수사용
ReleaseDC(hwnd, hdc);

스크롤 바

생성
WS_VSCROLL(수직 스크롤), WS_HSCROLL(수평 스크롤) CreateWindow의 세 번째 인자에 포함.

디폴트로 스크롤 바의 범위는 0 ~ 100 이지만 변경가능.
SetScrollRange(hwnd, iBar, iMin, iMax, bRedraw);

iBar SB_VERT or SB_HORZ
iMin,iMax 최소,최대
bRedraw true : Windows가 새로운 범위를 바탕으로 스크롤 바를 다시 그리기 원하면

Windows의 책임 영역
  • 스크롤 바에 대한 모든 마우스 메시지를 처리한다.
  • 사용자가 클릭했을 때 반전된 화면을 제공한다.
  • 범위 내에서 사용자가 막대를 이동시킬 때 막대를 이동시킨다.
  • 스크롤 바 메시지를 스크롤 바를 포함하고 있는 윈도우의 윈도우 프로시저에 전달한다.

프로그래머의 책임 영역
  • 스크롤 바의 범위와 위치를 초기화한다.
  • 윈도우 프로시저에 대한 스크롤 바 메시지를 처리한다.
  • 막대의 위치를 업데이트 한다.
  • 스크롤 바의 변화에 대하여 클라이언트 영역을 변경시킨다.

SetScrollInfo(hwnd, iBar, &si, bRedraw);
GetScrollInfo(hwnd, iBar, &si);

typedef struct tagSCROLLINFO
{
UINT cbSize;
UINT fMask;
int nMin;
int nMax;
UINT nPage;
int nPos;
int nTrackPos;
}

si.cbSize = sizeof(SCROLLINFO);
si.cbMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = NUMLINES - 1;
si.nPage = cyClient / cyChar;
SetScrollInfo(hwnd,SB_VERT, &si, TRUE);

SIF_RANGE nMin,nMax(스크롤 바 범위) 설정
SIF_PAGE nPage(페이지 크기) 설정

5장 기본적인 그리기

GDI철학

GDI32.DLL 이런 동적 링크 라이브러리는 설정되어 있는 비디오 출력이나 프린터의 장치 드라이버에 있는 루틴들을 호출한다. 비디오 드라이버는 비디오 출력 하드웨어를 엑세스하며 프린터 드라이버는 GDI 명령을 각각의 프린터가 이해할 수 있는 코드나 명령으로 변환한다.
GDI의 주된 목적 중의 하나는 장치에 구애 받지 않고 그랙픽을 지원하는 것이다. 다른 종류의 출력 장치에 대한 독특한 특성들로부터 프로그램을 분리시킴으로써 이런 목적을 완수한다.

  • 가상 좌표계 - 하드웨어에 구애받지 않게
  • 장치 좌표계 - 하드웨어에 더욱 밀접

GDI함수 호출
  • 장치 컨텍스트를 얻고(혹은 생성하고) 해제(혹은 소멸시키는)하는 함수들
  • 장치 컨텍스트에 대한 정보를 획득하는 함수들
  • 무엇인가를 그리는 함수들
  • 장치컨텍스트의 속성을 설정하고 얻어내는 함수들
  • GDI개체를 다루는 함수들

GDI의 근본 : 선과 곡선, 칠해진 영역, 비트맵, 텍스트

다른 것들 : 매핑 모드와 transform, 메타 파일, 영역, 경로, 클리핑, 팔레트, 인쇄

장치컨텍스트 : 화면이나 프린터 같은 그래픽 출력 장치에 그리고자 할 때에는 반드시 먼저 장치 컨텍스트에 대한 핸들을 얻어야 한다. 프로그램에 이 핸들을 주는 것으로 Windows는 사용자가 그 장치를 사용할 수 있도록 허가해 준다.

GetDCReleaseDC는 클라이언트 영역에 있을 수도 있는 무효영역을 유효화 하지 않는다.

전체 윈도우에 적용할 수 있는 장치 컨텍스트의 핸들을 얻는다.
hdc = GetWindowDC(hwnd);
ReleaseDC(hwnd, hdc);

장치 컨텍스트에 대한 핸들을 얻어내는 보다 더 일반적인 함수
CreateDC(pszDriver, pszDevice, pszOutput, pData);
hdc = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL); //예) 전체 출력에 장치 컨텍스트 핸들

그리지는 않고 단지 장치 컨텍스트에 대한 정보만을 필요할 때도 있다.
CreateIC(TEXT("DISPLAY"),NULL,NULL,NULL); //예) 전체 출력에 장치 컨텍스트 핸들

비트맵으로 작업할 때에는 메모리 장치 컨텍스트
hdcMem = CreateCompatibleDC(hdc);
DeleteDC(hdcMem);

장치컨텍스트 정보 얻기
iValue = GetDeviceCaps(hdc, iIndex);



"; if (isset($options[timer])) print $menu.$banner."
".$options[timer]->Write()."
"; else print $menu.$banner."
".$timer; ?> # # ?>