640 likes | 786 Views
Chapter 3 Windows 9x/XP/2000 프로그래밍의 기본. 이 장에서는. 윈도우즈의 역사 살펴보기 윈도우즈를 특별하게 만드는 다중작업 (Multitasking) 윈도우즈 프로그래밍의 기본 이해하기 헝가리식 표기법의 요소들 알아보기 간단한 윈도우즈 응용 프로그램 만들기 윈도우즈 응용 프로그램의 여러 부분들 확인하기. 윈도우즈의 역사 - 프로그래머의 관점. 스티브 잡스가 애플 매킨토시를 개발하면서 최초로 윈도우즈 기반 컴퓨터 환경을 대중에게 소개
E N D
이 장에서는... • 윈도우즈의 역사 살펴보기 • 윈도우즈를 특별하게 만드는 다중작업(Multitasking) • 윈도우즈 프로그래밍의 기본 이해하기 • 헝가리식 표기법의 요소들 알아보기 • 간단한 윈도우즈 응용 프로그램 만들기 • 윈도우즈 응용 프로그램의 여러 부분들 확인하기
윈도우즈의 역사 - 프로그래머의 관점 • 스티브 잡스가 애플 매킨토시를 개발하면서 최초로 윈도우즈 기반 컴퓨터 환경을 대중에게 소개 • 스크린상에 윈도우를 띄우는 아이디어는 오래 전에 제록스 팔로 알토 연구소에서 개발. • 마이크로소프트 윈도우즈 1.0은 1985년에 출시 • 별다른 기능도 없었고, 보기에도 별로였으며, 너무 많은 컴퓨터 자원이 필요해서 당시의 8086 기계에서는 잘 돌지도 않았다. • 윈도우 2.0 • 계산기 같은 프로그램을 개발할 수도 있었다. • 같은 기능을 도스용으로 작성하면 더 적은 메모리를 사용하며 거의 열 배 정도 빠른 프로그램으로 만들 수 있었다.
윈도우즈의 역사 - 프로그래머의 관점 • 1990년에 윈도우즈 3.0이 출시 • 이제는 정말로 보아줄만했다 • 도스 응용 프로그램이긴 했지만 다중작업을 지원 • 수많은 응용 프로그램들이 존재 • 윈도우즈 3.1은 1992년 • 빠르고, 보기도 좋았다 • 도스의 목숨을 위협 • 오디오와 비디오를 지원 • PC를 소규모 워크스테이션에 필적하는 멀티미디어 및 업무용 컴퓨터로 변신시켰다. • 그럼에도 불구하고, 윈도우즈 3.1은 여전히 32비트 컴퓨터에서 돌아가는 16비트 프로그램이었다.
윈도우즈의 역사 - 프로그래머의 관점 • 1995년 후반에 윈도우즈 95 • 인터페이스는 직관적이었고 • 커널은 진정한 다중작업과 다중스레드를 지원했으며 • 네트워크와 멀티미디어 등의 많은 것을 지원했다 • 프로그래머의 입장에서는 32비트 운영체제였다. • 처음으로 윈도우즈 프로그래밍을 만드는 작업이 꽤 쉬워졌다. • 윈도우즈 98이 1998년 후반 • 수많은 새로운 기술들(ActiveX, COM, DCOM, 동적 HTML)을 추가한 윈도우즈 95의 정리된 버전
윈도우즈의 역사 - 프로그래머의 관점 • 2000년경에 윈도우즈 Me(Millennium Edition) • 윈도우즈 Me는 일반 사용자들 대상 • 윈도우즈 98을 다시 포장 • 윈도우즈 2000 • 대단히 진보된 운영체제로, 거의 처음부터 완전하게 재 작성 • 2001년에는 윈도우즈 XP • 일반사용자를 위해 출시 • 윈도우즈 98이나 윈도우즈 Me와 달리, 윈도우즈 XP는 탄탄한 운영체제 • 프로그램의 호환성 • 프로그래머의 관점에서 보면, 윈도우즈 95, 98, Me, 2000 그리고 XP들이 다 똑같다. 제대로 작성된 Win32 응용 프로그램들은 대부분의 윈도우즈 버전에서 돌아간다. • DirectX가 설치되어 있다면, 윈도우즈 98에서 작성한 프로그램도 윈도우즈 95/Me/XP나 2000이 깔린 컴퓨터에서 바꾸지 않고 실행될 것
다중작업(Multitasking) • 윈도우즈 운영체제에서 중요한 것은 다중작업을 할 수 있다는 것 • 동시에 여러 개의 프로그램을 실행시킬 수 있다 • 도스는 단일작업(single-tasking) 운영체제 • 윈도우즈 3.0은 간단하게 도스 위에 GUI를 올린 정도였으므로, 한번에 하나의 프로그램만 실행 • 게임과 워드 프로세서, 페인트 프로그램들을 동시에 실행시킬 수 있다 • 이러한 프로그램들은 프로그램, 프로세스(process), 혹은 태스크(task)라고 불린다
다중스레딩(multithreading) • 하나의 응용 프로그램 안에 많은 작은 프로세스들이 있는 것으로 생각할 수 있다. • 프로그램들 내부에서 보다 작은 실행 스레드가 실행 • 워드 프로세서 • 입력을 다루기 위한 스레드 • 디스크에 저장 스레드 • 철자 검사 스레드
컴퓨터 자원을 절약 ? • 프로세서가 하나인 컴퓨터를 일반적으로 더 빠르게 만들어주지는 않는다. • 첫 번째 프로세스가 대기하고 있는 상황에서 만약 다른 프로세스가 있다면, 평소라면 놀고 있을 프로세스 사이클을 사용하도록 할 수 있다. • 둘 혹은 그 이상의 프로세서를 가진 컴퓨터라면, 다중작업 OS가 각각의 프로세서에 작업을 수행하게 되므로, 더 빠른 결과를 얻을 수 있다. • 어떤 프로세서는 한 개 이상의 명령어를 실행시킬 수도 있다. • 펜티엄 프로세서는 동시에 두 개의 명령어를 실행 (U 파이프에서, 다른 하나는 V 파이프에서) • 파워PC나 펜티엄 II의 경우는 최대 5개까지 실행
Why multitasking, multithreading? • 다중스레딩을 통해서 직접 관리하지 않고도 여러 개의 하위-프로세스(스레드)들을 가지는 응용 프로그램을 만들 수 있다. • 오토마타(자립적인 객체)를 가능하게 한다.
윈도우즈 MFC 대 SDK • MFC는 Microsoft Foundation Class의 약자이고, SDK는 Software Development Kit의 약자 • SDK • 초기 프로그래머들은 윈도우즈 프로그램을 만들기 위해 SDK만을 사용 • SDK는 윈도우즈 프로그래밍을 위한 많은 라이브러리와 헤더, 그리고 API(Application Programming Interface)로 구성 • MFC • SDK에 기반해서 만들어진 C++ 클래스들의 집합으로 윈도우즈 응용 프로그램을 좀더 쉽게 만들게 하기 위한 것 • 복잡…^^ • 본 course에서는 SDK만 사용 • 단순하고, 간단한 프로그래밍
이벤트-기반 프로그래밍 모델 • 윈도우즈는 이벤트-기반 운영체제이다.
이벤트-기반 프로그래밍 모델 • 메인 루프가 반복되면서 메시지가 들어오는 대로 그때그때 비정기적으로 처리 • 메시지(message) • 응용 프로그램에게 어떤 특정한 종류의 이벤트가 일어났음을 알리는 신호 • 윈도우즈나 다른 응용프로그램, 또는 사용자로부터 발생
이벤트의 예 • 윈도우 이벤트 • 사용자가 윈도우의 크기를 변경 • 윈도우즈는 응용 프로그램에게 윈도우의 변경된 크기를 알리는 메시지를 전송한다. • 키보드 이벤트 • 사용자가 키보드를 누르면 • 키가 눌러졌다는 메시지가 응용 프로그램에 전송된다. 응용 프로그램은 그 정보를 처리해서 (메뉴가 뜬다든가 하는) 적절한 행동을 수행한다. • 그리기(Drawing) 이벤트 • 다른 윈도우가 응용 프로그램의 윈도우를 가렸다가 치워지면서 아래에 깔린 윈도우를 다시 그려야 된다면 • 다시 칠하라는 메시지가 응용 프로그램에 전송된다.
메시지 • 윈도우즈안의 모든 것은 메시지이다. • 중요한 메시지들이 발생할 때마다 제대로 처리해주어야 한다. • 프로그램이 어떤 윈도우즈 메시지를 처리하지 않을 때에는, 무엇을 해도 상관없다. • 그렇기 때문에 비디오 게임 로직을 내부적으로 따로 처리하고 윈도우즈 응용 프로그램으로 렌더링할 수 있는 것이다. • 물론 제대로 돌아가는 윈도우즈 응용 프로그램에는 매우 많은 세부적인 것들이 필요하지만, 프로그램은 기본적으로 메시지를 처리하는 것이다.
타이핑을 좋아하는 이들을 위한 헝가리식 표기법 • 마이크로소프트에 다니던 어떤 헝가리 사람 - 찰스 시모니(Charles Simonyi) • 마이크로소프트의 모든 프로그래머들을 위한 표기법을 담당
변수 명명 • 핸들(handle) • 다른 객체를 가리키는 32비트 정수를 말한다 • 핸들의 자료형이 32비트가 아닌 다른 것으로 바뀔 경우를 대비한다 • 전치사가 나오고 다음에 변수 이름 • 변수 이름에 포함된 단어의 앞 글자는 대문자 • 예 • szName: NULL로 끝나는 문자열 • dwHitList: WORD (H와 L이 대문자임을 알 수 있음) • lpData: 무언가를 가리키는 32비트 포인터 • lpwData: 하나의 WORD를 가리키는 32비트 포인터 • g 와 밑줄(_)을 앞에 넣어서 변수가 전역변수임을 나타내기도 한다. 예를 들어 g_lTime 은 LONG 형인 전역 변수이다.
함수 명명 • 함수는 단어들 사이에 밑줄 없이 단어 첫 자를 대문자로 • 예 WORD IsFull(void); int LoadBitmap(void); BOOL IsRunning(void);
타입정의와 상수 • 새로 정의되는 자료형이나 상수는 모두 대문자 • 밑줄을 사용하며, 그렇게 엄밀하진 않다. • 예 typedef unsigned char UCHAR; typedef int BOOL; #define MAX_BRAINS 100
클래스 • 함수 이름과 비슷하다 • 단어의 첫 글자는 대문자를 쓴다 • 모든 클래스에는 앞에 C가 전치사로 붙는다 • 예 class CPoint { public: CPoint(void); ~CPoint(); private: int x,y; };
표준 콘솔 C 코드 // PROG3_1.CPP - what’s up standard version #include <stdio.h> // main entry point for all standard DOS/console programs void main(void) { printf(“\nWhat’s up, world!”); } // end main 실행: What’s up, world! C:\
What’s up, world! - 윈도우즈 스타일 // PROG3_2.CPP - A simple message box #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <windowsx.h> // main entry point for all windows programs int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { // call message box API MessageBox(NULL, “What’s up, world!”, “My First Windows Program”,MB_OK); // exit program return(0); } // end WinMain
MessageBox() 함수 int MessageBox( HWND hWnd, // handle of parent window LPCTSTR lpText, // pointer to message string LPCTSTR lpCaption, // pointer to title string UINT uType); // style of message box
실제 윈도우즈 응용 프로그램의 부분들 • Win32 라이브러리 지정 • include 파일 사용 • WinMain() 함수로 진입점(entry point) 지정 • 윈도우즈 클래스 지정 • 윈도우즈 클래스 등록 • 윈도우 생성 • 윈도우 보이기 • 필요에 따라 이벤트 루프 마련하기 • 이벤트 처리기(event handler) 마련하기
Win32 라이브러리 • 윈도우즈 프로그래밍 API • 정적(static) 라이브러리 • 프로그램이 필요할 때 동적으로 로드 되는 DLL(Dynamic Link Library) • 라이브러리가 Win32 응용프로그램을 위한 기본 라이브러리에 들어있지 있지 않을 때에만, 응용 프로그램에 따로 라이브러리를 추가해주면 된다. • 예 • 멀티미디어 확장기능 : WINMM.LIB (where?) • DirectX 응용 프로그램을 만들 때: DirectX 라이브러리를 응용 프로그램에 추가
include 파일 • WINDOWS.H • 수많은 다른 include file을 포함 … 직접 확인할것!! • WINDOWSX.H • 유용한 macro들 포함 #define WIN32_LEAN_AND_MEAN // MFC 기능 사용 안함 #include <windows.h> #include <windowsx.h>
WinMain() 함수 - 1 • 윈도우즈 응용 프로그램의 진입점 • main() 과 유사 int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow); • 함수의 형이 WINAPI로 선언: 함수가 PASCAL 호출 규약을 사용하며, 32비트라는 것을 의미 • hinstance : 응용 프로그램 인스턴스의 핸들 • hprevinstance는 거의 쓸모가 없는데 이전 인스턴스의 핸들에 사용 • lpcmdline이란 인자는 명령행 인자를 가리키는 포인터
WinMain() 함수 - 2 • lpcmdline 과 argv 의 차이 • Command Line: APP1.EXE FILE1.BMP FILE2.BMP • argv • arvg[0] = “APP1.EXE” • argv[1] = “FILE1.BMP” • argv[2] = “FILE2.BMP” • lpcmdline = “FILE1.BMP FILE2.BMP” : 하나의 스트링
WinMain() 함수 - 3 • WinMain() 함수의 마지막 인자는 ncmdshow • 윈도우즈 응용 프로그램이 초기에 보여지는 방식을 결정 • SW_SHOWNORMAL인 경우가 많다.
윈도우즈 클래스 • C++의 개념은 이미 윈도우즈의 디자인에 깊이 뿌리 박혀 있다. • 윈도우즈에 있는 모든 객체는 하나의 윈도우(window)이다. (버튼이나, 스크롤바, 텍스트 상자) • 윈도우즈의 각각의 객체들은 기본 윈도우 클래스로부터 상속 받은 윈도우 형태중 하나에 속한다. • 자신만의 윈도우를 만들기 위해서는, 하나의 윈도우의 클래스를 만들어야 한다.
윈도우즈 클래스 • 윈도우의 클래스란 특정한 윈도우의 속성들을 지정하는 것 • 하나의 윈도우즈 클래스를 정의하면, 그 클래스에 속한 윈도우를 원하는 개수만큼 생성할 수 있다. typedef struct _WNDCLASS { UINT style; // style flags WNDPROC lpfnWndProc; // pointer to event handler int cbClsExtra; // extra bytes int cbWndExtra; // extra bytes HANDLE hInstance; // handle of instance HICON hIcon; // handle to icon HCURSOR hCursor; // handle to cursor HBRUSH hbrBackground; // handle to background brush LPCTSTR lpszMenuName; // name of menu LPCTSTR lpszClassName; // name of class } WNDCLASS; WNDCLASS wndclass; // a declaration of a window class
Style • 윈도우가 어떻게 보이는지, 크기는 변경가능한지, 다시 그리는 일은 누가 하는지, 그것이 처리할 수 있는 메시지는 어떤 종류인지 등의 조건을 제어 • 가장 일반적인 경우: wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; • 윈도우 크기 변경시 메시지 • 더블클릭시 메시지 • 자신의 장치 콘텍스트(Device Context)를 가짐으로써 윈도우를 그리는 속도를 향상
lpfnWndProc 속성 • 이벤트 처리기 함수를 가리키는 함수 포인터 wndclass.lpfnWndProc = WindowProc; LRESULT CALLBACK WindowProc(HWND hWnd, // the window UINT msg, // the message itself WPARAM wParam, // more info on message LPARAM lParam);// more info on message
cbClsExtra와 cbWndExtra • 사용하는 사람은 별로 없는 것 같다 • 윈도우즈 클래스나 윈도우즈의 데이터를 위한 여분의 공간을 저장하는 역할 • 둘 다 0으로 wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0;
hInstance • 응용 프로그램의 인스턴스를 저장 • 그냥 WinMain()의 hinstance 인자로 지정 wndclass.hInstance = hinstance; // from winmain
hIcon, hCursor • hIcon • 응용 프로그램이 최소화되거나 바로가기로 표시될 때 보이게 되는 아이콘의 핸들 • hCursor • 응용 프로그램의 포인터가 되는 커서의 핸들 • 미리 만들어놓은 것들에서 리소스로 로드되거나, 또는 내장된 기본값을 사용 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
hbrBackground • 배경 브러시에 대한 핸들 • 윈도우즈는 그리는 것을 위해 브러시와 펜이라는 도구를 사용 wndclass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
lpszMenuName • 윈도우즈에 추가되는 메뉴 리소스의 이름 • 지금은 메뉴 속성을 NULL로 … (4장에서) wndclass.lpszMenuName= NULL;
lpszClassName • 새로 만들어진 윈도우즈 클래스를 부르는 이름 • 보통 "WINCLASS1"과 같은 이름을 사용 wndclass.lpszClassName = “WINCLASS1”;
윈도우즈 클래스 등록하기 • 윈도우 클래스를 생성한 다음에는 이를 등록 • 윈도우즈가 그 윈도우 클래스에 대해서 알게 되고, 클래스의 ASCII 이름을 통해서 윈도우를 생성할 수 있다. ATOM RegisterClass(CONST WNDCLASS *lpWndClass); 또는 if (RegisterClass(&wndclass)==0) { // error } // end if
윈도우 생성 • CreateWindow() 함수 HWND CreateWindow( LPCTSTR lpClassName, // pointer to class name (string) LPCTSTR lpWindowName, // pointer to window title (string) DWORD dwStyle, // windows style flags int x, // horizontal position of window int y, // vertical position of window int nWidth, // width of window int nHeight, // height of window HWND hWndParent, // handle to parent (usually NULL) HMENU hMenu, // handle to menu (usually NULL) HANDLE hInstance, // handle to application instance LPVOID lpParam // pointer to startup creation data ); // don’t worry about it (NULL)
CreateWindow • lpClassName은 CreateWindow()를 호출하기 전에 등록한 윈도우즈 클래스의 이름이다. • lpWindowName은 윈도우의 타이틀바(title bar)에 나오는 "My Window"같은 문자열이다. • x와 y는 윈도우가 열리는 화면의 위치이다. • nWindth와 hHeight는 윈도우의 크기가 몇 픽셀인지를 나타낸다. • hWndParent는 부모 윈도우의 핸들이다. 이 경우에는 항상 NULL로 한다. • hMenu는 윈도우 메뉴의 핸들이다. 메뉴를 추가하는 것은 윈도우즈 클래스 등록시에 이루어지기 때문에 이 값 또한 NULL로 하면 된다. • lParam은 조금 심화된 내용이다. 일단은 NULL이라고 하라.
CreateWindow 사용의 예 // define global to save window handle in HWND main_window_handle = NULL; main_window_handle = CreateWindow(“WNDCLASS1”, // preregistered class “My First Window”, // title of window WS_OVERLAPPEDWINDOW | WS_VISIBLE, // flags 100,100, // position 320,200, // size NULL, // handle to parent NULL, // handle to menu hinstance, // instance from WinMain NULL);
크기와 위치를 지정하지 않은 예 main_window_handle = CreateWindow(“WNDCLASS1”, // preregistered class “My First Window”, // title of window WS_OVERLAPPEDWINDOW | WS_VISIBLE, // flags CW_USEDEFAULT,CW_USEDEFAULT, // position CW_USEDEFAULT,CW_USEDEFAULT, // size NULL, // handle to parent NULL, // handle to menu hinstance, // instance from WinMain NULL);
윈도우 출력 • WS_VISIBLE 플래그를 사용했기 때문에 윈도우는 생성하고 나서 바로 보일 것이기 때문이다. • 이 플래그를 넣지 않는 경우나 조금 다른 방식으로 윈도우를 열고 싶다면, ShowWindow()을 사용 • ShowWindow()는 윈도우를 감추는 기능도 있다. BOOL ShowWindow(HWND hWnd, // handle of window int nCmdShow); // show state of window nCmdShow: 다음의 표
UpdateWindow • 윈도우를 갱신하거나 다시 그리게 할 수 있다. BOOL UpdateWindow(HWND hWnd); • Example of ShowWindow() and UpdateWindow() // register window class... // create window... // now show and update window ShowWindow(main_window_handle, SW_SHOW); UpdateWindow(main_window_handle);
WinMain() and the event loop • 메인 이벤트 루프는 메시지 큐(message queue)로부터 메시지들을 얻어서, 거르거나(filter) 번역한(translate) 뒤에, 이벤트 처리기로 전달한다. • 메인 이벤트 루프가 메시지를 처리하지 않을 때에는, 게임 로직과 같은 다른 일들을 처리한다.