Windows Programming -...
Transcript of Windows Programming -...
Windows Programming
2013. 3
출처: 인터넷에서 수집한 PT 자료
1. Overview
3
Getting Started (1)
관련 도서 Visual C++/API 프로젝트 따라하기, 오진환, 컴스페이스
“Programming Windows”, Charles Petzold, Microsoft Press
“Windows application Programming Interface”, 김상형
Microsoft Visual C++ Bible 6.0”, 이이표, 김병세, 삼양출판사
“VC++ 와 윈도우 프로그래밍”, 김주호
“Visual C++ Programming Bible”, 이상엽, 영진 출판사
Getting Started (2)
프로그래밍 환경 Microsoft Visual C++ 6.0/2008/2010
MSDN
Platform SDK(Software development kit) or MFC
OS가 제공하는 서비스
User : shell service
ex. 도스의 command.com 혹은 유닉스나 리눅스의 shell
Programmer : API(Application Programming Interface)
응용 프로그램을 만들기 위해서 제공되는 함수의 집합
Win16(윈도우즈3.x) vs. Win32 API(윈도우즈95~)
4
5
Getting Started (3)
윈도우의 구성
DLL
Windows의 대부분
Kernel : KERNEL32.dll
OS의 핵심 부분으로 메모리 관리, 파일 입출력, 프로그램의 로드와
실행 등 OS의 기본 기능 수행
User : USER32.dll
윈도우, 다이얼로그, 메뉴 등 사용자 인터페이스 관리
GDI : GDI32.dll
화면, 프린터 등에 대한 출력을 담당하며, 펜, 브러시, 폰트 등의
GDI 오브젝트를 관리
6
Getting Started (4)
Windows Programming Tools
SDK(Software Development Kit)
API 함수를 이용
단점 : 프로그램의 골격 및 GUI를 위한 코드를 프로그래머가
모두 작성해야 함
단순 작업이 반복되고 프로그램이 커질수록 관리가 어려움
7
Getting Started (5)
RAD (Rapid Application Development)
Visual Basic, PowerBuilder, Delphi
단점 : 저수준의 제어가 어려움
MFC(Microsoft Foundation Class Library)
함수가 아니라 유용한 클래스의 집합
기본적인 프로그램 골격 및 GUI 클래스 제공
WIN32 API를 직접 이용하여 저수준의 제어 가능
2. 프로그램의 구조와 메시지
9
Dos vs. Windows
Dos
절차적 혹은 순차적 프로그램
프로그래머가 프로그램 진행을 전적으로 제어
원하는 서비스가 있으면 프로그램이 도스 시스템을 호출
int main(int argc, char * argv[])
{
…………………….
while (1) {
char ch = bioskey();
keycheck(ch);
}
…………………….
}
void keycheck(char ch)
{
………………………….
switch (ch)
{
case ‘X’:
………………………….
}
………………………….
}
10
Dos vs. Windows
Windows
Event-driven or message-driven
윈도우 시스템과 프로그래머가 프로그램의 진행을 분담해서
처리
윈도우 시스템은 이벤트를 감지하여 프로그램에 전달
프로그래머는 관심 있는 메시지만 처리하면 됨
example
사용자 입력 장치 드라이버 메시지 큐 응용 프로그램
윈도우 시스템 장치 드라이버 출력
11
Dos vs. Windows
출력장치
입력장치
device
driver
device
driver
device
driver
message
queue
프로그램
프로그램
프로그램
12
구성방식
꼭 알아야 할 요소들
Event & Message
Message queue
Message loop
Window Proc
Handle
Instance
Resource
Hardware 접근방식
비트 연산자
13
필수적인 이해요소 (1)
Event & Message
Event : 주로 사용자의 기계적인 조작에 의해 발행되는 것
윈도우 OS가 감지, 해당 프로그램으로 메시지를 전달
이때 전달되는 메시지는 표준화 되어있는 상수 값 (winuser.h)
Message Queue
Message가 저장 되는 곳
FIFO
System message Queue & Program message Queue
RIT(Raw Input Thread)
해당 프로그램의 Message Queue로 전달
14
메시지큐
입력장치
device
driver
device
driver
device
driver
프로그램
그림판
윈도우즈OS
메모장
시스템
메시지큐
시스템
분배기
(RIT)
프로그램
메시지큐
(메모장)
프로그램
메시지큐
(그림판)
15
필수적인 이해요소 (2)
Message Loop
Message queue에 어떤 message가 들어왔는지를
지속적으로 감시하고 분석해 주는 부분
Window Procedure
Callback : 운영체제에서 호출하는 함수
Message loop에서 해석한 message를 구체적으로 처리하는
기능을 수행
구조 : 간단한 switch.. , case.. 문의 집합
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_LBUTTONDOWN:
case WM_DESTROY:
……………………………………………
}
}
16
필수적인 이해요소 (3)
Handle
Dos
데이터를 참조하거나 조작하기 위해 pointer 를 이용
ex) fopen()
Windows
데이터를 참조하거나 조작하기 위해 handle 사용
프로그램에서 현재 사용중인 객체들을 식별하기 위해 윈도우
OS가 부여하는 고유 번호
윈도우를 만들거나, 파일을 열면 OS 가 부여
해당 윈도우나 파일을 다시 참조시 핸들을 사용
32 bit 정수형, 중복되지 말아야 된다.
핸들형 변수를 만들어 핸들을 대입 받아 사용
17
Handle을 사용하는 이유
device
driver
device
driver
device
driver
프로그램
핸들테이블
윈도우핸들
기존의 참조 대상
이동된 참조 대상
메모리주소
18
Handle 종류
Data Type 의미
HWND 윈도우에 대한 핸들
HCURSOR 커서에 대한 핸들
HICON 아이콘에 대한 핸들
HINSTANCE 프로그램 자신의 ‘인스턴스’에 대한 핸들
HDC 장치 컨택스트에 대한 핸들
HMENU 메뉴에 대한 핸들
19
필수적인 이해요소 (4)
Instance
프로그램
Code segment & Data segment
모든 프로그램은 같은 코드를 실행
프로그램에 따라 데이터는 달라짐
Instance
실제 메모리 상에 할당된 객체
Module instance & Data Instance
모듈 인스턴스
데이터 인스턴스1
데이터 인스턴스2
20
필수적인 이해요소 (5)
Resource
사용자 인터페이스를 구성하는 자원들의 정적 data
메뉴, 커서, 아이콘
Resource Scrip에 의해 정의
자체 compile 과정 (.res)
메모리를 효율적으로 사용하기 위해 사용
필요한 시점에 파일로부터 로딩
DISCARDABLE 설정 가능
21
필수적인 이해요소 (6)
하드웨어 운용 방식
Dos
비디오나 프린터에 출력하기 위해서는 Port, Bios, DMA 등을
통해 직접 제어
하드웨어 장치에 종속된 프로그램
장치의 종류와 모델에 따른 프로그래밍 필요
Windows
디바이스 드라이버를 윈도우가 내장
하드웨어에 독립적인 프로그램
DC를 이용하여 GDI(Graphic Device Interface)를 호출
장치의 종류나 모델에 상관없이 1번만 프로그램을 작성하면 됨
22
필수적인 이해요소 (7)
비트 OR 연산자
함수에 인수 전달시, 여러 개의 옵션을 묶어 전달
옵션들의 실제값은 2의 제곱승으로 정의
옵션별로 비트 자리가 정해져 있다.
사용자는 매크로 값만 알고 있으면 된다.
ex)
윈도우 스타일, 문자열 출력 방식….
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED |
WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX
23
Window Program의 파일구성
Code file : C header와 source file
Resource file
.res file
실행 중에 내용이 변하지 않는 데이터 저장
bitmap, icon, cursor, string, dialog box, menu,..
.def file
code와 data의 메모리 속성
stack과 heap의 크기 지정
Makefile
.dsw file, cf) Visual C++ 4.X는 확장자 .mdp
24
표기법
접두어(Prefix) Data Type
a 배열 (array)
b bool
ch 문자
cb 바이트 개수
dw 부호없는 long 형 정수
h 핸들
sz Null로 끝나는 문자열
I integer
p 포인터
접두어(Prefix) 의미
BM_ 버튼 메시지
CB_ 콤보 박스 메시지
DM_ 다이얼로그 메시지
EM_ 에디트 컨트롤 메시지
LB_ 리스트 박스 메시지
WM_ 윈도우 메시지
접두어(Prefix) 의미
BS_ 버튼 스타일
CBS_ 콤보 박스 스타일
DS_ 다이얼로그 스타일
ES_ 에디트 컨트롤 스타일
LBS_ 리스트 박스 스타일
WS_ 윈도우 스타일
Ex) Char szAddress[10];
25
Type
Type BOOL : int로 부터 재정의
LPSTR : char*
HWND : 윈도우 식별자
HINSTANCE : 인스턴스 식별자,
UINT : 4 bytes
HANDLE : UINT를 재정의
WPARAM : 메시지의 부가정보, UINT를 재정의
LPARAM : 메시지의 부가정보, LONG을 재정의
26
DefWindowProc
WinMain
Message Handler Message Handler
Message Handler Message Handler
WinProc 제일 먼저 전달된 메시지
처리되지 않은 메시지
가져온 메시지
MsgQueue
WM_PAINT
WM_KEYDOWN
WM_SIZE
Window Program의 구조 (1)
27
Window Program의 구조 (2)
Int winapi WinMain(…)
{
InitApplication(); // 클래스 등록
InitInstance(); // 창 생성
while (GetMessage(&msg,NULL,0,0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//메시지를 전송 받으면 실행, 실행이 끝나면
메시지를 전송한 곳으로 되돌아 간다.
LRESULT WndProc(…)
{
<전송받은 메시지에 따른 처리를 수행>
}
28
#include “windows.h” // SDK의 API의 각종 상수, 구조체가 정의된 헤더 파일
#include “generic.h” // 이 프로그램에서 사용한 상수가 정의되고 함수 선언
HINSTANCE hInst; // 인스턴스 핸들을 기억
HWND hMainWnd; // 메인 윈도우 핸들을 기억
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
if(!hPrevInstance)
if(!InitApplication(hInstance)) // 윈도우 클래스를 등록
return FALSE;
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장 if(!InitInstance(hInstance, nCmdShow))
return FALSE;
// 메시지 루프에 진입한다.
While(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
29
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc; // WNDCLASS는 윈도우 클래스의 등록에 필요한 구조체
wc.lpfnWndProc = MainWndProc; // 윈도우 프로시져
wc.cbClsExtra = 0; // 클래스 여분 바이트
wc.cbWndExtra = 0; // 윈도우 여분 바이트
wc.hInstance = hInstance; // 인스턴스 핸들
wc.hIcon = LoadIcon(NULL, IDI_APPLIATION); // 아이콘 지정
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 커서 지정
wc.hbrBackground = GetStockObject(WHITE_BRUSH); // 배경색 지정
wc.lpszMenuName = “EX1_1Menu”; // 메뉴 지정
wc.lpszClassName = “EX1_1WClass”; // 클래스 이름 지정
return RegisterClass(&wc); // 윈도우 클래스를 등록한다.
}
30
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hMainWnd = hWnd = CreateWindow(
“EX1_1WClass”, // 생성하려는 윈도우 클래스 이름
“EX 1-1”, // 윈도우 타이틀 지정
WS_OVERLAPPEDWINDOW, // 윈도우 스타일
CW_USEDEFAULT, // 시작 X좌표
CW_USEDEFAULT, // 시작 Y좌표
CW_USEDEFAULT, // 윈도우의 폭
CW_USEDEFAULT, // 윈도우의 높이
NULL, // 부모 윈도우 핸들
NULL, // 메뉴 핸들
hInstance, // 응용 프로그램 인스턴스 핸들
NULL // 윈도우 작성일
);
if(!hWnd) // 윈도우가 실패했으면,
return FALSE;
ShowWindow(hWnd, nCmdShow); // 메인 윈도우 형태 결정, WM_PAINT 발생
UpdateWindow(hWnd); // WM_PAINT 메시지를 바로 처리
return TRUE;
}
31
long APIENTRY MainWndProc
(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
case WM_COMMAND: { // 사용자가 메뉴 항목을 선택할 때 발생하는 메시지
switch(LOWORD(wParam)) { // wParam의 하위 워드에 메뉴 ID
case ID_FILE_EXIT:
SendMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
break;
}
case WM_PAINT: { // 사용자 영역이 다시 그려져야 할 때 발생하는 메시지
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd, &ps);
TextOut(hDC, 10, 10, “Hello, Everybody”, 16);
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY: // 윈도우가 없어지기 직전에 발생
PostQuitMessage(0);
break;
default: return DefWindowProc(hWnd, message, wParam, lParam);
}
32
WinMain 분석
WinMain 함수 인자
(1) WNDCLASS 등록 앞으로 사용할 윈도우의 특성을 OS에 알림
(2) Main Window의 생성 앞서 등록한 윈도우를 메인 윈도우로 생성
(3) Message Loop의 진입 윈도우에서 발생한 메시지를 처리하기 위해서 루프에 들어감
함수 인자 의미
hInstance 현재 실행중인 어플리케이션의 인스턴스 핸들
hPrevInstance 동일한 어플리케이션이 실행중일 경우 이전에 실행된 프로그램의 인스턴스 핸들을
나타냄(win32 의 경우 항상 NULL)
lpCmdLine 커맨드 라인의 문자열을 가르키는 포인터
nCmdShow 메인 윈도우를 어떻게 출력할 것인지를 결정하는 인자로 ShowWindow()함수
호출시 사용된다.
33
(1) WNDCLASS 등록
WNDCLASS 구조체 : 윈도우 클래스를 OS에 등록 lpfnWndProc - 메시지를 처리할 Window Procedure의 이름
hInstance - 이 윈도우가 속한 instance handle
hIcon - 아이콘을 지정, LoadIcon
hCursor - 커서를 지정, LoadCursor
hbrBackground - 배경색 지정
lpszMenuName - 메뉴 지정
lpszClassName - 윈도우 이름
RegisterClass API를 이용해서 OS에 등록
클래스 스타일 의미
CS_HREDRAW 사용자 영역의 폭이 변경되면 전체를 다시 그린다.
CS_VREDRAW 사용자 영역의 높이가 변경되면 전체를 다시 그린다.
CS_NOCLOSE 시스템 메뉴의 Close 항목을 사용할 수 없게 한다.
CS_DBCLICKS 윈도우 프로시저에 더블클릭 메시지를 보낸다.
34
(2) Main Window의 생성& 출력
Window Style WS_OVERLAPPED
WS_SYSMENU
WS_CAPTION
WS_MINIMIZEBOX
WS_MAXMIZEBOX
WS_CHILD
WS_VISIBLE
WS_BORDER
WS_HSCROLL
WS_VSCROLL
WS_POPUP
WS_CLIPSIBLINGS
WS_CLIPCHILDREN
……….
Popup & Child
35
WS_OVERLAPPEDWINDOW & Client Area
WS_OVERLAPPEDWINDOW #define WS_OVERLAPPEDWINDOW
(WS_OVERLAPPED |\
WS_CAPTION |\
WS_SYSMENU |\
WS_THICKFRAME |\
WS_MINIMIZE |\
WS_MAXMIZE)
Client Area window border, title bar, menu bar, scroll bar를 제외한 영역
36
Window border
Client Area
사용자 영역의 원점
Title bar Menu bar
<사용자 영역>
37
ShowWindow & UpdateWindow
BOOL ShowWindow(HWND hWnd, // handle of window
int nCmdShow // show state of window);
WM_PAINT 메시지 발생
SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE,
SW_SHOW
BOOL UpdateWindow( HWND hWnd );
ShowWindow에서 발생한 WM_PAINT 메시지를 처리
SW_HIDE
SW_MAXIMIZE
SW_MINIMIZE
SW_RESTORE
SW_SHOW
윈도우를 감춘다.
윈도우를 전체 화면 크기로 만든다.
윈도우를 아이콘화 한다.
이전 상태로 되돌린다.
윈도우를 활성화시킨다.
38
(3) Message Loop의 진입
GetMessage Message queue로부터 메시지를 읽어 온다.
WM_QUIT메시지를 받으면 0(False)을 리턴한다.
Message loop를 빠져 나오면서, 프로그램을 종료한다.
TranslateMessage Message 중 키보드와 관련된 message에 대해서 특정 작업 수행
문자가 입력되었다는 Message (WM_CHAR)를 생성
DispatchMessage Message를 윈도우 프로시저(WndProc)에 전달하는 역할을 한다.
OS에게 윈도우 프로시져의 호출을 요청
WM_QUIT Message가 오기 전까지 Loop
39
MSG 구조체
Typedef struct tagMSG
{
HWND hwnd;
UINT messgae;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}
멤버 의미
Hwnd 메시지를 받을 윈도우 핸들
Message 어떤 종류의 메시지 인가?
wParam 전달된 메시지의 부가 정보
lParam 전달된 메시지의 부가 정보
time 메시지가 발생한 시간
Pt 메시지가 발생했을 때의 마우스의 위치
마우스 왼쪽 버튼을 누른 경우
1st parameter: hwnd
2nd parameter: WM_LBUTTONDOWN
3rd parameter: Ctrl key나 shift key가 눌렸는지 여부
4th parameter: LOWOD(lPARAM)은 커서의 x좌표
HIWORD(lPARAM)은 커서의 y좌표
40
Window Procedure
LRESULT CALLBACK WndProc
(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam)
해당 윈도우에서 발생한 메시지를 최종적으로 처리
각 메시지마다 추가 정보가 wParam, lParam에 온다.
- help참조
ex) WM_KEYDOWN 메시지
nVirtKey = (int) wParam; // virtual-key code
lKeyData = lParam; // key data
message handler가 없는 메시지는 DefWindowProc함수가
처리한다.
WM_CLOSE, WM_ACTIVATE, WM_SYSCOMMAND 등
수십개의 메시지를 디폴트로 처리해준다.
41
중요한 메시지 (1)
WM_PAINT
윈도우의 모양에 변화가 생길 때 발생
가려졌다가 복구
크기가 변경될 때
BeginPaint()를 호출함으로써 시작
EndPaint()를 호출하여 끝냄
(2)
(1) (1)
(2)
(2)에 WM_PAINT
메시지 발생
42
중요한 메시지 (2)
WM_SIZE
윈도우의 크기가 변경될 때
wParam : 메시지가 발생한 이유
lParam :
상위 워드 : 변경된 후의 윈도우 높이
하위 워드 : 변경된 후의 윈도우 폭
플래그 값
SIZE_MAXHIDE 다른 윈도우가 최대화 되어 이 윈도우가 가려졌다
SIZE_MAXMIZED 최대화되었다.
SIZE_MAXSHOW 다른 윈도우가 원래 크기로 복구되어 이 윈도우가 드러났다.
SIZE_MINIMIZED 최소화 되었다.
SIZE_RESTORED 크기가 변경되었다.
43
중요한 메시지 (3)
WM_MOVE
윈도우의 위치가 변경될 때
wParam : 위치 변경 플래그 (SIZE_RESTORED)
lParam
상위워드 : 윈도우의 x 좌표
하위워드 : 원도우의 y 좌표
44
중요한 메시지 (4)
WM_DESTROY
사용자의 명령에 의해 Windows가 원도우를 종료하고 있음을
알려준다.
자원을 OS에 반환
PostQuitMessage()를 호출
프로그램의 메시지 큐에 WM_QUIT를 삽입
GetMessage는 0을 반환
WinMain이 메시지 루프를 벗어나게 함
윈도우가 생성될 때 : WM_CREATE -> WM_SIZE -> WM_PAINT
윈도우가 종료될 때 : WM_CLOSE -> WM_DESTROY -> WM_QUIT