WindowsPrograming

advertisement
Windows Programming
차례














1. Overview
2. 프로그램의 구조와 메시지
3. Drawing
4. Input Message
5. Control
6. Resource
7. Printing
8. MDI
9. DLL
10. Memory, File I/O, Clipboard
11. Process & Thread
12. IPC
13. Synchronization
14. Network Programming
2
1. Overview
Getting Started (1)

주 교재



부 교재




“Programming Windows”, Charles Petzold, Microsoft Press
“Windows application Programming Interface”, 김상형
“Microsoft Visual C++ Bible 6.0”, 이이표, 김병세,
삼양출판사
“VC++ 와 윈도우 프로그래밍”, 김주호
“Visual C++ Programming Bible”, 이상엽, 영진 출판사
프로그래밍 환경



Microsoft Visual C++ 6.0
MSDN
Platform SDK(Software development kit) or MFC
4
Getting Started (2)

윈도우의 구성

DLL
 Windows 98 : \Windows\System
 Windows NT : \Winnt\System ,\Winnt\System32

Windows의 대부분
 Kernel : KERNEL32.dll
 OS의 핵심 부분으로 메모리 관리, 파일 입출력, 프로그램의 로드와
실행 등 OS의 기본 기능 수행
 User : USER32.dll
 윈도우, 다이얼로그, 메뉴 등 사용자 인터페이스 관리
 GDI : GDI32.dll
 화면, 프린터 등에 대한 출력을 담당하며, 펜, 브러시, 폰트 등의
GDI 오브젝트를 관리
5
Getting Started (3)

OS가 제공하는 서비스

User : shell service
 ex. 도스의 command.com 혹은 유닉스나 리눅스의 shell

Programmer : API(Application Programming Interface)
 응용 프로그램을 만들기 위해서 제공되는 함수의 집합
 Win16(윈도우즈3.x) vs. Win32 API(윈도우즈95~)

Windows Programming Tools

SDK(Software Development Kit)
 API 함수를 이용
 단점 : 프로그램의 골격 및 GUI를 위한 코드를 프로그래머가
모두 작성해야 함
 단순 작업이 반복되고 프로그램이 커질수록 관리가 어려움
6
Getting Started (4)

RAD (Rapid Application Development)
 Visual Basic, PowerBuilder, Delphi
 단점 : 저수준의 제어가 어려움

MFC(Microsoft Foundation Class Library)
 함수가 아니라 유용한 클래스의 집합
 기본적인 프로그램 골격 및 GUI 클래스 제공
 WIN32 API를 직접 이용하여 저수준의 제어 가능
7
2. 프로그램의 구조와 메시지
Dos vs. Windows

Dos



절차적 혹은 순차적 프로그램
프로그래머가 프로그램 진행을 전적으로 제어
원하는 서비스가 있으면 프로그램이 도스 시스템을 호출
int main(int argc, char * argv[])
void keycheck(char ch)
{
{
…………………….
………………………….
while (1) {
switch (ch)
char ch = bioskey();
{
case ‘X’:
keycheck(ch);
………………………….
}
…………………….
}
}
………………………….
}
9
Dos vs. Windows

Windows


Event-driven or message-driven
윈도우 시스템과 프로그래머가 프로그램의 진행을 분담해서
처리
 윈도우 시스템은 이벤트를 감지하여 프로그램에 전달
 프로그래머는 관심 있는 메시지만 처리하면 됨

example
 사용자 입력  장치 드라이버  메시지 큐  응용 프로그램 
윈도우 시스템  장치 드라이버  출력
10
Dos vs. Windows
출력장치
device
프로그램
driver
device
message
driver
queue
프로그램
device
입력장치
driver
프로그램
11
구성방식

꼭 알아야 할 요소들









Event & Message
Message queue
Message loop
Window Proc
Handle
Instance
Resource
Hardware 접근방식
비트 연산자
12
필수적인 이해요소 (1)

Event & Message

Event : 주로 사용자의 기계적인 조작에 의해 발행되는 것
 윈도우 OS가 감지, 해당 프로그램으로 메시지를 전달
 이때 전달되는 메시지는 표준화 되어있는 상수 값 (winuser.h)

Message Queue




Message가 저장 되는 곳
FIFO
System message Queue & Program message Queue
RIT(Raw Input Thread)
 해당 프로그램의 Message Queue로 전달
13
메시지큐
윈도우즈OS
device
driver
프로그램
입력장치
시스템 device
메시지큐driver
프로그램
메시지큐
시스템
(메모장)
분배기
(RIT)
프로그램
메시지큐
device
메모장
그림판
(그림판)
driver
14
필수적인 이해요소 (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:
……………………………………………
}
}
15
필수적인 이해요소 (3)

Handle

Dos
 데이터를 참조하거나 조작하기 위해 pointer 를 이용
 ex) fopen()

Windows
 데이터를 참조하거나 조작하기 위해 handle 사용
 프로그램에서 현제 사용중인 객체들을 식별하기 위해 윈도우
OS가 부여하는 고유 번호
 윈도우를 만들거나, 파일을 열면 OS 가 부여
 해당 윈도우나 파일을 다시 참조시 핸들을 사용
 32 bit 정수형, 중복되지 말아야 된다.
 핸들형 변수를 만들어 핸들을 대입 받아 사용
16
Handle을 사용하는 이유
device
driver
프로그램
device
윈도우핸들
기존의 참조 대상
driver
이동된 참조 대상
device
driver
핸들테이블
메모리주소
17
Handle 종류
Data Type
의미
HWND
윈도우에 대한 핸들
HCURSOR
커서에 대한 핸들
HICON
아이콘에 대한 핸들
HINSTANCE
프로그램 자신의 ‘인스턴스’에 대한 핸들
HDC
장치 컨택스트에 대한 핸들
HMENU
메뉴에 대한 핸들
18
필수적인 이해요소 (4)

Instance

프로그램
 Code segment & Data segment
 모든 프로그램은 같은 코드를 실행
 프로그램에 따라 데이터는 달라짐

Instance
 실제 메모리 상에 할당된 객체
 Module instance & Data Instance
모듈 인스턴스
데이터 인스턴스1
데이터 인스턴스2
19
필수적인 이해요소 (5)

Resource

사용자 인터페이스를 구성하는 자원들의 정적 data
 메뉴, 커서, 아이콘



Resource Scrip에 의해 정의
자체 compile 과정 (.res)
메모리를 효율적으로 사용하기 위해 사용
 필요한 시점에 파일로부터 로딩
 DISCARDABLE 설정 가능
20
필수적인 이해요소 (6)

하드웨어 운용 방식

Dos
 비디오나 프린터에 출력하기 위해서는 Port, Bios, DMA 등을
통해 직접 제어
 하드웨어 장치에 종속된 프로그램
 장치의 종류와 모델에 따른 프로그래밍 필요

Windows




디바이스 드라이버를 윈도우가 내장
하드웨어에 독립적인 프로그램
DC를 이용하여 GDI(Graphic Device Interface)를 호출
장치의 종류나 모델에 상관없이 1번만 프로그램을 작성하면 됨
21
필수적인 이해요소 (7)

비트 OR 연산자





함수에 인수 전달시, 여러 개의 옵션을 묶어 전달
옵션들의 실제값은 2의 제곱승으로 정의
옵션별로 비트 자리가 정해져 있다.
사용자는 매크로 값만 알고 있으면 된다.
ex)
 윈도우 스타일, 문자열 출력 방식….
 WS_OVERLAPPEDWINDOW = WS_OVERLAPPED |
WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX
22
Window Program의 파일구성


Code file : C header와 source file
Resource file




.def file



.res file
실행 중에 내용이 변하지 않는 데이터 저장
bitmap, icon, cursor, string, dialog box, menu,..
code와 data의 메모리 속성
stack과 heap의 크기 지정
Makefile

.dsw file, cf) Visual C++ 4.X는 확장자 .mdp
23
표기법
Ex) Char szAddress[10];
접두어(Prefix)
의미
BM_
버튼 메시지
CB_
콤보 박스 메시지
접두어(Prefix)
Data Type
DM_
다이얼로그 메시지
a
배열 (array)
EM_
에디트 컨트롤 메시지
b
bool
LB_
리스트 박스 메시지
ch
문자
WM_
윈도우 메시지
cb
바이트 개수
접두어(Prefix)
의미
dw
부호없는 long 형 정수
BS_
버튼 스타일
h
핸들
CBS_
콤보 박스 스타일
sz
Null로 끝나는 문자열
DS_
다이얼로그 스타일
I
integer
ES_
에디트 컨트롤 스타일
p
포인터
LBS_
리스트 박스 스타일
WS_
윈도우 스타일
24
Type

Type








BOOL
LPSTR
HWND
HINSTANCE
UINT
HANDLE
WPARAM
LPARAM
: int로 부터 재정의
: char*
: 윈도우 식별자
: 인스턴스 식별자,
: 4 bytes
: UINT를 재정의
: 메시지의 부가정보, UINT를 재정의
: 메시지의 부가정보, LONG을 재정의
25
Window Program의 구조 (1)
WM_PAINT
WM_KEYDOWN
MsgQueue
가져온 메시지
WM_SIZE
WinMain
제일 먼저 전달된 메시지
WinProc
Message Handler
Message Handler
Message Handler
Message Handler
처리되지 않은 메시지
DefWindowProc
26
Window Program의 구조 (2)
Int winapi WinMain(…)
{
InitApplication(); // 클래스 등록
InitInstance(); // 창 생성
//메시지를 전송 받으면 실행, 실행이 끝나면
메시지를 전송한 곳으로 되돌아 간다.
LRESULT WndProc(…)
while (GetMessage(&msg,NULL,0,0)
{
<전송받은 메시지에 따른 처리를 수행>
{
TranslateMessage(&msg);
}
DispatchMessage(&msg);
}
}
27
#include “windows.h”
#include “generic.h”
// SDK의 API의 각종 상수, 구조체가 정의된 헤더 파일
// 이 프로그램에서 사용한 상수가 정의되고 함수 선언
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;
}
28
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); // 윈도우 클래스를 등록한다.
}
29
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;
}
30
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);
31
}
WinMain 분석

WinMain 함수 인자
함수 인자
hInstance
hPrevInstance

동일한 어플리케이션이 실행중일 경우 이전에 실행된 프로그램의 인스턴스 핸들을
나타냄(win32 의 경우 항상 NULL)
커맨드 라인의 문자열을 가르키는 포인터
nCmdShow
메인 윈도우를 어떻게 출력할 것인지를 결정하는 인자로 ShowWindow()함수
호출시 사용된다.
(1) WNDCLASS 등록
앞으로 사용할 윈도우의 특성을 OS에 알림
(2) Main Window의 생성


현재 실행중인 어플리케이션의 인스턴스 핸들
lpCmdLine


의미
앞서 등록한 윈도우를 메인 윈도우로 생성
(3) Message Loop의 진입

윈도우에서 발생한 메시지를 처리하기 위해서 루프에 들어감
32
(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
윈도우 프로시저에 더블클릭 메시지를 보낸다.
33
(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
34
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를 제외한 영역
35
Title bar
Menu bar
Window border
사용자 영역의 원점
Client Area
<사용자 영역>
36
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
SW_HIDE
윈도우를 감춘다.
SW_MAXIMIZE 윈도우를 전체 화면 크기로 만든다.
SW_MINIMIZE 윈도우를 아이콘화 한다.

SW_RESTORE
이전 상태로 되돌린다.
SW_SHOW
윈도우를 활성화시킨다.
BOOL UpdateWindow( HWND hWnd );

ShowWindow에서 발생한 WM_PAINT 메시지를 처리
37
(3) Message Loop의 진입

GetMessage




TranslateMessage



Message 중 키보드와 관련된 message에 대해서 특정 작업 수행
문자가 입력되었다는 Message (WM_CHAR)를 생성
DispatchMessage



Message queue로부터 메시지를 읽어 온다.
WM_QUIT메시지를 받으면 0(False)을 리턴한다.
Message loop를 빠져 나오면서, 프로그램을 종료한다.
Message를 윈도우 프로시저(WndProc)에 전달하는 역할을 한다.
OS에게 윈도우 프로시져의 호출을 요청
WM_QUIT Message가 오기 전까지 Loop
38
MSG 구조체
Typedef struct tagMSG
멤버
의미
Hwnd
메시지를 받을 윈도우 핸들
HWND hwnd;
Message
어떤 종류의 메시지 인가?
UINT messgae;
wParam
전달된 메시지의 부가 정보
WPARAM wParam;
lParam
전달된 메시지의 부가 정보
time
메시지가 발생한 시간
Pt
메시지가 발생했을 때의 마우스의 위치
{
LPARAM lParam;
DWORD time;
POINT pt;
}
마우스 왼쪽 버튼을 누른 경우
1st parameter: hwnd
2nd parameter: WM_LBUTTONDOWN
3rd parameter: Ctrl key나 shift key가 눌렸는지 여부
4th parameter: LOWOD(lPARAM)은 커서의 x좌표
HIWORD(lPARAM)은 커서의 y좌표
39
Window Procedure

LRESULT CALLBACK WndProc
(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam)
 해당 윈도우에서 발생한 메시지를 최종적으로 처리
 각 메시지마다 추가 정보가 wParam, lParam에 온다.

 - help참조
ex) WM_KEYDOWN 메시지
 nVirtKey = (int) wParam;
 lKeyData = lParam;

// virtual-key code
// key data
message handler가 없는 메시지는 DefWindowProc함수가
처리한다.
 WM_CLOSE, WM_ACTIVATE, WM_SYSCOMMAND 등
수십개의 메시지를 디폴트로 처리해준다.
40
중요한 메시지 (1)

WM_PAINT

윈도우의 모양에 변화가 생길 때 발생
 가려졌다가 복구
 크기가 변경될 때


BeginPaint()를 호출함으로써 시작
EndPaint()를 호출하여 끝냄
(2)에 WM_PAINT
메시지 발생
(1)
(1)
(2)
(2)
41
중요한 메시지 (2)

WM_SIZE



윈도우의 크기가 변경될 때
wParam : 메시지가 발생한 이유
플래그
값
SIZE_MAXHIDE
다른 윈도우가 최대화 되어 이 윈도우가 가려졌다
SIZE_MAXMIZED
최대화되었다.
SIZE_MAXSHOW
다른 윈도우가 원래 크기로 복구되어 이 윈도우가 드러났다.
SIZE_MINIMIZED
최소화 되었다.
SIZE_RESTORED
크기가 변경되었다.
lParam :
 상위 워드 : 변경된 후의 윈도우 높이
 하위 워드 : 변경된 후의 윈도우 폭
42
중요한 메시지 (3)

WM_MOVE



윈도우의 위치가 변경될 때
wParam : 위치 변경 플래그 (SIZE_RESTORED)
lParam
 상위워드 : 윈도우의 x 좌표
 하위워드 : 원도우의 y 좌표
43
중요한 메시지 (4)

WM_DESTROY



사용자의 명령에 의해 Windows가 원도우를 종료하고 있음을
알려준다.
자원을 OS에 반환
PostQuitMessage()를 호출
 프로그램의 메시지 큐에 WM_QUIT를 삽입
 GetMessage는 0을 반환
 WinMain이 메시지 루프를 벗어나게 함
 윈도우가 생성될 때 : WM_CREATE -> WM_SIZE
 윈도우가 종료될 때 : WM_CLOSE
-> WM_PAINT
-> WM_DESTROY -> WM_QUIT
44
실습

간단한 윈도우 프로그램 생성

WndClass의 내용을 변경하여 다음 과정을 수행
 1) 배경색 바꾸기  hbrBackgroud 를 이용
 2) 커서 바꾸기 LoadCursor
 3) 윈도우 타이틀 바꾸기

윈도우의 스타일 바꾸기
 1) 크기 변경
 2) 스타일 변경
 3) ShowWindow 옵션 변경

WinProc 변경
 1) Exit 메뉴를 누르면 메시지 출력  MessageBox()를 이용
 2) Exit 메뉴를 눌렀을 때 종료할지 여부를 결정
45
실습
 3) WM_RBUTTONDOWN에 대한 처리 추가
 오른쪽 버튼이 눌렸다는 메시지 출력
 메시지 상자를 통해 부팅이 가능하도록 수정
 ExitWindowEx(EWX_REBOOT, 0) 이용
46
3. Drawing
GDI (1)

GDI (Graphic Device Interface) 란



gdi32.dll
다양한 출력 장치에 대한 고수준 인터페이스
Device-independency 제공
 화면 출력과 프린터 출력 방법 동일
 출력 장치에 대한 정보를 분석하여 드라이버를 로드,
호출함으로써 실제 출력 작업을 수행
Device
Driver
GDI
그응
램용
프
로
실
장제
치출
력
WIN32 API
48
GDI (2)

GDI 개체

화면에 그림을 그리거나 문자를 출력할 때 사용하는 개체
 펜, 브러쉬, 비트맵, 영역, 글꼴, 팔레트


프로그램이 종료 되어도 GDI 개체는 자동적으로 제거되지
않는다. (프로그램에서 제거해 주어야 한다.)
StockObject

사용 빈도가 많아서 OS가 기본으로 제공하는 GDI 오브젝트
 ex) BLACK_PEN, BLACK_BRUSH, ANSI_FIXED_FONT


생성하거나 제거할 필요가 없다.
GDI 기본 구성 요소


(1) 텍스트(Text)
(2) 선과 곡선(Lines and Curves)
 직선, 사각형, 타원
49
GDI (2)

(3) 채워진 영역(Filled Areas)
 브러시 개체를 이용 – 색상, 패턴, 비트맵 이미지

(4) 비트맵(Bitmaps)
 디스플레이 장치의 픽셀과 일치하는 직사각형 배열

GDI 관련 함수





Device Context의 속성 관련 함수
Text 관련 출력 함수
도형 관련 출력 함수
그림 도구 변경 함수
Mapping mode 관련 함수
50
Device Context (1)

Device Context



출력 장치에 대한 정보를 나타내는 구조체
윈도우에서 모든 출력 요구는 DC를 통해 이뤄진다.
화면 출력의 경우 device context를 얻는 방법
 WM_PAINT
 BeginPaint - EndPaint
 WM_PAINT가 아닌 메시지 (클라이언트 영역)
 GetDC - ReleaseDC
 WM_NCPAINT
 GetWindowDC - ReleaseDC
 비트맵 출력
 CreateCompatibleDC – DeleteDC
51
Device Context (2)

독립성


hDC의 사용은 독립성을 유지
다음과 같은 점에 유의.
 hDC를 정적 변수로 선언해서는 안된다.
 윈도우 프로시저의 서로 다른 case문에서 동일한 hDC 사용할
수 없다.
 사용이 끝나면 반드시 release한다.
Device Context Handle를 얻는다.
GDI로 얻은 handle에 출력한다.
출력 절차
Device Context를 제거한다.
52
Device Context의 속성 관련 함수

int GetDeviceCaps(HDC hdc, // device-context handle
int nIndex // index of capability to query);
 Device Context의 속성을 알아낼 때 사용
 nIndex의 값과 의미(29개)








DRIVERVERSION
TECHNOLOGY
HORZSIZE
VERTSIZE
HORZRES
VERTRES
LOGPIXESX
LOGPIXESY
 SIZEPALETTE

- GDI Driver 버전
- Device 종류
- 출력 화면의 폭 (mm단위)
- 출력 화면의 높이(mm단위)
- 출력 화면의 폭 (pixel 단위)
- 출력 화면의 높이(pixel 단위)
- 출력 화면의 가로 방향 DPI
- 출력 화면의 가로 방향 DPI
- System Palette 크기
실습 : 화면의 해상도 출력하기
53
Text 관련 함수
 속성관련
 BOOL GetTextMetrics(HDC hdc, LPTEXTMETRIC lptm);
 설정된 글꼴에 대한 정보를 구함
 typedef struct tagTEXTMETRIC
{
int tmHeight,
int tmAveCharWidth,
BYTE tmItalic,
BYTE tmUnderlined…
}



COLORREF SetTextColor(HDC hdc, COLORREF crColor);
COLORREF SetBkColor(HDC hdc, COLORREF crColor);
UNIT SetTextAlign(HDC hdc, UINT fMode);
 fMode : 좌표의 위치를 결정(TA_CENTER|TA_LEFT…)
54
Text 관련 함수

출력함수

BOOL TextOut( HDC hdc, int nXStart, int nYStart,
LPCTSTR lpString, int cbString);
 LPCTSTR : 문자열 포인터

int DrawText( HDC hDC, LPCTSTR lpString, int nCount,
LPRECT lpRect, UINT uFormat);
 사각형 안에 정렬을 지정해서 (DT_LEFT, DT_VCENTER,
DT_NOCLIP) 문자열을 출력할 수 있다.

실습
 메뉴를 만들어서 글자색, 배경색, align 바꿔보기
(TextOut, DrawText)
55
도형 관련 출력 함수(1)

CP



GDI에서 다음 그래픽이 출력될 위치
내부적으로 기억됨
가장 기본적인 함수



SetPixel();
GetPixel();
COLORREF SetPixel(HDC hdc, int X, int Y, COLORREF
crColor);
색상
RGB
Blue
RGB(0, 0, 255)
Black
RGB(0, 0, 0)
Gray
RGB(128, 128, 128)
White
RGB(255, 255, 255)
Yellow
RGB(255, 255, 0)
56
도형 관련 출력 함수 (2)

BOOL MoveToEx(HDC hdc, int X, int Y, POINT lpPoint);


BOOL LineTo(HDC hdc, int nXEnd, int nYEnd);




CP의 위치를 X,Y로 이동
CP에서 지정한 위치까지 Line
BOOL Ellipse(HDC hdc, int nLeftRect, int nTopRect, int
nRightRect, int nBottomRect);
BOOL Rectangle(HDC hdc, int nLeftRect, int nTopRect,
int nRightRect, int nBottomRect);
BOOL RoundRect(HDC hdc, int nLeftRect, int nTopRect, int
nRightRect, int nBottomRect, int nWidth, int nHeight);


실습 : 메뉴를 누르면 선, 사각형, 타원, 모서리가 둥근 사각형 출력
마우스 버튼을 누르면 그 자리에 사각형 출력
57
GDI 개체(1)

GDI 개체를 사용하는 방법







(1) GDI 개체를 생성
 CreatePen, CreateSolidBrush 등 이용
(2) DC를 얻는다. (GetDC나 BeginPaint)
(3) 개체를 DC에 등록
 SeleteObject 함수 이용
 리턴되는 기존 개체는 저장
(4) DC를 사용하여 출력
(5) 이전 개체로 환원 (SelectObject)
(6) DC를 OS로 반환 (ReleaseDC나 EndPaint)
(7) 생성해서 사용한 개체를 삭제 (DeleteObject)
58
GDI 개체(2)
 펜 (Pen)
※선이나 영역의 경계선을 그릴 때 사용
※두께, 색상, 스타일 설정 가능
 BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor);
펜의 스타일
내용
PS_SOLID
실선
PS_DASH
파선
PS_DOT
점선
PS_DASHDOT
일점 쇄선
PS_DASHDOTDOT
이점 쇄선
PS_NULL
선을 그리지 않음
모양
59
GDI 개체(3)
 브러쉬 (Brush)
※ 색과 패턴을 이용하여 영역의 내부를 채울 때 사용
(1) CreateSolidBrush : 단일색을 가진 브러쉬 생성
(2) CreateHatchBrush : 패턴을 가진 브러쉬 생성
해치 브러시의 스타일
내용
HS_BDIAGONAL
오른쪽에서 왼쪽으로 45도 내려가는 빗금
HS_CROSS
십자가 형태의 빗금
HS_DIAGCROSS
X자 형태의 빗금
HS_FDIAGONAL
왼쪽에서 오른쪽으로 45도 내려가는 빗금
HS_HORIZONTAL
수평으로 빗금
HS_VERTICAL
수직으로 빗금
모양
60
GDI 개체(4)

예제 – 영역을 채운 사각형 출력
HPEN hPen, hOldPen;
HBRUSH hBrush, hOldBrush;
hPen = CreatePen(PS_DASH, 1, RGB(255, 0, 0));
hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 128, 0));
hdc = GetDC(hWnd);
hOldPen = (HPEN)SelectObject(hdc, hPen);
hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Rectangle(hdc, 0, 0, 400, 400);
SelectObject(hdc, hOldPen);
SelectObject(hdc, hOldBrush);
ReleaseDC(hWnd, hdc);
DeleteObject(hPen);
DeleteObject(hBrush);
61
GDI 개체(5)

비트맵




Pixel 단위로 표현한 그림
DDB (Device Dependent Bitmap, 장치 종속 비트맵)
 DDB는 별도의 색상정보(팔레트)가 포함되지 않음
 16 컬러로 제한
 GDI 비트맵
DIB (Device Independent Bitmap, 장치 독립 비트맵)
 이미지에 대한 색상 정보(팔레트)나 해상도, 데이터 압축 등을 포함
 하드웨어 종류가 달라져도 변형 없이 출력 가능
 24 비트 true color 표현 가능
Palette 오브젝트
 응용 프로그램이 필요로 하는 색과 시스템이 제공할 수 있는 색과의
차이를 조정하여 보다 효율적으로 색상을 표현
62
GDI 개체(6)

메모리 디바이스 컨텍스트 (Memory DC)
 비트맵 출력을 위해 필요
 메모리 DC의 경우 출력이 나가는 종이는 메모리상에 존재하는
비트맵이 된다.
 메모리 DC를 생성하려면 특정 출력 장치에 대한 DC를 먼저 생성
 출력 대상 DC에 대응하는 DC를 메모리에 생성
63
GDI 개체(7)

비트맵 출력 방법
① 화면 DC 생성
② 화면 DC와 호환성을 갖는 메모리 DC 생성
③ 비트맵을 읽는다.
④ 메모리 DC에 비트맵을 설정한다.
⑤ 메모리 DC에 있는 내용을 화면 DC로 전송한다.
⑥ 각종 제거 작업을 수행
메모리 DC 복원 및 생성한 메모리 DC 삭제
비트맵 제거
화면 DC release
64
GDI 개체(8)

비트맵 출력 예제
HDC hMemDC;
HBITMAP hBitmap, hOldBitmap;
BITMAP bm;
hMemDC = CreateCompatibleDC(hdc);
hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP));
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
GetObject(hBitmap, sizeof(BITMAP), &bm);
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldBitmap);
DeleteObject(hBitmap);
DeleteDC(hMemDC);
ReleaseDC(hWnd, hdc);
65
GDI 개체(9)

비트맵 출력 함수
BitBlt(HDC destDC, int destx, int desty, int width, int height, HDC
srcDC, int srcx, int srcy, DWORD ROP);
 StretchBlt : 사이즈를 변경해서 출력

래스터 연산(ROP코드)
논리 연산
설명
SRCCOPY
dst = src
그대로 복사
NOTSRCCOPY
dst = ~src
반전시켜 복사
SRCAND
dst = dst&src
AND 연산 결합
SRCPAINT
dst = dst|src
OR 연산 결합
SRCINVERT
dst = dst^src
XOR 연산 결합
66
GDI 개체(10)

래스터 연산
대상 비트맵
SRCCOPY
NOTSRCCOPY SRCPAINT
래스터
연산
원본 비트맵
SRCAND
실습
SRCINVERT
: Bitmap 출력, 화면중앙에 출력, 화면 전체로 확대, 타일로 출력
67
Drawing Mode (1)

Drawing Mode



도형이 그려질 때 원래 그려져 있던 그림과 새로 그려지는
그림과의 관계를 정의하는 함수
Int SetROP2(HDC hdc, int fnDrawMode);
Int GetROP2(HDC hdc);
그리기모드
설명
R2_BLACK
항상 검은색
R2_WHITE
항상 흰색
R2_NOP
아무런 그리기도 안함
R2_NOT
원래의 그림을 반전
R2_COPYPEN
원래의 그림을 덮어버리고 새 그림을 그림
R2_NOTCOPYPEN
새 그림을 반전시켜 그림
R2_MERGEPEN
OR 연산으로 두 그림을 합친다
R2_MASKPEN
AND 연산으로 겹치는 부분만 그림
R2_XORPEN
XOR 연산으로 겹치는 부분만 반전
68
Drawing Mode (2)

흑백에서의 비트 연산 예
원본
그림
COPY
OR
AND
XOR
69
Mapping Mode

Window & ViewPort

Window
 프로그램에서 사용하는 그래픽 출력함수는 논리적인 좌표
영역을 이용한다.

ViewPort
 화면의 장치 좌표를 이용한다.
응용 프
로그램
DC
Logical
Display
Device
Driver
논리(logical) 좌표
논리적 원도우
(window)
Actual
Display
장치(device) 좌표
뷰포트 (viewport)
Mapping
70
Mapping Mode 관련 함수

Mapping mode

Device Context에서 좌표를 해석하는 방법
 논리적 단위 사용
관련 API



int GetMapMode( HDC hdc);
int SetMapMode( HDC hdc, int fnMapMode );
 fnMapMode : 맵핑모드 식별자

BOOL LPtoDP( HDC hdc, LPPOINT lpPoints, int nCount );
 logical point -> device point

BOOL DPtoLP( HDC hdc, LPPOINT lpPoints, int nCount );
 device point -> logical point
71
매핑모드
MM_TEXT
MM_LOMETRIC
MM_HIMETRIC
MM_LOENGLISH
MM_HIENGLISH
MM_TWIPS
MM_ISOTROPIC
MM_ANISOTROPIC
원점
단위크기
Pixel
0.1mm
0.01mm
0.01inch
0.001inch
1/1440inch
임의적
임의적
X축 증가
오른쪽
오른쪽
오른쪽
오른쪽
오른쪽
오른쪽
선택
선택
Y축 증가
아래쪽
위쪽
위쪽
위쪽
위쪽
위쪽
선택
선택
원점
X좌표 증가(+)
사용자 영역
Y좌표 증가(+)
MM_TEXT
X좌표 증가(+)
사용자 영역
Y좌표 감소(-)
MM_HIMETRIC, MM_HIENGLISH
72
WM_PAINT (1)

WM_PAINT가 보내지는 시점




우선순위가 가장 낮다.
메시지 큐에 대기중인 메시지가 없어야 한다.
무효영역이 있어야 한다.
무효영역



화면의 일부가 변경되어 다시 그려져야 할 부분
운영체제는 최대한 좁은 면적만 무효영역으로 만듬
InvalidateRect(HWND hwnd, RECT *lpRect, BOOL bErase)
 해당 작업영역을 무효화 시켜 준다.

바로 다시 그리고 싶을 경우

UpdateWindow()
 WM_PAINT를 메시지 큐를 거치지 않고 WndProc으로 보냄
73
WM_PAINT (2)

WM_PAINT에서의 화면 복구
1
1
2
1번 윈도우에 의해
가려졌던 2번 윈도
우가 클릭된다.
1
2
가려졌던 영역이 일
단
WM_ERASERKGN
D 메시지에 의해 지
워진다.
2
WM_PAINT 메시지
에 의해 가려졌던 영
역이 복구된다.
74
WM_PAINT (3)

클리핑 영역




운영체제가 실제 그리기에 사용하는 영역
무효영역중에서도 화면에 보이는 가시 영역
BeginPaint()에 의해 계산
BeginPaint()

동작
 DC를 발급 받는다.
 클리핑 영역을 조사하여 DC에 설정, 운영체제는 이 값을
이용하여 영역 바깥으로 출력되는 것을 잘라낸다.
 무효영역을 없앤다.
 다시 그려지는 영역에 캐럿이 있다면 잠시 숨기고, EndPaint()에
의해 복구된다.
 WM_ERASEBKGND 메시지를 보내 배경을 지운다.
 WM_PAINT 메시지를 보내 작업 영역을 그리도록 한다.
75
GetDC vs BeginPaint

HDC GetDC( HWND hWnd );



Device Context를 얻고, 화면 출력에 사용
ReleaseDC로 Device Context를 제거
HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lpPaint );



WM_PAINT 메시지에서만 사용 가능
lpPaint로 복구할 영역 정보를 얻을 수 있다.
EndPaint로 Device Context를 제거
case WM_PAINT:
{
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd, &ps);
// ps.rcPaint에 복구 영역의 좌표가 들어 있다. 이 부분만 그릴 수 있다면 이상적이다.
EndPaint(hWnd, &ps)
}
76
4. Input Message
Introduction

Message




하나의 사건을 가리키는 상수
현재 약 200 개의 메시지가 존재
windows.h에 정의
ex)WM_KEYDOWN, WM_MOUSEMOVE, ……..
78
4.1 기본 입력 메시지

6가지의 입력 메시지




Keyboard, Mouse, Timer 입력 메시지
문자, Scrollbar, Menu 입력 메시지
Note) 키보드, 마우스 : 현재성이 중요
분류

하드웨어적인 이유로 발생하는 메시지
 Keyboard, Mouse, Timer

Keyboard message or Mouse message를 해석한 메시지
 Character, Scrollbar, Menu
79
Keyboard 입력 메시지(1)

메시지 종류



WM_KEYDOWN, WM_KEYUP
WM_SYSKEYDOWN, WM_SYSKEYUP : ALT Key
wParam와 lParam에 부가적인 정보
wParam
Virtual Keycode(windows.h에 정의)
lParam
키의 scan code와 keyboard의 상태
- 비트 0 -15 : 키의 반복 횟수,
- 비트 16-23 : 키의 스캔 코드
- 비트 24 : 확장키(1: T, 0: F), 확장키란 ASCII코드가 없는
키 ex) Insert, Delete 키
- 비트 25-26 : 쓰이지 않음
- 비트 27-28 : OS가 사용
- 비트 29 : 1이면 ALT키가 눌린 것, 0이면 ALT키가 눌리지
않은 것
- 비트 30 : 키의 이전 상태, 1이면 키가 눌린 것, 0이면 키가
눌리지 않은 것
- 비트 31 : 1->WM_KEYDOWN, 0->WM_KEYUP
80
Keyboard 입력 메시지(2)

Virtual Keycode(window.h)



프로그래밍시 wParam에 전달되는 가상 키 코드가 더 중요
VK_로 시작
ASCII코드가 있는 경우, ASCII코드 사용
VK_RETURN
Enter키가 눌린 경우
VK_ESCAPE
ESC키가 눌린 경우
VK_HOME
Home키가 눌린 경우
VK_INSERT
Insert키가 눌린 경우
VK_NUMLOCK NumLock키가 눌린 경우
VK_SPACE
Space Bar가 눌린 경우
VK_LEFT
왼쪽 방향키가 눌린 경우
81
문자 입력 메시지

메시지 종류


WM_CHAR, WM_SYSCHAR(ALT Key가 눌린 상태)
cf)WM_KEYDOWN
ASCII코드가 존재, TranslateMessage함수가 call
 TranslateMessage : 키의 값을 가지고 문자를 만들어 냄

WM_KEYDOWN vs WM_CHAR

‘s’ 키를 누를 때:
 WM_KEYDOWN -> WM_CHAR -> WM_KEYUP

‘insert’키를 누를 때:
 WM_KEYDOWN -> WM_KEYUP
82
Mouse 입력 메시지

마우스 클릭


마우스의 이동


클라이언트 영역 & 비클라이언트 영역
현재성
마우스 더블클릭


Application에서 조합하여 만든 메시지
일정 시간 안에 두 번 눌리면 메시지를 변경
83
Mouse 입력 메시지(1)

메시지 종류 (9종류)


WM_LBUTTONDOWN, WM_MOUSEMOVE,
WM_LBUTTONUP, WM_LBUTTONDBLCLK,...
WM_LBUTTONDBLCLK
 wc.style = CS_DBLCLKS; // ……….. WNDCLASS에 등록


MouseWheel  WM_MOUSEWHEEL
Mouse dragging을 처리하는 메시지는 제공 안됨
wParam
마우스 버튼 상태와 특수키(CTRL, Shift)들의 상태를 알 수 있다.
- MK_SHIFT , MK_CONTROL, MK_LBUTTON, MK_MBUTTON,
MK_RBUTTON,……
lParam
메시지가 발생한 시점의 X, Y좌표
X좌표 : 하위워드, Y좌표 : 상위워드
84
Mouse 입력 메시지(2)
T1에서 T2 사이에는 1번
윈도우로 마우스 메시지
가 발생하고, T2와 T3사
이에는 2번 윈도우로 마
우스 메시지가 발생한다.
1
2
T1
T2
T3
마우스 메시지와 윈도우
85
Mouse 입력 메시지(3)

Mouse dragging할 때의 문제점
① 드래그 시작
② 윈도우 바깥으로 나가면 마
우스 메시지가 이 윈도우에게
로 발생하지 않는다.
드래그시의 문제점
86
Mouse 입력 메시지(4)



SetCapture function
 커서가 어디에 있었는지에 상관없이 모든 마우스 메시지가 그
함수의 인자로 주어진 윈도우로 전달
 마우스 메시지를 독점
HWND SetCapture(HWND hWnd
// handle of window to receive mouse capture);
ReleaseCapture function
 마우스 메시지의 독점을 해제
BOOL ReleaseCapture(VOID)
GetCapture function

Identifies the window that has the mouse capture.
HWND GetCapture(VOID);
87
Mouse 입력 메시지(5)

Mouse dragging의 구현

두 동작의 결합
 마우스 이동 & 마우스 단추를 누른다.

드래깅 시작
 HWND SetCapture(HWND hWnd)
 이 함수를 호출하면 application 밖에서도 위치를 알 수 있다.

버튼 up인 경우 드래깅을 끝낸다.
 BOOL ReleaseCapture(VOID);
case WM_MOUSEMOVE:
if (wParam == MK_LBUTTON)
SetCapture(hWnd);
}
break;
case WM_LBUTTONUP:
if (GetCapture() == hWnd)
ReleaseCapture();
break;
………………………………………….
88
Mouse 입력 메시지(6)

비 작업영역에서


Title bar, 경계선, 스크롤 바
NC_
 wParam : 비 클라이언트 영역을 가르킨다.
 lParam : 스크린 좌표
89
Mouse 입력 메시지(7)

예제 – 상자 그리기



마우스메시지 이용
SetCapture, ReleaseCapture 이용
마우스의 좌측 버튼을 누르면서 드래그하면 박스 그려짐
90
Timer 입력 메시지(1)

WM_TIMER






한번만 지정
주기적으로 작업을 수행, ex)주기적인 저장
Msg Queue에 중복으로 저장 안됨
wParam : 타이머 ID
lParam : 호출될 함수의 번지
Timer의 용도





멀티태스킹
시간 표시
일정한 시간 간격으로 파일을 자동 저장
슬라이드 쇼
움직이는 동작 처리
91
Timer 입력 메시지(2)
Timer 실행방법 (1)

WM_CREATE


UINT SetTimer(HWND hWnd, UINT nIDEvent, UINT uElapse,
TIMERPROC lpTimerFunc);
 HWND hWnd : WM_TIMER메시지를 받는 윈도우 핸들
 UINT idTimer : 0이 아닌 값, timer ID
 UINT uTimer : 시간 간격, 0.001초 단위
 TIMERPROC lpTimerFunc : 메시지를 받을 함수,
NULL - 일정 간격으로 WM_TIMER 메시지를 받음
WM_DESTROY

BOOL KillTimer(HWND hWnd, UINT uIDEvent);
 Ex) SetTimer(hWnd, 1, 5000, NULL)
92
Timer 입력 메시지(3)

Timer의 구별


wParam에 Timer 번호가 기록
Timer 의 수
 제한 없다.
 Win16 : 16 개
ex)
WM_TIMER :
Switch (wParam)
{
case 1: ~~~
case 2: ~~~
}
93
Timer 입력 메시지(4)
Timer 실행방법 (2)
 타이머 프로시저



타이머를 설치할 때 지정한 시간이 경과되면 자동적으로 실행되는
함수를 지정할 수 있다.
WM_TIMER보다 비교적 정확
TimerProc()
 LRESULT CALLBACK TimerProc (HWND hWnd,
UNIT uMsg, //WM_TIMER 메시지
WPARAM wParam, // 타이머 ID
LPARAM lParam // 현재 시간)



TimerProc()의 실행이 끝나면 호출한 곳으로 돌아감
실습 : WM_TIMER의 발생 간격과 TIMERPROC의 발생 간격 측정
1초마다 화면에 시간 표시
94
Keyboard 입력 메시지(3)

예제 – 글자 떨어뜨리기







메뉴의 Begin, End로 시작, 종료
2초 간격으로 글자를 떨어뜨린다. (폰트, 글자색, 배경색 바꾸기)
왼쪽, 오른쪽 방향키로 방향 이동
윈도우의 하단을 벗어나면 다시 상단으로 감
윈도우의 크기를 변화시키면 상단 중앙에서부터 다시 떨어짐
처음에는 WM_TIMER로 처리하고, TIMERPROC으로 같은 동작
처리
글자 떨어지기 변경
 밑에 도달하면 위로 이동, 위에 도달하면 아래로 이동
 떨어질 때 빨간색, 올라올 때 파란색

글자 옆으로 이동
 왼쪽에 도달하면 오른쪽으로, 오른쪽에 도달하면 반대로 이동

메뉴를 사용하여 이동 방향 변경
95
Scrollbar 입력 메시지


윈도우를 생성할 때, WS_VSCROLL, WS_HSCROLL을 주면
scroll bar 생성
메시지 종류

WM_VSCROLL, WM_HSCROLL
wParam
하위 워드
- SB_LINEDOWN, SB_LINEUP
- SB_PAGEDOWN, SB_PAGEUP
- SB_THUMBTRACK, SB_THUMBPOSITION
 상위 워드
- SB_THUMBTRACK, SB_THUMBPOSITION일 때의
thumb의 위치 값
lParam
Scrollbar의 윈도우 핸들
96
메시지 전달

SendMessgae(hwnd,msg,wParam,lParam)




곧바로 윈도우 프로시저로 보내짐
메시지가 완전히 처리되기 전에는 리턴하지 않는다.
윈도우간, 윈도우와 차일드 컨트롤간의 통신에 주로 사용
PostMessage(hwnd, msg, wParam, lParam)



메시지를 메시지 큐에 넣어 놓기만 하고 바로 리턴
급하지 않거나 지금 작업이 완전히 끝내야만 처리할 수 있는
메시지에 사용
성공하면 TRUE 리턴, 가급적 확인할 것
97
메시지 큐

메시지 종류

Queue 메시지
 사용자의 입력으로부터 발생

Non-Queue 메시지
 큐를 통하지 않고 바로 윈도우 프로시져로 보내짐
 ex) UpdateWindow를 호출했을 때의 WM_PAINT

Queue 종류


System Message Queue: 하나만 존재
Thread Message Queue : 스레드당 존재
 즉 메시지 큐는 스레드당 하나씩 생기는 것
 스레드 생성시에는 큐가 없음
98
4.2 사용자 정의 메시지 (1)

User Defined Message
 윈도우들간의 정보 교환
 구성
 0 through WM_USER – 1 Messages reserved for use by the
system.
 WM_USER through 0x7FFF Integer messages for use by private
window classes.
 WM_APP through 0xBFFF Messages available for use by
applications.
 0xC000 through 0xFFFF String messages for use by applications.
 Greater than 0xFFFF Reserved by the system for future use

함수와의 차이
 프로세스 통신 가능
99
4.2 사용자 정의 메시지 (2)

해당 윈도우에 메시지를 보내는 방법

LRESULT SendMessage(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam);
 윈도우에 바로 전달해서 msg 처리 후 리턴

BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM
wParam, LPARAM lParam);
 msg queue에 넣은 후 바로 리턴

WM_COPYDATA
 서로 다른 process에 속한 윈도우간에 pointer 전달
100
4.2 사용자 정의 메시지 (3)

ex) 프로세스간의 메시지 통신

메시지 ID 정의
 UNIT RegisterWindowMessage(LPCTSTR lpString)
 사용되지 않는 ID를 리턴
 통신하고자 하는 윈도우는 같은 문자열을 사용해서 메시지 ID를
얻어야 한다.

통신하려는 윈도우 탐색
 FindWindow() : Caption 값을 이용, 윈도우 핸들을 알아냄

메시지 전달
 SendMessage()

실습
 윈도우 2개를 만들어서 사용자 정의 메시지를 정하고, 메시지를
받으면 메시지 박스를 출력한다.
101
예제
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_FILE_EXIT:
SendMessage(hWnd, WM_CLOSE, 0, 0);
break;
…………
}
switch(message)
{
case WM_MYMESSAGE:
LPSTR lpData;
lpData = (LPSTR)lParam;
// ……….원하는 일을 수행한다.
}
102
메시지 수신

GetMessage()


메시지가 없으면 새로운 메시지가 전달될 때까지 리턴하지
않는다.
PeekMessage()


메시지가 없더라도 즉각 리턴
WM_QUIT 메시지에 대한 예외 처리 필요
for (;;) {
if (PeekMessage(&Message,NULL,0,0,PM_REMOVE))
{
if(Message.message==WM_QUIT)
break;
TranslateMessage(&Message);
DispatchMessage(&Message);
}
}
103
서브 클래싱

서브클래싱



윈도우 프로시저로 보내지는 메시지를 중간에 가로챔
중간에 메시지를 변경할 수 있다.
주로 컨트롤에서 많이 이용
메시지
운영체제
서브클래스 프로시져
리턴
윈도우 프로시져
104
Control
Control Basic (1)

Control

기능이 미리 정해진 윈도우
 원하는 기능을 가진 컨트롤을 생성하여 이용하면 된다.



스타일에 따라 기능이 달라짐
단독으로 존재할 수 없고, 항상 child 윈도우
각 control을 사용할 때 알아야 할 것
 컨트롤의 스타일
 컨트롤에 보낼 수 있는 메시지
 컨트롤이 부모 윈도우에게 보내는 알림 코드

종류
 Built-in control : OS에 미리 등록된 컨트롤 (19가지 - Win32)
 Custom control : third party에서 제공하는 컨트롤
106
Control Basic (2)

6가지 기본 컨트롤
107
Control Basic (3)

Notification Message
컨트롤이 자신에게 생긴 일을 parent 윈도우에게 알릴 때 사용
 WM_COMMAND 메시지를 사용 (cf. Scroll 제외)

 메시지 타입
 LOWORD(wParam)
 HIWORD(wParam)
 lParam
:
:
:
:
WM_COMMAND
Child 윈도우 ID (자식 윈도우 이름)
알림 코드 (발생한 일의 종류)
컨트롤의 윈도우 핸들
사용자가 이렇게 행동하였다
(WM_COMMAND)
Control
( 독립적인 메시지 처리가능)
부모 윈도우
... 한 일을 하여라.
( SendMessage() )
108
Control Basic (4)
WM_COMMAND :
Switch (LOWORD(wParam))
Case ControlID1 : ~~~~
Case ControlID2 : ~~~~
Switch(HIWORD(wParam))
Case 알림코드 :~~~
109
Control Basic (5)

Control 작성법

Parent가 CreateWindow() 함수를 호출하여 생성
 CreateWindow(classname, title, style, left, top, width, height,
parenhtwnd, (HMENU)id, hinstance, lparam);

Control Class

Control의 형태는 CreateWindow(lpClassName,…) 에서
lpClassName 에 의해 결정
lpClassName
생성되는 Control
“BUTTON”
Push, Radio, Check
“LISTBOX”
목록상자
“COMBOBOX”
복합상자
“EDIT”
글상자
“SCROLLBAR”
이동줄
“STATIC”
라벨
110
Control Basic (6)

Control Style

세번째 인자(wStyle)를 이용하여 지정
hOKBtn = CreateWindow(“BUTTON”, “OK”,
BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE,
20, 20, 80, 40, hWnd, IDC_OKBTN, hInst, NULL);
 WS_CHILD : Child 윈도우
 WS_VISIBLE : ShowWindow없이 생성과 동시에 보이도록
한다.

Control ID & Handle

ID는 0 이상의 정수
HWND GetDlgItem(HWND hDlg, int nIDDlgItem);
 컨트롤 ID로부터 핸들 정보를 알아낸다.

111
Control Basic (7)

Focus

키 입력의 시작점
 창에 여러 컨트롤이 존재하는 경우 키 입력은 초점이 설정된
컨트롤에 대행 수행

초점 설정
 SetFocus(hwnd);
112
Button Control (1)

Button control의 종류
113
Button Control (2)

Button control의 종류(wStyle)






Push button
Default push button
Check box
Radio button
Owner draw button
: BS_PUSHBUTTON
: BS_DEFPUSHBUTTON
: BS_CHECKBOX,BS_AUTO_CHECKBOX
: BS_RADIOBUTTON
: BS_OWNERDRAW, BS_GROUPBOX
Notification code (부모 윈도우로)





BN_CLICKED
: 사용자가 click하면 발생
BN_DISABLE
: button이 비활성화 되면 발생
BN_DBLCLICKED : 사용자가 double click하면 발생
BN_SETFOCUS
BN_KILLFOCUS
114
Button Control (3)

상태 조사 및 종류

SendMessage(hWnd, message, WPARAM, LPARAM);
Push Button
- OK, Cancel button
Default push button
- 엔터를 누르면 실행되는 버튼
Check box
- 배타적이지 않은 옵션 선택, ex) 문자 속성 지정
- BM_SETCHECK, BM_GETCHECK
Radio button
- 배타적인 옵션 선택, ex) 문단 정렬
- BM_SETCHECK, BM_GETCHECK
Owner draw button
- push button처럼 동작
- button control style을 BS_OWNERDRAW로 지정
- WM_MEASUREITEM, WM_DRAWITEM을 parent 윈도우가 처리
115
CheckBox

종류


수동, 자동
수동의 경우 그때그때의 상태를 보고 조작을 해 주어야 한다.
 Check 시마다 변경값을 알아야 하는 경우 사용
 BST_CHECK, BST_UNCHECK
ex)
If (SendMessage(c1, BM_GETCHECK, 0, 0) == BST_UNCHECKED)
{
SendMessage(c1, BM_SETCHECK, BST_CHECKED, 0);
// 기타 …
}
116
RadioBox

종류


수동, 자동
그룹
 하나의 선택사항에 대해 여러 개의 라디오 버튼들이 그룹 형성
 같은 그룹에 속한 라디오 버튼은 오직 하나만 선택
 그룹을 이루는 첫 번째 라디오 버튼에만 WS_GROUP 스타일

버튼을 생성한 후에는 CheckRadioButton() 호출
ex)
CreateWindow(…, BS_GROUP, …);
r1 = CreateWindow(…, WS_GROUP, …);
R2 = CreateWindow(……);
CheckRadioButton(hwnd, r1, r2, r1);
117
Static Control(1)

Static Control



작성


주로 텍스트 출력에 사용
문자열 입출력 외에는 특별한 이벤트나 제어 메시지가 없다.
lpClassName : “STATIC”
Control에 문자열 입출력

Control에 문자열 lpString을 출력
 SetWindowText(hWnd, lpString);

Control의 문자열을 lpBuf에 읽어들임
 GetWindowText(hWnd, lpBuf, nMaxLength)

모든 윈도우에 적용 가능 -> 윈도우 타이틑 입출력
118
Static Control(2)

Style(wStyle)
SS_BLACKFRAME
둘레를 black으로 칠한다.
SS_GRAYFRAME
둘레를 gray로 칠한다.
SS_WHITEFRAME
둘레를 white로 칠한다.
SS_BLACKRECT
내부를 black으로 칠한다
SS_GRAYRECT
내부를 gray로 칠한다
SS_WHITERECT
내부를 white로 칠한다
SS_LEFT, SS_CENTER,
SS_RIGHT
텍스트의 정렬 방식
SS_NOPREFIX
&을 단축키로 인식하는 것을 중지한다.
SS_SIMPLE
한 줄짜리 static 컨트롤을 지정한다.
119
Edit Control(1)

Edit control


문자의 입력과 편집
Edit control’s style









ES_MULTILINE
: 디폴트는 한 줄짜리 에디터
ES_WANTRETURN
: Return키 사용 가능 (멀티라인 사용시)
ES_AUTOHSCROLL
: 수평 스크롤
ES_AUTOVSCROLL
: 수직 스크롤
ES_PASSWORD
: 모든 내용이 *로 표시
ES_LEFT, ES_CENTER, ES_RIGHT : 정렬
ES_UPPERCASE
: 입력되는 문자를 대문자로 표시
ES_LOWERCASE
: 입력되는 문자를 소문자로 표시
ES_READONLY
: 키보드로 편집 불가
120
Edit Control(2)

제어 메시지








EM_GETLINE
EM_GETLINECOUNT
EM_CANUNDO
EM_UNDO
EM_SETSEL
EM_GETSEL
WM_SETTEXT
WM_GETTEXT
: 특정 라인의 내용 읽기
: 전체 라인 수
: 가장 최근 명령의 취소여부 알아 내기
: 가장 최근 명령을 취소
: 선택영역(블록) 잡기
: 선택영역(블록)의 위치 알아 내기
: 새로운 내용으로 설정
: 편집 내용 읽어 오기
121
Edit Control(3)

알림코드
EN_CHANGE
문자열이 변경되었다.
EN_UPDATE
문자열이 변경되기 직전이다.
EN_HSCROLL
가로 스크롤을 마우스로 건드림
EN_VSCROLL
세로 스크롤을 마우스로 건드림
EN_MAXTEXT
EDIT에 문자열을 더 입력할 수 없음
EN_SETFOCUS
해당 EDIT에 초점이 설정
EN_KILLFOCUS
해당 EDIT에서 초점이 떠났음
122
Edit Control(4)

화면 출력

EN_UPDATE
 문자열이 변경된 후 화면에 출력하기 전에 보내주는 메시지
 문자열 길이에 따라 에디트의 폭을 늘리거나 별도의 조치 가능

EN_CHANGE
 문자열이 화면으로 출력되고 난 후 보내지는 메시지

입출력

edit contol의 내용을 최대 nMax 문자까지 buf에 읽어들인다.
 nCount = GetWindowText(hEdit, buf, nMax)

edit control에 buf의 내용을 출력한다.
 SetWindowText(hEdit, buf)
123
Edit Control(5)

폰트 변경

WM_SETFONT
 wParam : 폰트의 핸들
 lParam : 폰트를 바꾼후 에디트를 다시 그릴 것인가?

실습 – 간단한 editor
 Edit control 생성 (WM_CRETE에서 CreateWindow 사용)
 Edit control의 font 변경
HFONT hFontE
hFontEdit = CreateFont(30,0,0,0,0,0,0,0,HANGEUL_CHARSET,3,2,1,
VARIABLE_PITCH | FF_ROMAN, “궁서”);
SendMessage(hEdit, WM_SETFONT, (WPARAM)hFontE, MAKELPARAM(FALSE,0));
 Undo, copy, paste, cut, clear 구현
 메뉴 생성, 생성한 edit control의 WM_UNDO, WM_COPY,
WM_PASTE, WM_CUT, WM_CLEAR 등을 이용
 글자가 입력되면 EN_CHANGE가 오는지 확인
 에디트 2개를 만들어서 내용을 복사
124
List Box Control(1)

List Box control


선택 가능한 대상을 나열하고, 이 중에서 선택
Style(wStyle)

LBS_NOTIFY 필수
LBS_HASSTRINGS
여러 스타일의 조합
(LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)
각 항목별로 별도 데이터 저장
LSB_MULTICOLUMN
수평으로도 스크롤이 가능한 다중열 리스트
LBS_MULTIPLESEL
여러 항목 동시 선택 가능
LBS_NOTIFY
click, double click시에 알림 코드 발생
LBS_SORT
알파벳순으로 정렬
LBS_STANDARD
125
List Box Control(2)

제어 메시지(SendMessage)

LB_ADDSTRING
 항목 추가, lParam를 사용하여 추가하고자 하는 문자열 번지를 넘겨줌
 LBS_SORT인 경우는 추가하면서 정렬된다.

LB_INSERTSTERING
 지정한 위치에 항목을 추가한다.
 LSB_SORT인 경우에도 정렬하지 않는다.

LB_DELETESTRING
 지정한 위치에 있는 항목을 삭제, wParam으로 항목의 번호를 넘겨주며,
남은 항목수 리턴

LB_DIR
 특정 디렉토리에서 해당하는 파일들을 읽어들여서 리스트에 항목으로
추가한다. (파일 관련 대화상자에서 이용 가능)

LB_GETCURSEL, LB_SETCURSEL
 현재의 선택된 항목의 인덱스를 얻어오거나 변경


LB_GETCOUNT : 전체 항목수
LB_GETSEL, LS_SETSEL
 인덱스로 지정한 항목의 상태를 얻거나 변경
126
List Box Control(3)

LB_GETTEXT, LB_SETTEXT
 특정 인덱스의 문자열을 얻어오거나 변경

LB_GETITEMDATA
 LBS_HASSTRINGS일 때, 별도의 데이터를 읽어들임

LB_SETITEMDATA
 LBS_HASSTRINGS일 때, 별도의 데이터를 저장

알림 코드 (List Box에서 이벤트 발생시)

HIWORD(wParam)
LBN_DBLCLK
한 항목을 Double click하면 발생
LBN_ERRSPACE
내부적으로 메모리 부족 발생
LBN_KILLFOCUS
입력 포커스를 잃으면 발생
LBN_SELCHANGE
선택 항목이 변경되면 발생
LBN_SETFOCUS
입력 포커스를 받으면 발생
127
List Box Control(4)

항목 데이터



문자열 이외에 32비트의 item data를 가질 수 있다.
정수나 포인터를 사용해서 다른 형태의 데이터도 저장 가능
사용법
 LB_SETITEMDATA 메시지 전달
 wParam : item index
 lParam : item data
ex) SendMessage(hList, LB_SETITEMDATA, 0, (LPARAM)1000);
 wParam으로 항목의 index를 주고 LB_GETITEMDATA 메시지
전달
ex) itemData = SendMessage(hList, LB_GETITEMDATA, 0, 0)
128
List Box Control(5)

항목 검색

LB_FINDSTRING
 wParam : 문자열 검색 시작 index
 -1 로 지정할 경우 처음부터
 lParam : 찾고자 하는 문자열
 선두 부분이 일치하는 것을 찾아 index 리턴
 찾지 못하면 , LB_ERR 리턴

LB_FINDSTRINGEXACT
 lParam과 정확히 일치하는 항목만 검색

LB_SELECTSTRING
 LB_FINDSTRING으로 찾은 후 LB_SETCURSEL 메시지 전달
129
List Box Control(6)

실습

리스트 박스와 static control 생성
 WM_CREATE에서 CreateWindow
 리스트 박스에 아이템 추가 (LB_ADDSTRING)
 리스트에서 다른 항목을 선택할 때마다 static contorl에 현재
선택된 항목을 출력
 리스트 항목에 부가 데이터 설정하고 더블 클릭하면 그 내용을
static control에 출력
 에디트 컨트롤에 입력된 스트링을 리스트에서 찾아서 결과를
static control에 출력
 LB_DIR 속성을 이용하여 파일 탐색기 구현
 SendMessage(hWndList, LB_DIR, DIRATTR, (LPARAM)"*.txt");
130
Combo Box Control(1)

Combo Box



Edit box + List Box
필요한 경우에만 항목을 열어서 화면공간 절약
Style(wStyle)






CBS_SIMPLE
CBS_DROPDOWN
CBS_ DROPDOWNLIST
CBS_AUTOHSCROLL
CBS_HASSTRINGS
CBS_SORT
: list box처럼 항상 펼쳐진 스타일
: edit control + list box
: static control + list box
: 수평 스크롤 가능
: 각 항목에 부가 정보 저장
: 알파벳순으로 정렬
131
Combo Box Control(2)

제어 메시지

CB_ADDSTRING
 콤보 박스의 리스트에 항목 추가
 CBS_SORT라면 추가하면서 정렬

CB_INSERTSTRING
 콤보 박스의 리스트 박스에 지정한 위치에 항목 추가
 CBS_SORT라도 추가하면서 정렬하지 않는다.


CB_DELETESTRING
CB_DIR
 와일드 카드를 지정하면 특정 디렉토리에서 파일 리스트를 읽어들여서
리스트에 추가

CB_GETCURSEL, CB_SETCURSEL
 리스트 박스에서 현재 선택된 항목의 인덱스를 읽어오거나 변경


CB_GETCOUNT
CB_GETLBTEXT, CB_SETLBTEXT
132
Combo Box Control(3)

알림 코드

CBN_CLOSEUP
 리스트 박스가 닫힐 때 발생

CBN_DBLCLK
 리스트 박스 내의 항목을 더블클릭







CBN_DROPDOWN : 리스트 박스가 펼쳐짐
CBN_EDITCHANGE : 에디트의 내용이 변경
CBN_EDITUPDATE
CBN_SETFOCUS
CBN_KILLFOCUS
CBN_SELCHANGE
CBN_ERRSPACE
133
Scrollbar (1)

종류

표준 스크롤바
 옆과 아래에 밀착
 WS_HSCROLL, WS_VSCROLL

스크롤바 컨트롤
 CreateWindow()로 만들어지는 독립적인 윈도우

구조
화살표
몸통(Shaft)
(Arrow)
썸(Thumb)
134
Scrollbar (2)


표준 Scrollbar는 스타일을 지정할 수 없다.
Message


WM_VSCROLL, WM_HSCROLL을 부모 윈도우에게 전달
WM_COMMAND를 사용하지 않는다.
인수
LOWORD(wParam)
HIWORD(wPARAM)
lParam
설명
사용자가 스크롤 바의 어디를 눌렀는지를 알려줌
썸의 위치값, 단 사용자가 썸을 드래그할 때만 전달
스크롤 바위 윈도우 핸들, 표준 스크롤 바에서는 NULL
135
Scrollbar (3)
 LOWORD(wParam)에 전달되는 scroll message
SB_LINEUP
SB_PAGEUP
SB_LINEDOWN
SB_PAGEDOWN
Thumb을 drag하는 동안 SB_THUMBTRACK이 계속 발생
Thumb의 drag가 끝나면 SB_THUMBPOSITION이 발생
 BOOL EnableWindow(HWND hWnd, BOOL bEnable);
- 윈도우를 활성화 또는 비활성화 시킨다.
136
Scrollbar(4)

스크롤 범위와 위치

기본
 스크롤바 : 0~100
 스크롤바 컨트롤 : 0~0

정의
 SetScrollRange(HWND hwnd, int nbar, int nMinPos, int nMaxPos,
BOOL bRedraw)
 bRedraw = false
 SetScrollPos(HWND hwnd, int nbar, int nMinPos, int nMaxPos,
BOOL bRedraw)
 bRedraw = true
nBar
SB_CTL
SB_HORZ
SB_VERT
설명
스크롤바 컨트롤이며, hWnd 는 범위 지정 스크롤 바의 윈도우 핸들
수평 표준 스크롤바, hWnd는 스크롤바를 가진 윈도우의 핸들
수직 표준 스크롤바, hWnd는 스크롤바를 가진 윈도우의 핸들
137
Scrollbar(5)

정확한 범위 설정


작업영역의 크기에서 화면 크기를 뺀 부분으로 설정
화면 크기에 따라 스크롤 범위가 변경되어야 한다.
 WM_SIZE에서 스크롤 범위 지정
ex)
case WM_SIZE:
xMax = 1024 – LOWORD(lParam);
yMax = 768 – HIWORD(lParam);
SetScrollRange(hWnd, SB_VERT, 0, yMax, TRUE);
SetScrollPos(hWnd, SB_VERT, 0, TRUE);
SetScrollRange(hWnd, SB_HORZ, 0, xMax, TRUE);
SetScrollPos(hWnd, SB_HORZ, TRUE);
Return 0;
138
Scrollbar(6)

스크롤 영역




화면이 스크롤  전체 화면이 변하는 것
전체 화면을 다시 그리지 않는다.
위치만 변하는 부분은 비트맵으로 복사
과정
 스크롤 된 만큼 화면을 고속 복사(bitblt())
 새로 드러난 부분 무효화
 WM_PAINT에 의해 드러난 부분이 새로 그려짐


ScrollWindow(Hwnd hwnd, int xAmount, int yAmount, RECT
*lpRect, Rect *lpClipRect)
클리핑 영역
 무효 영역과 가시화 영역의 교집합이며, 그리기의 대상이 되는
영역
139
Scrollbar(7)

비례 스크롤 바


위치와 길이를 함께 보여줌
SetScrollInfo() 사용
 SetScrollRange(), SetScrollPos()의 기능을 한꺼번에
 SetScrollInfo(hWnd, SB_CTL, &si, TRUE)
 si는 SCROLLINFO형 구조체
typedef struct {
UINT cbsize;
// 이 구조체의 바이트 수
UNIT fMask;
// 대부분 SIF_ALL 사용
int nMin;
// 최소값
int nMax,
// 최대값
UINT nPage;
// 한 페이지의 크기, Thumb의 길이를 결정
int nPos;
// 스크롤 바의 위치
int nTrackPos; // Thumb를 끌고 있는 현재의 위치
} SCROOLLINFO;
140
Scrollbar(8)
ex)
SCROLLINFO si;
....
case WM_SIZE:
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
si.nMin= 0;
si.nMax = 768;
si.nPage = HIWORD(lParam);
si.nPos = yPos;
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
si.nMax = 1024;
si.nPage = LOWORD(lParam);
si.nPos=xPos;
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
141
Scrollbar Control

Scrollbar control


Scrollbar control style



SBS_VERT
SBS_HORZ
: 수직 스크롤 바를 생성
: 수평 스크롤 바를 생성
제어 메시지






연속적인 범위의 값에서 하나의 값 선택
SBM_ENABLE_ARROWS
SBM_GETPOS
SBM_GETRANGE
SBM_SETPOS
SBM_SETRANGE
: 활성, 비활성 여부 지정
: 현재 thumb의 위치 알아 내기
: 양끝에 설정된 값 알아 내기
: 현재 thumb의 위치 설정
: 양끝에 새로운 값 설정하기
관리 함수


ShowScrollBar()
EnableWindow()
142
Scrollbar Control (2)

한 윈도우


표준 스크롤바와 스크롤바 컨트롤을 모두 사용
lParam 로 구분
 표준 : NULL
 컨트롤 : 컨트롤 바 윈도우 핸들값
143
ETC(1)

자식 윈도우 프로시져 가로채기
설정)
HWND butwnd;
WNDPROC butProc;
butwnd = CreateWindow(“buttom”,”버튼”, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 10,
20, 100, 40, hwnd, (HMENU)1, hinst, NULL);
butProc = (WNDPROC)SetWindowLong(butwnd, GWL_WINPROC, (LONG)ButtonProc);
Callback 함수)
LRESEULT CALLBACK ButtonProc(HWND hwnd, UNIT imsg, WPARAM wParam, LPARAM
lParam);
{
Switch (imsg)
{ // 버튼에 해당하는 내용 기록
}
return CallWindowProc(butProc, hwnd, imsg, wParam, lParam);
}
144
ETC(2)

자식 윈도우 색상 변경
ex)
case WM_CTCOLORSTATIC :
return (LRESULT)CreateSolidBrush(RGB(10,10,10));
Message
Child Window
WM_CTLCOLORSTATIC
정적 외곽 박스형
WM_CTLCOLORMSGBOX
메시지 박스
WM_CTLCOLORLISTBOX
리스트 박스
WM_CTLCOLOREDIT
에디트 박스
WM_CTLOLORSRLLBAR
스크롤 바
WM_CTLCOLORDLG
다이얼로그
145
ETC(3) : 버튼 윈도우 메시지
ex) case WM_COMMAND :
if(LOWORD(wParam)==1)
// 1번으로 설정된 버튼이면
switch (HIWORD(wParam))
case BN_CLICKED : ~~~;~~~; break;
case BN_SETFOCUS : ~~~;~~~; break;


문제점) 버튼의 수가 증가하게 되면?
해결점) 함수의 포인터
 형(* 함수명)();
ex)
void Button1(HWND hwnd, UNIT imsg, WPARAM wParam, LPARAM lParam);
void Button2(HWND hwnd, UNIT imsg, WPARAM wParam, LPARAM lParam);
void Button3(HWND hwnd, UNIT imsg, WPARAM wParam, LPARAM lParam);
void (*Button[3])(HWND hwnd, UNIT imsg, WPARAM wParam, LPARAM lParam)=
{Button1, Button2, Button3};
case WM_COMMAND;
Button[LOWORD(wParam)](hwnd, imsg, wParam, lParam);
break;
146
ETC (4)

사용자 정의 그리기



버튼 생성시 : BS_OWNERDRAW
윈도우에서 --> WM_DRAWITEM 메시지 발생
(wParm : 버튼의 번호, lParam : 버튼의 정보)
 이 메시지와 함께 들어오는 lParam을
포인터로 받음
 구조체를 이용하여 사용자가 직접 그림
DRAWITEMSTRUCT
ex) case WM_DRAWITEM:
drawbut = (LPDRAWITEMSTRUCT)lParam;
147
ETC (5)

윈도우 활성, 비활성화


EnableWindow() 를 이용
BOOL EnableWindow(HWND hwnd, BOOL bEnable);
 활성일 경우 true, 비활성이면 false

Static Window에 메시지 전달



WM_CREATE에서 static window 생성
새로운 프로시져 등록 (StaticProc())
이벤트에 따른 메시지를 정적 윈도우로 전달
 SendMessage()
148
6.Resource
Introduction

Resource


읽기 전용의 사용자 인터페이스 관련 데이터
리소스는 코드와 분리해서 관리한다.
 res 파일로 관리


VC++ ResourceView가 시각적으로 관리
cf) VC++ 1.5까지는 AppStudio
Text로 편집 : Open As에서 Text로 선택
150
Dialog Box (1)

Dialog Box


응용 프로그램에서 사용자와 대화하기 위해서 사용하는 팝업
윈도우
컨트롤을 자식 윈도우로 갖는 특수한 부모 윈도우
151
Dialog Box (2)

종류

Modal dialog box
 입력을 받지 않으면 다음 작업 진행이 불가능한 사용자 입력을
받을 때 사용
 대화 상자를 닫아야만 다른 작업이 가능
 모달 대화상자의 경우 입력이 끝나면 화면에서 사라진다.
 대부분의 dialog box가 여기에 해당
 ex) 파일 메뉴의 열기(Open) 명령의 대화상자

Modeless dialog box
 모달 대화상자처럼 사용자가 입력을 했다고 없어져야 하는 것은
아니다.
 대화상자를 띄운 상태로 부모 윈도우와 대화상자가 공존
 ex )찾기 명령 명령의 대화상자

생성, 파괴하는 API 만 다르다.
 DialogBox vs. CreateDialog, EndDialog vs. DestroyWindow
152
Dialog Box (3)

대화 상자의 작성 절차




(1) 리소스 뷰에서 대화상자의 모양 작성
(2) 대화상자의 동작이 기술된 대화상자 프로시저 작성
(3) 대화상자 생성
Control palette의 구성 컨트롤
static control
group box
check box
combo box
horizontal scroll
spin scroll
slider
list control
tab control
rich edit control
picture control
edit control
push button control
radio control
list box
vertical scroll
progress bar
hotkey control
tree control
animation control
custom control
153
Dialog Box (4)
IDD_SELECTOBJECT DIALOG DISCARDABLE 0, 0, 185, 92
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION “Select Object”
FONT 8, “MS Sans Serif”
BEGIN
DEFPUSHBUTTON “OK”, IDOK, 129, 6, 50, 14
PUSHBUTTON
LISTBOX
“Cancel”, IDCANCEL, 129, 23, 50, 14
IDC_LISTBOX, 8, 7, 113, 80, LBS_SORT |
LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
END
154
Dialog Box Procedure (1)

대화상자 프로시져



WM_INITDIALOG 메시지



대화상자도 윈도우이기 때문에 윈도우 프로시저가 필요
주로 두 개의 메시지만을 처리
대화상자가 생성될 때 제일 처음 오는 메시지
컨트롤들을 초기화
WM_COMMAND 메시지



컨트롤이 부모 윈도우에게 자신에게 발생한 일을 알리는데
사용되는 알림 메시지(notification message)
LOWORD(wParam) : 컨트롤 ID(자식 윈도우 이름)
HIWORD(wParam) : 발생한 일의 종류를 나타내는 알림 코드
155
Dialog Box Procedure (2)

GetDlgItem


컨트롤을 조작하기 위해서는 윈도우 핸들이 필요
자식 윈도우의 윈도우 핸들을 얻어옴
 HWND GetDlgItem(hWndDlg, controlID);

대화 상자 생성
 Modal 대화 상자 : DiagloBox
 Modeless 대화 상자 : CreateDialog -> ShowWindow

대화 상자의 종료


Modal 대화 상자 : EndDialog
Modeless 대화 상자 : DestroyWindow
156
Dialog Box Procedure (3)
BOOL APIENTRY 대화상자 프로시져 이름(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
// 가장 먼저 발생하므로 여기서 컨트롤을 초기화한다.
return TRUE;
case WM_COMMAND :
// 컨트롤의 알림 메시지 처리
switch((LOWORD(wParam))
// 컨트롤에 따라 분류
{
case 컨트롤 ID1 :
{
switch(HIWORD(wParam)) // 일어난 일에 따라 처리
{
.......
}
}
case 컨트롤 ID2 :
{
switch(HIWORD(lParam)) // 일어난 일에 따라 처리
{
.......
}
}
.....
}
return TRUE;
}
157
return FALSE;
}
Dialog Box Procedure (4)
BOOL APIENTRY SelectObj(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// 리스트 박스의 윈도우 핸들을 얻는다.
HWND hListBox = GetDlgItem(hDlg, IDC_LIST);
// 리스트 박스로 메시지를 보내 채운다.
SendMessage(hListBox, LB_ADDSTRING, NULL, (LONG)(LPCSTR)"Rectangle");
SendMessage(hListBox, LB_ADDSTRING, NULL, (LONG)(LPCSTR)"Ellipse");
SendMessage(hListBox, LB_ADDSTRING, NULL, (LONG)(LPCSTR)"Line");
SendMessage(hListBox, LB_ADDSTRING, NULL, (LONG)(LPCSTR)“Box");
// wCurType 변수 값에 따라 리스트 박스의 현재 선택을 만든다.
SendMessage(hListBox, LB_SETCURSEL, wCurType, 0L);
return (TRUE);
}
158
Dialog Box Procedure (5)
case WM_COMMAND:
{
HWND hListBox = GetDlgItem(hDlg, IDC_LIST);
switch(wParam)
{
case IDOK : // OK 버튼이 눌린 경우
{
DWORD dwIndex = SendMessage(hListBox, LB_GETCURSEL, 0, 0L);
wCurType = (enum OBJECTTYPE)dwIndex;
EndDialog(hDlg, TRUE);
return (TRUE);
}
case IDCANCEL :
{
EndDialog(hDlg, TRUE);
return (TRUE);
}
}
}
}
return (FALSE);
}
159
Modal Diabog Box

생성 : DialogBox


int DialogBox(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent,
DLGPROC lpDialogFunc);
파괴 : EndDialog
BOOL EndDialog(HWND hDlg, int nResult);
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDM_SELECT_OBJECT :
{
DialogBox(hInst, MAKEINTRESOURCE(IDD_SELECTOBJECT),
hWnd, SelectObj);
break;
}
.....................…
}
160
}

Modeless Dialog Box (1)

생성 : CreateDialog

HWND CreateDialog(HINSTANCE hInstance, LPCTSTR
lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc);

ShowWindow를 이용해서 화면에 출력
 ShowWindow(dialogwnd, SW_SHOW);
 ShowWindow(dialogwnd, SW_HIDE);

// 화면에 출력
// 화면에서 감춤
삭제 : DestroyWindow

BOOL DestroyWindow(HWND hWnd);
161
Modeless Dialog Box (2)

모달리스 대화상자는 메시지 루프 변경이 필요

부모 윈도우와 대화상자가 동시에 떠있기 때문에 어느
윈도우로 메시지가 가야 할지 정해야 한다.
while (GetMessage(&msg, NULL, NULL, NULL))
{
if (hDlg == NULL || !IsDialogMessage(hDlg, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
162
Common Dialog Box (1)

Common Dialog Box



comdlg32.dll 라이브러리에서 제공하는 대화 상자
구조체를 초기화하여 함수를 호출하면 간편하게 다양한
기능의 대화 상자를 이용할 수 있다.
공통 대화 상자를 띄우는 절차




commdlg.h를 포함
Project->Settings->Link의 Object/Library modules에
comdlg32.lib를 넣기
공통 대화상자별로 필요한 구조체 초기화
정해진 함수 호출
163
Common Dialog Box(2)

Common Dialog Box의 종류, 구조체, 호출함수
종류
구조체
호출함수
File Open
OPENFILENAME
GetOpenFileName
File Save
OPENFILENAME
GetSaveFileName
Printer
PRINTDLG
PrintDlg
Find
FINDREPLACE
FindText
Replace
FINDREPLACE
ReplaceText
Color Choose
CHOOSECOLOR
ChooseColor
Font Choose
CHOOSEFONT
ChooseFont
Page Setup
PAGESETUPDLG
PageSetupDlg
164
실습 (1)

대화상자에서 색, 타입을 지정하면 지정된 색과
타입의 도형 출력

화면에 버튼 4개 생성
 2개는 BS_OWNERDRAW, 나머지는 FONT, FILE



Ownerdraw 버튼 그리기 (FillRect and Bitmap)
대화상자 템플릿 작성 및 대화상자 프로시져 작성
버튼을 누르면 도형 타입을 선택할 수 있는 대화상자 띄우기
 DialogBox



WM_PAINT에서 선택한 값에 따라 도형 바꿔서 그리기
버튼을 누르면 color choose dialog를 띄워서 색을 선택하면
도형을 선택한 색으로 바꿔 그리기
FONT 버튼을 누르면 font choose dialog를 띄워서 지정한
폰트로 변경
165
실습 (2)


File 버튼을 누르면 파일 열기 대화 상자 띄우기
리스트에 텍스트를 채우고 find dialog로 찾아보기
166
PRINTDLG pd;
pd.lStructSize = sizeof(PRINTDLG);
pd.hwndOwner = hWnd;
pd.Flags = PD_RETURNDC;
if(PrintDlg(&pd)) // 해당 함수의 호출, 인자로 앞의 변수가 사용되었다.
{
………………….
}
만일 프린터 설정 대화상자를 띄우고 싶다면,
pd.flags=PD_RETURNDC | PD_PRINTSETUP
167
ICON

Icon



메인 윈도우가 축소되거나 배경 화면에 등록할 때 응용 프로그램을
나타내기 위한 그래픽 이미지
WNDCLASS의 hIcon에 LoadIcon으로 등록
종류
 Built-in Icon : OS에 미리 등록된 Icon
 User defined Icon: 사용자가 만든 Icon

Built-in Icon

종류
IDI_APPLICATION
디폴트 응용 프로그램 아이콘
IDI_ASTERISK
대화상자에서 사용하는 별표(*) 모양의 아이콘
IDI_EXCLAMATION
느낌표(!) 모양의 아이콘 (경고할 때 사용)
IDI_HAND
손모양의 아이콘( 심각한 경고를 할 때 사용)
IDI_QUESTION
물음표(?) 모양의 아이콘 (질문할 때 사용)
 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
168
User defined Icon

User defined icon


리소스 편집기로 아이콘 작성
resource.h에 아이콘 등록 - 숫자와 string 둘 다 가능
 아이콘의 Resource ID가 숫자인 경우:
wc.hIcon =
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON);
 아이콘의 Resource ID가 string인 경우:
wc.hIcon =
LoadIcon(hInstance, “IDI_MYICON”);
169
Icon 직접 표시하기

직접 아이콘을 표시해야 하는 경우


ex) 시계 프로그램
WNDCLASS 등록할 때
 wc.hIcon = NULL;

WndProc 처리할 때
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC;
hDC = BeginPaint(hWnd, &ps);
if (IsIconic(hWnd)){ /* Icon상태에 맞게 출력 작업 수행 */}
else { /* 정상적인 상태에 맞게 화면 복구 */}
EndPaint(hWnd, &ps);
break;
}
170
Cursor

Cursor





마우스의 위치를 가리키는 포인터 cf) caret
Hot spot : 마우스가 가르키는 지점
WNDCLASS의 hCusror에 LoadCursor로 등록
모양에 따라 작업 종류 파악 ex) 모래 시계,...
종류
 Built-in Cursor : OS에 미리 등록된 Cursor
 User defined Cursor : 사용자가 만든 Cursor

Built-in Cursor

wc.hCursor = LoadCursor(NULL, IDC_ARROW);
171
Built-in Cursor
IDC_ARROW
화살 모양의 디폴트 커서
IDC_CROSS
십자가 모양의 커서(윈도우 등의 이동할 때 사용)
IDC_IBEAM
텍스트 입력 위치를 결정하는 데 쓰이는 커서
IDC_ICON
비어 있는 커서
IDC_SIZENESW
우측 하단에 사각형을 포함하는 커서
IDC_SIZENS
북쪽과 남쪽을 가리키는 커서
IDC_SIZENWSE
북서쪽과 남동쪽을 가리키는 커서
IDC_UPARROW
수직으로 선 화살표 모양의 커서
IDC_WAIT
모래 시계 모양의 커서
172
User defined Cursor

User defined cursor




리소스 편집기로 커서 작성
resource.h에 커서 등록 - 숫자와 string 둘 다 가능
Hot spot
 마우스 포인터의 위치
wc.hCursor =
LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYCURSOR));
173
그 밖의 커서 모양 표시하기

WNDCLASS에 등록하지 않고 매번 그리는 경우


WM_SETCURSOR 또는 WM_MOUSEMOVE 메시지가 올
때마다 SetCursor함수 호출
WndProc에서
static HCURSOR hMyCursor;
…..
switch(msg)
{
case WM_CREATE:
// 앞으로 사용할 커서 모양을 미리 load해 놓는다
hMyCursor = LoadCursor(hInstance, (LPSTR)”MyCursor”);
………
case WM_SETCURSOR:
SetCursor(hMyCursor);
break;
174
WM_SETCURSOR

WM_SETCURSOR


wParam : window handle
lParam : hit-test code (뒤 페이지 참고)
case WM_SETCURSOR:
if(LOWORD(lParam) == HTCLIENT) {
SetCursor(hMyCursor); // hMyCursor에 커서가 미리 load되었다고 하자.
return TRUE;
}
return DefWindowProc(hWnd, message, wParam, lParam);
175
HTBORDER
크기 조절이 불가능한 윈도우의 테두리에 커서가 위치
HTBOTTOM
윈도우의 하단 테두리에 커서가 위치
HTBOTTOMLEFT
윈도우의 좌측 하단 테두리에 커서가 위치
HTBOTTOMRIGHT 윈도우의 우측 하단 테두리에 커서가 위치
HTCAPTION
윈도우의 타이틀바 영역에 위치
HTCLIENT
윈도우의 사용자 영역에 위치
HTHSCROLL
수평 스크롤바에 위치
HTLEFT
윈도우의 좌측 테두리에 위치
HTMAXBUTTON
전체화면(Maximize)버튼에 위치
HTMENU
메뉴 영역에 위치
HTMINBUTTON
아이콘화 버튼에 위치
HTRIGHT
윈도우의 우측 테두리에 위치
HTSYSMENU
시스템 메뉴에 위치
HTTOP
윈도우의 상단 테두리에 위치
HTTOPRIGHT
윈도우의 좌측 상단 테두리에 위치
HTVSCROLL
윈도우의 수직 스크롤바에 위치
176
잠깐동안 다른 커서 모양 표시
HCURSOR hSaveCursor;
HCURSOR hHourGlass;
………
hHourGlass = LoadCursor(NULL, IDC_WAIT);
………
hSaveCursor = SetCursor(hHourGlass);
// 모래시계 커서를 loading
// 커서 모양을 모래시계로 변경
/* 시간이 오래 걸리는 작업 수행 ex) file I/O */
SetCursor(hSaveCursor);
ReleaseCapture();
………
// 커서를 원상복구
// 마우스 독점 해제
커서가 하는 일은 단순히 마우스 위치를 표시하는 것으로 이외에도
프로그램의 상태를 나타내는 것이다. 예를 들어 작업할 수 없는
영역에 들어갈 경우에 커서가 X자 모양으로 바뀌는 경우
177
예제

Cursur를 만들어 좌측 버튼을 클릭시 커서 변경
HCURSOR cur;
...
case WM_LBUTTONDOWN:
cur = LoadCursorFromFile("test.cur");
SetCursor(cur);
case WM_LBUTTONUP:
Setcursor(LoadCursor(NULL, IDC_ARROW));
break;

마우스가 움직이거나 다른 메시지 발생시 원래값으로 돌아간다.
 해결) flag 설정
BOOL cflag = FALSE; // 함수 밖에서 extern으로 설정
case WM_LBUTTONDOWN: // 커서 변경
cflag= TRUE;
case WM_LBUTTONUP: // 커서 변경
cflag= FALSE;
case WM_MOUSEMOVE:
if (cflag) { // 커서를 로드 } else { //원래의 커서로}
178
예제

마우스가 어플리케이션 밖에 나갔다 들어올 경우


해결점)
WM_SETCURSOR
 자신의 윈도우에 포커스가 있을 때 발생하는 메시지
ex)
case WM_SETCURSOR:
if (cflag) { hcur=LoadCursorFromFile("test.cur"); SetCursor(hcur); }
else { SetCursor(LoadCursor(hInst,IDC_ARROW); } break;

wc에 설정된 커서와 교차되는 문제점



해결점)
GetClassLong() : RegisterClassEx에 등록된 정보를 꺼내올 때
SetClassLong() : RegisterClassEx에 정보를 등록시킬 때
ex)
HCURSOR cur = LoadCusorFromFile("test.cur");
SetClassLong(hwnd, GCL_HCURSOR, (LONG)cur);
179
실습

도형 그리기 프로그램에 도형의 종류에 따라 cursor
변경

도형 타입만큼의 커서 등록
 WM_CREATE, LoadCursor

WM_SETCURSOR에서 도형의 타입에 따라 커서 로드
180
캐럿 (1)

캐럿



키보드의 다음 입력 위치를 가리키는 용어
시스템 전역적으로 하나만 존재
생성 및 파괴



BOOL CreateCaret(HWND hWnd, HBITMAP hBitmap, int
nWidth, int nHeight)
BOOL DestroyCaret(VOID)
생성 시점
 WM_SETFOCUS 메시지가 전달 되었을 떄

화면 표시


BOOL ShowCaret(HWND hWnd)
BOOL HideCaret(HWND hWnd)
181
캐럿 (2)

Ex)

HideCaret(hWnd);
HDC hdc = GetDC(hWnd);
//그리기
ReleaseDC(hWnd, hdc);
ShowCaret(hWnd);
cf) WM_PAINT
 일부로 숨기지 않아도 된다.

캐럿의 위치



BOOL SetCaretPos(int X, int Y);
BOOL GetCaretPos(LPPOINT lpPoint);
깜박임 속도


BOOL SetCaretBlinkTime(UINT uMSeonds);
UINT GetCaretBlinkTime(VOID);
182
Bitmap

Bitmap


OS에서 가장 많이 사용하는 BMP 파일을 resource화
종류
 장치 의존 bitmap(DDB)
: palette 정보 포함 안함
 자원을 이용하여 비트맵을 로드,출력
 장치 독립 bitmap(DIB)
: palette 정보 포함
 Bmp 파일에서 비트맵을 로드하여 출력

Bitmap 생성
VC++ resource editor 사용


DC(Device Context)



출력 장치를 가리키는 자료구조
DC의 구성요소 : bitmap, brush, pen, palette, font
GDI

출력 장치에 출력을 하는 그래픽 출력 함수의 집합
183
Bitmap

과정


비트맵을 생성
비트맵 로드
 hBitmap = LoadBitMap(hInstance, 비트멥 ID)


비트맵 출력
비트맵에서 패턴 얻어오기
 CreatePatternBrush(hBitmap);
Ex) 비트맵을 이용 배경화면 사용
bBitmap = LoadBitmap(hInstance,ID_BITMAP);
hBrush = CreatePattern(hBitmap);
,,
wc.hbrBackground = hBrush;
184
Bitmap

DC를 비트맵으로

CreateBitmap (비트맵 가로크기, 세로크기, 비트맵 플랜,
픽셀당 비트수, 팔레트 데이터);
ex) 문자를 비트맵으로
HBITMAP hBitmap; HDC memdc;
hBitmap = CreateBitmap(100,100,1,24,NULL);
memdc = CreateCompatableDC(hdc); SelectObject(memdc,hBitmap);
TextOut(memdc, 0, 0, "Test",12);
185
Bitmap 출력방식

Memory Device Context 생성

특정 출력 장치의 DC와 동일한 속성을 가지는 DC를 메모리에
만든 것
DC간의 자료 교환



메모리 DC  화면 DC 또는 프린터 DC
BitBlt(1:1 복사), StretchBlt(축소 또는 확대 복사)
HDC hDC, hMemDC;
hDC = GetDC(hWnd); // hWnd가 가리키는 윈도우에 대한 DC를 얻는다.
hMemDC = CreateCompatible(hDC); // 메모리 DC 생성
/* 원하는 작업 수행*/
DeleteDC(hMemDC);
// 메모리 DC 삭제
ReleaseDC(hWnd, hDC);
186
BitBlt vs StretchBlt(1)

BOOL BitBlt( HDC hdcDest, int nXDest, int nYDest, int nWidth, int
nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop );
 HDC hdcDest : target DC
 int nXDest, int nYDest : target DC에서의 bitmap의 시작 X, Y좌표
 int nWidth, int nHeight : target DC에서의 bitmap의 폭, 높이
 HDC hdcSrc : source DC
 int nXSrc, int nYSrc: source DC에서의 bitmap의 시작 X, Y좌표

DWORD dwRop : raster 적용 기술





SRCAND
SRCCOPY
SRCPAINT
SRCINVERT
- (source DC AND target DC)
- source DC
- (source DC OR target DC)
- (source DC XOR target DC)
=> target DC
=> target DC
=> target DC
=> target DC
BOOL StretchBlt( HDC hdcDest, int nXOriginDest, int nYOriginDest, int
nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int
nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop );
확대 or 축소
187
BitBlt vs StretchBlt(2)
Target DC(MemDC)
Target DC(MemDC)
Source DC(화면DC)
Source DC(화면DC)
<BitBlt의 경우>
<StretchBlt의 경우>
188
메모리 DC의 bitmap교체(1)

절차



bitmap을 메모리로 loading
메모리 DC의 bitmap 변경(SelectObject사용)
메모리 DC의 bitmap을 출력 DC로 복사
(BitBlt, StretchBlt사용)
189
메모리 DC의 bitmap교체(2)
HDC hDC, hMemDC;
HBITMAP hBitmap, hOldBitmap;
// 비트맵을 메모리로 loading
hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_MYBITMAP));
hDC = GetDC(hWnd);
hMemDC = CreateCompatibleDC(hDC);
// 메모리 DC를 만든다.
// 메모리 DC의 bitmap을 교체한다.
hOldBitmap = SelectObject(hMemDc, hBitmap);
……………..
// 각종 제거 작업을 수행한다.
SelectObject(hMemDC, hOldBitmap);
DeleteObject(hBitmap);
DeleteDC(hMemDC);
ReleaseDC(hWnd, hDC);
// 메모리 DC의 bitmap을 원상복구
// bitmap을 제거한다.
// 메모리 DC를 삭제한다.
190
Memory DC  화면 DC 로 복사
HDC hDC, hMemDC;
HBITMAP hBitmap, hOldBitmap;
BITMAP bm;
// bitmap을 메모리로 올린다.
hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_MYBITMAP);
hDC = GetDC(hWnd);
hMemDC = CreateCompatible(hDC);
// 메모리 DC를 만든다
// 메모리 DC의 bitmap을 교체한다
hOldBitmap = SelectObject(hMemDC, hBitmap);
// bitmap의 크기를 알아낸다
GetObject(hBitmap, &bm);
// 메모리 DC에 들어간 bitmap을 화면 DC로 복사한다
BitBlt(hDC, 10, 10, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
// 각종 제거 작업을 수행한다
SelectObject(hMemDC, hOldbitmap);
DeleteObject(hBitmap);
DeleteDC(hMemDC);
ReleaseDC(hWnd, hDC);
// 메모리 DC를 원상 복구
// bitmap을 제거
// 메모리 DC를 제거
191
int GetObject( HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject);
- graphic object에 대한 정보를 얻는 데 사용한다.
192
그 밖의 bitmap의 출력 방법

빈 bitmap을 생성하고, GDI로 출력
: dynamic하다.



HBITMAP CreateBitmap( int nWidth, int nHeight, UINT
cPlanes, UINT cBitsPerPel, CONST VOID *lpvBits );
HBITMAP CreateCompatibleBitmap( HDC hdc, int nWidth,
int nHeight );
메모리 DC를 거치치 않고, 출력 장치로 출력

int SetDIBitsToDevice( HDC hdc, int XDest, int YDest,
DWORD dwWidth, DWORD dwHeight, int XSrc, int YSrc,
UINT uStartScan, UINT cScanLines, CONST VOID *lpvBits,
CONST BITMAPINFO *lpbmi, UINT fuColorUse );
193
Menu

용어
액셀러레이터
메뉴 바(Menu)
팝업 메뉴(SubMenu)
194
Menu

속성

ID
 해당 메뉴들은 독립적인 ID 값을 가짐

Caption
 메뉴의 내용

메뉴 관련 메시지

WM_COMMAND
 LOWORD(wParam) : 메뉴에 해당하는 ID
 HIWORD (wParam) : 0
 lParam : 0
195
Menu

윈도우에서 기본적으로 제공해 주는 메뉴(WS_SYSMENU)
시스템 메뉴
ex) 메뉴 아이템 추가시
hSys = GetSystemMenu(hwnd, FALSE);
AppendMenu(hSys, MF_STRING, 1, "Test");


Floating 팝업 메뉴

마우스 버튼 클릭시 그 위치에서 나타나는 메뉴
ex)
case WM_RBUTTONDOWN:
point.x = LOWORD(lParam);
point.y = LOWORD(lParam);
ClientToScreen(hwnd, &point);
TrackPopupMenu(hsubMenu, PM_LEFTALIGN, point.x, point.y, 0, hwnd,
NULL);

Default Menu Item
 팝업 메뉴를 더블 클릭하면 디폴트로 선택되는 메뉴
 SetMenuDefaultItem()
196
Menu 생성 방법

방법

(1) 메뉴 편집기에서 생성
 윈도우 생성시 wndclass의 lpszMenuName에 resource ID 설정
(wc.lpszMenuName =“MyMenu")

(2) LoadMenu(), SetMenu() 이용
 여러 개의 메뉴를 생성시킨 후 윈도우에 붙임

(3) CreateMenu(), CreatePopupMenu()
 프로그램 도중에 새로운 메뉴를 생성시킴
197
Menu 교체

각 상태에 맞는 메뉴를 실행 중에 로드
ex) 메뉴를 로드 :
HMENU hMenu = LoadMenu(hInstance, "Menu");
SetMenu(hwnd, hMenu);

프로그램이 종료되기 전에 직접 파괴
DestroyMenu(hMenu);
198
Menu 생성 (실행중)

프로그램 실행중에 메뉴 생성

CreateMenu() --> AppendMenu()

AppendMenu(hMenu, uFlag, MenuID, content)
 uFalg : MF_BITMAP, MF_OWNERDRAW, MF_STRING
ex)
HMENU hMenu = CreateMenu();
HMENU sMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)sMenu,”Menu”);
AppendMenu(sMenu, MF_STRING, ID_NEW,"&New\f1 tCtrl+N");
AppendMenu(sMenu, MF_STRING ,ID_OPEN,"&Open\f1 tCtrl+N");
AppendMenu(hMenu, MF_POPUP, (UINT)sMenu, "&File");
199
Menu 속성 변경 (1)

메뉴 초기화


WM_INITMENU
메뉴의 상태

UNIT GetMenuState(HMENU hMenu, UINT uId, UINT uFlags);
 MF_BYCOMMAND, MF_BYPOSITION
 MF_CHECKED, MF_DISABLED, MF_GRAYED, MF_HILITE

특정 메뉴의 체크 설정 및 해제

CheckMenuItem(hMenu, uIDCheckItem, CheckFlag)
 MF_BYCOMMAND Indicates that the uIDCheckItem parameter gives
the identifier of the menu item.
 MF_BYPOSITION Indicates that the uIDCheckItem parameter gives
the zero-based relative position of the menu item.
 MF_CHECKED Sets the check-mark attribute to the selected state.
 MF_UNCHECKED Sets the check-mark attribute to the clear state.
CheckMenuItem(hMenu, ID_NEW, MF_UNCHECKED);
CheckMenuItem(hMenu, ID_NEW, MF_CHECKED);
200
Menu 속성 변경 (2)

특정 메뉴의 활성화 및 비활성화

EnableMenuItem(hMenu, MenuID, ActiveFlag)
EnableMenuItem(hMenu, ID_NEW, MF_CRAYED);
EnableMenuItem(hMenu, ID_NEW, MF_ENABLED);

기존 메뉴 수정

BOOL ModifyMenu(HMENU hMenu, UINT uPostion, UINT
uFlags, UINT uIDNewItem, LPCTSTR lpNewItem);
 기존 메뉴의 내용이나 형태, 동작을 수정한다.
 ModifyMenu(hMenu, id, MF_BYCOMMAND, id, "&Save
Selection");
201
Menu 속성 변경 (3)

메뉴 항목 관련




InsertMenu(hMenu, 위치, 메뉴 flag, 메뉴 ID, 문자열);
DeleteMenu(hMenu, 위치, 메뉴 flag);
 팝업 항목 사라짐
RemoveMenu(hMenu, 위치 , 메뉴 flag);
 팝업 항목 그대로
DrawMenuBar(hWnd);
 수정 후 메뉴를 다시 출력
202
기타 함수

메뉴를 얻음
 상위 메뉴(설정된 메뉴)

ex) HMENU hMenu; hMenu = GetMenu(hwnd)
 서브 메뉴(팝업 메뉴)


ex) HMENU hMenu; hMenu = GetSubMenu(hMenu, 0) // 0번째 서브메뉴
메뉴의 문자열 얻기
 GetMenuString(hMenu, 메뉴 ID,문자열을 저장할 버퍼, 버퍼의 최대
크기, 메뉴 flag)
 MF_BYCOMMAND : 메뉴 ID 에 의해서 값을 얻음
 MF_BYPOSITION : 0부터 시작하는 순서대로
ex) case WM_COMMAND:
if (GetMenuString(hMenu, LOWORD(wParam), temp, 80,
MF_BYCOMMAND) == 0)
{
MessageBox(hwnd, temp,"메뉴”, MB_OK);
}
203
Menu 관련 메시지

WM_INITMENUPOPUP


WM_CONTEXTMENU



메뉴 선택시 (항목위에 있을 경우)
WM_COMMAND


마우스 오른쪽 버튼을 클릭했을 때
floating popup 메뉴 호출에 사용 가능
WM_MENUSELECT


메뉴가 활성화될 때, 즉 화면에 표시될 때
메뉴 선택시
WM_HELP

메뉴에서 f1 누를 경우
204
응용 : 비트맵 메뉴 생성(1)

비트맵 메뉴 설정


메뉴를 프로그램에서 작성해야 한다.
메뉴에 나타낼 비트맵을 등록/로드
ex)
static HBITMAP hFileNew, hFileOpen,hFileMenu;
hFileNew = LoadBitmap(hInstance, "New");
hFileOpen = LoadBitmap(hInstance, "Open");
hFileMenu = LoadBitmap(hInstance, "File Menu");
205
응용 : 비트맵 메뉴 생성 (2)

윈도우에 설정할 메뉴 생성

서브메뉴 생성
hSubMenu = CreateMenu();

비트맵을 설정한 메뉴를 추가
AppendMenu(hSubMenu, MF_BITMAP, ID_NEW,
(PSTR)(LONG)hFileNew);
AppendMenu(hSubMenu, MF_BITMAP, ID_OPEN,
(PSTR)(LONG)hFileOpen);

생성한 메뉴를 parent menu에 붙임
AppendMenu(hMenu, MF_STRING|MF_POPUP, (UINT) hSubMenu,
“Submenu");
206
Accelerator

Hot Key - .res 파일에 저장

ex) Shift + SpaceBar(한/영 전환), Ctrl+Y(한 줄 삭제)
// 엑셀러레이터를 메모리로 올린다. 엑셀러레이터 리소스의 이름은 “TestAccel”이다.
hAccel = LoadAccelerators(hInstance, “TestAccel”);
while(GetMessage(&msg, NULL, NULL, NULL)) {
// 메시지 루프 안에서 엑셀러레이터 해석 함수를 집어 넣는다.
if(!TranslateAccelerator(hWnd, hAccel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (msg. wParam);
207
Other Resources

String Table




NULL로 끝나는 문자열
Data Segment를 절약하기 위해서 별도의 영역 차지
다국적 프로그램의 작성
문자열은 핸들러를 사용하지 않는다.
 바로 버퍼로 이동
 int LoadString( HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer,
int nBufferMax );

VersionInfo



모듈의 버전 정보
설치 프로그램에서 버전 정보를 비교
Resource Viewer를 사용하여 편집
208
8. Printing
Introduction

프린트 출력과 화면 출력


공통점 : GDI를 이용
차이점 :
 프린터 출력은 제어코드가 필요
 화면 출력은 GetDC, BeginPaint를 이용해서 DC 획득
 프린터 출력은 CreateDC를 이용해서 DC 획득
210
Printing Step

프린터에 대한 DC를 얻는다.
–

CreateDC API를 이용해서 현재 선택된 프린터에 대한 DC
획득
DC에 GDI를 이용해서 출력 작업 수행
–
–
출력은 바로 종이로 나가는 것이 아니고, 프린터 매니저를
통해서 나간다.
종이와 같은 한정된 영역에 나가기 때문에, 새종이에 대한
출력의 시작과 끝을 알리는 코드 필요
211
관련된 API
StartDoc
프린터 매니저에게 프린트 작업이 시작되었음을 알림, 프린터 출력을
파일로 보낼 수도 있음
StartPage
새로운 페이지의 출력이 시작되었음을 알림
EndPage
한 페이지의 출력이 끝났음을 알림
EndDoc
프린트 작업이 정상적으로 끝났음을 알림
AbortDoc
현재 프린트 작업을 종료하고, StartDoc 이후의 출력 작업 취소
(예) 프린터 작업을 취소, 에러가 발생할 경우
SetAbortDoc 프린트 도중에 발생하는 에러 처리 함수
ResetDC
프린터 출력 작업중에 종이의 방향이나 용지 설정의 전환
Printer DC를 얻는다.
프린트 작업을 시작(StartDoc API)
for(page = 1; page <= 출력할 페이지 수; page++) {
새 페이지를 연다(StartPage API)
페이지의 내용을 GDI를 이용하여 printer DC에 출력
페이지를 닫는다(EndPage API)
}
프린트 작업을 끝낸다(EndDoc API)
Printer DC를 제거(DeleteDC)
212
Registry and INI file

INI file in Windows 3.X





win.ini, system.ini, powerpnt.ini,….
프로그램에 대한 정보가 산재 => 통합 관리의 어려움
여러 section으로 구성, key와 value로 표시
64KB의 한계
Registry

32MB까지 가능
INI file에 비하여 이진 데이터와 트리 형태의 데이터 저장 가능

regedit(윈도우 95), regedt32(윈도우 NT)로 편집 가능

HKEY_CLASSES_ROOT
OLE 관련 정보, 셀 관련 정보
HKEY_LOCAL_MACHINE
시스템에 설치된 소프트웨어, 메모리, 그 외 하드웨어
HKEY_USERS
사용자 정보
HKEY_CURRENT_USER
현재 사용자의 환경에 관한 정보 저장
HKEY_CURRENT_CONFIG
시스템에 설치된 하드웨어 설정 정보
HKEY_DYN_DATA
시스템 성능에 대한 통계 정보
213
Printer DC의 생성 방법

win.ini를 이용


Registry를 이용


GetProfileString, WriteProfileString API를 이용
NT의 경우, win.ini이 존재하지 않음
프린트 관련 common dialog box를 이용

가장 효율적
214
HDC GetPrinterDC(BOOL bInvokeDlg)
{
HDC hDC;
LPDEVMODE lpDevMode = NULL;
LPDEVNAMES lpDevNames;
LPSTR lpszDriverName;
LPSTR lpszPortName;
PRINTDLG pd;
// pd를 초기화한다.
pd.lStructSize = sizeof(PRINTDLG);
pd.hwndOwner = hWnd;
if(bInvokeDlg)
pd.Flags = PD_RETURNDC;
else
pd.Flags = PD_RETURNDC | PD_RETURNDEFALUT;
if(!PrintDlg(&pd))
// 프린터 작업이 취소되면, NULL을 리턴한다.
return NULL;
// PrintDlg함수에서 프린터 DC를 얻었는지 검사.
hDC = pd.HDC;
else // 아니면, 프린터 DC를 직접 만든다.
{
………………………..
}
if(pd.hDC)
215
// PrintDlg함수에서 프린터 DC를 얻었는지 검사.
if(pd.hDC)
hDC = pd.HDC;
if(pd.hDevNames)
{
GlobalFree(pd.hDevNames);
pd.hDevNames = NULL;
}
if(pd.hDevMode)
{
GlobalFree(pd.hDevNames);
pd.hDevNames = NULL;
}
return hDC;
}
216
Others in Printing

프린트 작업 취소
BOOLAPIENTRY
AbortProc(HDC
hDC, int
iError)이용
사용자가
SetAbortProc
API를
{

프린트 중간에 에러 발생 ex) SP_OUTOFDISK
MSG msg;
// 프린터 취소 함수를 띄우지 않았다면 바로 리턴한다.
if(!bAbortDlgWnd)
return TRUE;
//사용자가 프린트 중단을 하지 않았다면 그 동안 큐에 있는 메시지를 처리
while(!bAbort && PeekMessage(&msg, NULL, NULL, NULL, TRUE)) {
if(!IsDialogMessage(hAbortDlgWnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (!bAbort);
}
217
Creating Printing Cancel
Dialog Box(1)

Print Cancel Dialog Box

Modeless dialog box
Dialog box template
ABORTDLG DIALOG DISCARDABLE 20, 20, 90, 64
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION “Print a File”
BEGIN
DEFPUSHBUTTON “Cancel”, IDCANCEL, 29, 44, 32, 14, WS_GROUP
CTEXT
“Sending”, -1, 0, 8, 90, 8
CTEXT
“text”, IDC_FILENAME, 0, 18, 90, 8
CTEXT
“to print spooler”, -1, 0, 28, 90, 8
END
218
Creating Printing Cancel
Dialog Box(2)
int APIENTRY AbortDlg(HWND hDlg, UINT msg, UINT wParam, LONG lParam)
{
switch(msg)
{
case WM_COMMAND:
return (bAbort = TRUE);
case WM_INITDIALOG:
SetFocus(GetDlgItem(hDlg, IDCANCEL));
SetDlgItemText(hDlg, IDC_FILENAME, szFileName);
return TRUE;
}
return FALSE;
}
Static control의 출력을 변경하기 위해서 SetDlgItemText 함수를 사용
219
Creating Printing Cancel
Dialog Box(3)
HWND hAbortDlgWnd;
………….
/* 프린트 취소 대화상자를 생성한다. */
hAbortDlgWnd = CreateDialog(hInst, “AbortDlg”, hWnd, AbortDlg);
if(!hAbortDlgWnd) {
SetCursor(hSaveCursor);
/* 커서를 원상 복구한다 */
return TRUE;
}
/* 프린트 취소 대화 상자를 보이게 한다. */
ShowWindow(hAbortDlgWnd, SW_NORMAL);
UpdateWindow(hAbortDlgWnd);
………….
220
Printing a Text to Paper(1)

절차







Printer DC를 얻는다(GetPrinterDC 호출)
프린터 작업을 시작한다(StartDoc 호출)
새 페이지를 연다(StartPage 호출)
Printer DC로 텍스트 한줄을 출력한다(TextOut 호출)
페이지를 닫는다(EndPage 호출)
프린트 작업을 끝낸다(EndDoc 호출)
Printer DC를 제거한다(DeleteDC 호출)
221
Printing a Text to Paper(2)
HDC hDC;
DOCINFO DocInfo;
hDC = GetPrinterDC();
if(hDC != NULL)
{
// 프린터 job을 연다
DocInfo.cbSize = sizeof(DOCINFO); // StartDoc을 호출하기 위해 DOCINFO를 초기화
DocInfo.lpszDocName = “Test”;
// 프린터 매니저에 표시되는 출력 문서의 이름
// NULL이면 프린터 출력, 아니면 그 이름의 파일로 출력
DocInfo.lpszOutput = (LPSTR)NULL;
StartDoc(hDC, &DocInfo);
// 한 페이지의 출력을 연다.
StartPage(hDC);
TextOut(hDC, 10, 10, “A Single Line of a Text”, 22);
//페이지의 출력을 닫는다
EndDoc(hDC);
DeleteDc(hDC);
};
222
9. MDI
Introduction

MDI(Multiple Document Interface)

하나의 메인 윈도우에 여러 개의 자식 윈도우를 올려 놓아
사용하는 방법
 ex)윈도우 3.1 Program Manager, MS-Word

SDI(Single Document Interface)

Microsoft에서 SDI를 권장함
 ex)NotePad(메모장), WordPad
224
MDI Program Structure(1)

MDI의 구성




MDI Main(Frame) Window
MDI Client Window
MDI Child Window
윈도우를 정의



WNDCLASS를 채움
RegisterClass를 이용하여 등록
Window Procedure를 만듬
MDI Main Window
MDI Main Window
File Edit … Window
MDI Child #1
MDI Child #2
MDI Child
Window
MDI Child
Window
MDI Client Window
225
MDI Program Structure(2)

Popup Window와 Child Window

Popup Window
 Parent Window가 필요
 Parent Window의 영역 밖으로 나갈 수 있음
 Child Window의 경우는 나갈 수 없음
 CreateWindow로 생성
 부모 윈도우의 핸들을 준다
 윈도우 ID를 주지 않는다. 자식 윈도우의 경우는 윈도우 ID를 준다
 윈도우 스타일을 (WS_POPUP | WS_VISIBLE)을 준다.
자식 윈도우의 경우는 WS_CHILD를 준다
226
MDI Program 작성(1)

윈도우 클래스의 등록


MDI 프레임 윈도우, MDI자식 윈도우 정의
윈도우 클래스의 등록

2개의 윈도우를 등록
WNDCLASS wc;
// MDI 프레임 윈도우 클래스를 등록
wc.style = 0;
wc.lpfnWndProc = MDIFrameWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(MDIFRAME));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
wc.lpszMenuName = “MDIMENU”;
wc.lpszClassName = “MDIFRAME”;
227
MDI Program 작성(2)

윈도우 클래스의 등록(cont’d)
if(RegisterClass(&wc))
{
// MDI 자식 윈도우 클래스를 등록한다
wc.lpfnWndProc = MDIChildWndProc;
wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(MDICHILD));
wc.lpszMenuName = NULL;
wc.cbWndExtra = CBWNDEXTRA;
wc.lpszClassName = “MDIChild”;
if(!RegisterClass(&wc))
return FALSE;
}
else
return FALSE;
 MDI 자식 윈도우와 일반 윈도우의 차이점
 MDI 자식 윈도우는 반드시 Icon을 갖는다
 MDI 자식 윈도우는 윈도우 Extra byte를 할당해야 한다
228
MDI Program 작성(3)

윈도우의 생성


MDI 메인 윈도우의 생성
MDI 자식 윈도우의 생성 - WM_CREATE 처리부
MDI Main Window의 생성
HWND hwndFrame;
hwndFrame = CreateWindow(“MDIFrame”, “MDI Application”, WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN, CW_USEDDEFAULT,
CW_USEDDEFAULT, CW_USEDDEFAULT,
CW_USEDDEFAULT, NULL, NULL, hInst, NULL) ;
if(!hwndFrame)
return FALSE;
ShowWindow(hwndFrame, nCmdShow);
UpdateWindow(hwndFrame);
229
MDI Program 작성(4)

윈도우의 생성(cont’d)
MDI Child Window의 생성 : MDI Frame 윈도우의 프로시져
case : WM_CREATE:
{
CLIENTCREATESTRUCT ccs;
ccs.hWindowMenu = GetSubMenu(GetSubMenu(hWnd), WINDOWMENU);
ccs.idFirstChild = ID_WINDOW_CHILD;
hwndMDIClient = CreateWindow(“MDICLIENT”, NULL, WS_CHILD |
WS_CLIPCHILDREN, 0, 0, 0, 0, hwndFrame,
hInst, (LPSTR)&ccs);
ShowWindow(hwndMDIClient, SW_SHOW);
break;
}
230
MDI Program 작성(5)

메시지 루프의 변경


단축키의 처리(CTRL+F4, CTRL+F6)
TranslateMDISysAccel API를 이용해서 MDI 클라이언트
윈도우가 메시지를 처리할 기회 제공
While(GetMessage(&msg, NULL, NULL, NULL)) {
if(!TranslateMDISysAccel(hwndMDIClient, &msg)) {
TranslateMessage(&msg);
Dispatchmessage(&msg);
}
231
MDI Program 작성(6)

윈도우 프로시져의 작성
MDI Frame 윈도우 프로시져
자신이 처리하지 못하는 메시지는 DefFrameProc 이 처리
MDI Child 윈도우 프로시져
자신이 처리하지 못하는 메시지는 DefMDIChildProc이 처리

MDI 자식 윈도우를 제어하기


MDI Client 윈도우에 메시지를 보내서, MDI Child 윈도우를
제어
MDI 자식 윈도우의 생성
 MDI Client 윈도우에 WM_MDICREATE 메시지를 보냄
232
MDI Program 작성(7)
HWND hwnd;
MDICREATESTRUCT mcs;
mcs.szTitle = szName;
// 생성할 MDI 자식 윈도우의 갭션을 등록한다.
mcs.szClass = “MDIChild”;
// MDI 자식 윈도우의 클래스를 등록한다.
mcs.x = mcs.y = mcs.cx = mcs.cy = CW_USEDEFAULT; // 시작위치, 폭, 높이
mcs.style = 0;
// MDI클라이언트 윈도우에게 자식 윈도우를 생성시킨다.
hwnd = SendMessage(hwndMDIClient, WM_MDICREATE, 0,
(LPARAM)(LPMDICREATESTRUT)&mcs);
ShowWindow(hwnd, SW_SHOW);

MDI 자식 윈도우의 제거

활성화된 MDI 자식 윈도우의 제거
HWND hwndChild;
hwndChild = (HWND)SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0L);
SendMessage(hwndClient, WM_MDIDESTROY, hwndChild, 0L);
233
MDI Program 작성(8)

MDI 자식 윈도우의 활성화와 비활성화
WM_MDINEXT
wParam의 앞 윈도우나 뒤 윈도우를 활성화시킨다.
lParam == TRUE이면, 이전 윈도우를 활성화
lParam == FALSE이면, 앞 윈도우를 활성화
WM_MDIACTIVE
wParam로 지정한 MDI 자식 윈도우를 활성화시킨다.
WM_MDIGETACTIVE
현재 활성화된 MDI자식 윈도우에 대한 포인터를 얻는다. lParam으로
BOOL 타입의 포인터를 지정해서 최대화 여부 지정
WM_MDIMAXIMIZE
wParam으로 지정한 MDI 자식 윈도우를 최대화 시킨다.
WM_MDIMINIMIZE
wParam으로 지정한 MDI 자식 윈도우를 최소화 시킨다.
234
MDI Program 작성(9)

자식 윈도우의 정렬
WM_MDICASCADE
MDI 자식 윈도우들을 계단식으로 배열한다
WM_MDITITLE
MDI 자식 윈도우들을 바둑판식으로 배열한다.
wParam에 MDITITLE_HORIZONTAL을 넣으면, 수평으로 배열
wParam에 MDITITLE_VERTICAL을 넣으면, 수직으로 배열
WM_MDIICONARRAGNE
아이콘화된 자식 윈도우를 정렬한다.
창
바둑판 배열
계단 배열
아이콘 정렬
1. Test.gif
2. 한.gif
<창 메뉴의 전형적인 구성>
235
MDI 자식 윈도우의 데이터
설정하기(1)
char KeyIn = ‘A’;
LONG APIENTRY MDIChildWndProc
(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CHAR:
{
ch = wParam; // ch에 키값을 저장
InvalidateRect(hWnd, NULL, TRUE); //WM_PAINT 발생
break;
}
case WM_PAINT:
{
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd, &ps);
lpChar[0] = ch; lpChar[1] = NULL;
TextOut(hDC, 10, 10, lpChar, 1); // 출력...
EndPaint(hWnd, &ps);
break;
}
default:
return DefMDIChildProc(hWnd, msg, wParam, lParam);
}
236
return 0;}
MDI 자식 윈도우의 데이터
설정하기(2)

WNDCLASS의 Extra byte이용하기


cbWndExtra 필드에 양수값을 할당
: 각 윈도우마다 cbWndExtra의 공간만큼 할당
인덱스를 이용해 데이터에 접근
 SetWindowLong, GetWindowLong
LONG APIENTRY MDIChildWndProc
(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CREATE: {
HGLOBAL hGlobal;
LPSTR lpChar;
hGlobal = GlobalAlloc(GMEM_MOVALBE, 1); // 1바이트 할당
if(hGlobal == NULL) return -1L;
lpChar = (LPSTR)GlobalLock(hGlobal);
lpChar[0] = 0;
237
GlobalUnlock(hGlobal);
SetWindowLong(hWnd, 0, hGlobal);
break;
}
case WM_DESTROY: {
// 종료될 때 할당했던 메모리를 제거한다.
GlobalFree(GetWindowLong(hWnd, 0);
break;
}
case WM_CHAR: {
LPSTR lpChar;
HGLOBAL hGlobal;
hGlobal = (HGLOBAL) GetWindowLong(hWnd, 0);
lpChar = (LPSTR)GlobalLock(hGlobal);
lpChar[0] = (char)wParam;
GlobalUnlock(hGlobal);
InvalidateRect(hWnd, NULL, TRUE);
break;
}
238
case WM_PAINT: {
HDC hDC;
PAINTSTRUCT ps;
char lpStr[2];
LPSTR lpChar;
HGLOBAL hGlobal;
hGlobal = (HGLOBAL)GetWindowLong(hWnd, 0);
lpChar = GlobalLock(hGlobal);
hDC = BeginPaint(hWnd, &ps);
lpStr[0] = lpChar[0];
lpStr[1] = NULL;
TextOut(hDC, 10, 10, lpStr, 1);
EndPaint(hWnd, &ps);
GlobalUnlock(hGlobal);
break;
}
default:
return DefMDIChildProc(hWnd, msg, wParam, lParam);
}
return 0L;
}
239
MDI 자식 윈도우의 데이터
설정하기(3)

GetWindowLong의 기타 용도


윈도우 관련 정보를 접근할 때 사용
두 번째 인자
GWL_EXSTYLE
이 윈도우의 확장 스타일을 얻어 온다
GWL_STYLE
이 윈도우의 스타일을 얻어 온다
이 윈도우의 프로시져 주소를 얻어 온다. CallWindowProc함수를
이용해 호출할 수 있다.
이 윈도우가 속한 인스턴스 핸들을 얻어 온다
GWL_WNDPROC
GWL_HINSTANCE
GWL_HWNDPARENT 이 윈도우가 자식 윈도우라면, 부모 윈도우 핸들을 얻어 온다.
GWL_ID
윈도우 ID를 얻어 온다. 자식 윈도우일 경우에만 의미가 있다.
지정한 윈도우가 대화 상자일 때만, 의미가 있다. 대화상자의
DWL_DLGPROC
프로시저의 주소를 돌려준다.
240
MDI 자식 윈도우의 데이터
설정하기(4)

윈도우 프로퍼티 이용하기




필요한 영역을 확보하고, 문자열로 접근
 장점 : Extra Byte에 비하여 사용이 쉽다.
 단점 : Extra Byte에 비하여 속도가 느리다.
HANDLE GetProp( HWND hWnd, LPCTSTR lpString );
BOOL SetProp( HWND hWnd, LPCTSTR lpString, HANDLE hData
);
HANDLE RemoveProp( HWND hWnd, LPCTSTR lpString );
241
9.DLL
DLL의 등장 배경

고전적인 프로그래밍 모델


소스 코드를 작성하고 컴파일해서 실행 파일 생성
하드웨어 인프라의 발전과 GUI로의 전환

요구되는 내장 기능이 늘어남
 추가되는 코드의 양도 늘어남
 실행 파일의 크기가 기하급수적으로 증가
 메모리 요구량이 증가
 로딩 속도 및 수행 속도 저하
 프로그램간에 코드와 리소스를 중복해서 가지고 있기 때문에
리소스 사용이 비효율적

해결 방안


프로그램의 모듈화
중복되는 코드와 리소스 공유
243
DLL이란? (1)

DLL(Dynamic Link Library)



1983년 MS사의 Steve Wood가 고안
실행중 함수 호출시에 메모리로 load되어 실행
DLL vs. SLL

SLL
 컴파일 결과 생성된 오브젝트 파일과 소스에서 사용한
라이브러리가 합쳐져서 실행 파일을 구성한다.
 즉, 라이브러리 코드 자체를 복사

DLL
 링크시(실행파일 생성시)에는 라이브러리 이름과 사용한 함수의
위치만이 복사된다.
 실행중에 함수를 실제로 사용할 시점이 되면 라이브러리를
로드하여 함수를 실행시킨다.
244
DLL이란? (2)

a1.c
DLL과 SLL(Static Link Library)의 비교
strcpy(...); SLL호출
a1.c
compile
실행 파일
strcpy(...); DLL호출
compile
a1.obj
a1.obj
link
link
strcpy
SLL에서 해당 코드 자체가 copy된다.
실행 파일
strcpy
DLL에서 해당 코드 이름과 위치가
기록된다.
245
DLL이란? (3)

DLL을 로드한 응용 프로그램의 메모리맵
프로세스A
프로세스B
프로그램A코드
프로그램A코드
프로그램B코드
프로그램B코드
DLL 코드
DLL 코드
공유 데이터
DLL 코드
공유 데이터
인스턴스데이터A
공유 데이터
인스턴스데이터B
인스턴스데이터A
인스턴스데이터B
246
DLL의 장점 (1)

(1) 메모리의 효율적인 사용

코드 공유
 윈도우와 같은 멀티태스킹 환경에서는 동시에 여러 개의 프로그램이
실행되며 같은 코드를 사용하는 경우가 많다.
 CreateWindow, GetDC 같은 윈도우 API들은 모든 윈도우 응용
프로그램에서 사용
 SSL을 이용한다면 각 프로그램마다 윈도우 API들이 중복되어
들어가게 되므로 메모리 낭비
 DLL을 사용하면 실행 파일 안에는 함수의 위치만 기록하고 코드를
공유하므로 메모리를 획기적으로 절감

리소스 공유
 자주 사용하는 비트맵 등에 이용 가능

Reference count 관리
247
DLL의 장점 (2)
 Reference count : dll을 참조하는 프로그램의 개수
 Reference count가 0이 되면 메모리에서 제거



(2) 모듈화 및 재사용성 증가
(3) 플랫폼 버전 차이에 따른 문제를 해결
(4) 다목적용 프로그램의 작성



(5) 혼합 프로그래밍이 가능하다.


사용자의 요구에 맞게 dll만 바꾸면 됨
다국적용 프로그램의 작성
ex) UI는 Visual Basic으로 작성하고 기능은 C++로 작성
(6) 기타

Device driver, Custom control을 DLL로 작성
 VBX(Visual Basic eXtension), OCX(OLE Control eXtension),
ActiveX
248
DLL 개요(1)



SDK API들이 DLL로 제공
VC++ 4.0부터 C Libarary도 가능
기본적인 확장자는 dll
 이 경우 자동으로 로드할 수도 있고 LoadLibrary를 이용해
명시적으로 로드 가능

확장자가 dll이 아니어도 상관없다
 확장자가 dll이 아닌 경우는 모든 일을 Programmer가 수행
 LoadLibrary, GetProcAddress, FreeLibrary API 이용
일종의 dll
HANDLE hLibrary; HMENU hMenu;
hLibrary = LoadLibrary(“MENULIB.EXE”);
hMenu = LoadMenu(hLibrary, “MainMenu”);
………
FreeLibrary(hLibrary);
249
DLL 개요 (2)

DLL을 찾는 순서
실행 파일이 있는 디렉토리
 현재 디렉토리
 윈95: 시스템 디렉토리, NT: SYSTEM32 디렉토리
: GetSystemDirectory API
 윈도우 디렉토리 : GetWindowsDirectory API
 PATH 환경변수에 기록된 디렉토리

250
Win32 DLL에서 달라진 점(1)

(1) DllMain


Dll의 시작과 끝은 DllMain에서 처리
Dll이 로드되거나 제거될 때 DllMain 호출
int WINAPI DllMain(HANDLE hInst, ULONG umessage, LPVOID lpReserved);
Dll을 사용하려는 프로그램에 관한 정보를 OS에게 알려 주는 일종의 메시지
DLL_PROCESS_ATTACH
Dll을 사용하는 프로세스가 생길 때 호출
DLL_PROCESS_DETACH
Dll을 사용하는 프로세스가 사라질 때 호출
DLL_THREAD_DETACH
Dll을 사용하는프로세스에서 쓰레드가 생성될 떄 호출
DLL_ THREAD _DETACH
Dll을 사용하는 프로세스에서 쓰레드가 사라질 때 호출
251
Win32 DLL에서 달라진 점(2)

(2) DLL의 데이터 세그먼트



Dll을 사용하는 프로세스 당 데이터 세그먼트 할당
DLL 코드만 공유
쓰레드간에는 공유 문제 존속
 프로세스당 데이터 세그먼트를 할당하기 때문애 멀티 쓰레드
환경에서는 쓰레드간에 충돌 가능
 TLS(Thread Local Storage) 사용-> thread-safe dll

Threads and Multi-Threads

Threads : CPU를 할당하는 최소 단위
 하나의 프로세스는 하나이상의 쓰레드로 구성

Multi-Threads : 2개의 이상의 쓰레드가 작동
252
DLL 만들기(1)

작성


컴파일


일반 프로그램과 같이 헤더, 소스, rc, 모듈 정의 파일로 구성
Dynamic library(.dll)와 import library(.lib) 생성
DLL Linking

Implicit linking
 프로그램이 시작하면서 사용하는 dll을 바로 로드
 Import library 지정
 라이브러리 함수들의 위치 저장

Explicit linking
 실행 중에 API를 호출하여 명시적으로 dll을 로드
 Import library가 필요없다.
253
DLL 만들기(1)

(1) Dll의 헤더 파일


Dll에서 제공하는 함수들에 대한 정보
Dll을 사용하는 프로그램에서 포함시켜야 됨
#ifndef __DLL32_H__
#define __DLL32_H__
#ifdef __cplusplus__
extern “C” {
#endif
int APIENTRY DLL32TestFunc(HWND hWnd, LPCSTR lpStr);
#ifdef __cplusplus__
}
#endif
#endif
// __DLL32_H__
254
DLL 만들기(2)

DLL 소스 파일


DllMain 필요
Dll을 구성하는 함수 정의
 라이브러리 함수에는 반드시 APIENTRY를 붙여야 한다.
int APIENTRY DLL32TestFunc(HWND hWnd, LPCSTR lpStr)
{
라이브러리 함수들 앞에는 꼭 붙어야 됨
// ………...

Import Library를 생성

모듈 정의 파일 이용
 모듈 정의 파일의 EXPORTS문에 라이브러리 함수를 나열

함수 정의시에 __decspec(dllexport) 사용
255
DLL 만들기(3)
Library DLL32
CODE EXECUTE READ
DATA READ WRITE
EXPORTS
DLL32TestFunc @1
__declspec(dllexport) int APIENTRY
DLL32TestFunc(HWND hWnd, LPCSTR lpStr)
{
// …………………...
}
256
실행파일에서 DLL호출하기(1)

2가지 방법 존재
Import Library 사용
LoadLibrary 등의 API 사용
메모리 로드 시점
프로그램이 실행될 때
LoadLibrary를 호출했을 때
메모리 해제 시점
프로그램이 종료될 때
FreeLibrary를 호출했을 때
장점
단점
사용이 간편
불필요하게 DLL이 메모리에
남아 있는 경우가 발생,
DLL 이 없는 경우 프로그램이
실행 안 됨
DLL 로드 시점을 정할 수 있다.
해당 DLL이 없을 경우에
대처 가능
사용이 복잡
257
실행파일에서 DLL호출하기(2)

(1) Import Library 사용

Dll의 import library를 project에 추가
 [Project] ->[Settings]->[Link]에서 [Object/Library modules]에
추가


추가 후에는 일반 API처럼 사용
(2) LoadLibrary 등의 API 사용

절차
 LoadLibrary 함수로 dll을 load한다
GetProcAddress로 원하는 함수의 주소를 얻어낸다
 앞에서 얻어낸 함수 주소로 호출한다
 FreeLibrary로 dll을 메모리에서 제거한다
258
실행파일에서 DLL호출하기(3)
 Import Library 사용
DLL32TestFunc(hWnd, “테스트 중입니다.”);
 LoadLibrary 등의 API 사용
typedef int (APIENTRY *FPDLL32TestFunc) (HWND, LPSTR);
HANDLE hLibrary;
FP32DLLTestFunc lpfnDLL32TestFunc;
hLibrary = LoadLibrary(“dll32.dll”);
if(hLibrary)
{
lpfnDLL32TestFunc = GetProcAddress(hLibrary, “DLL32TestFunc”);
if(lpfnDLL32TestFunc)
lpfnDLL32TestFunc(hWnd, “Testing in Main Process”);
}
FreeLibrary(hLibrary);
259
실습 (1)
(1)
Implicit linking
Dll
작성
Dll을
생성하고 DllMain이 호출되는 각 경우에 메시지 박스 추가
간단한
메시지 박스를 출력하는 dll fuction 정의
정수를
parameter로 받아서 factorial을 계산하는 dll fuction 정의
def
Dll을
파일을 작성한 후 컴파일해서 dll과 lib 생성
호출할 프로그램 작성
Win32
프로젝트를 생성하고 library import
프로그램
내에서 두가지 dll 함수 사용
260
실습 (2)
(2)
Explicit linking
Dll
작성
이전에
Dll을
작성한 dll을 그대로 사용
호출할 프로그램 작성
Win32
프로젝트를 생성
Library에서
두가지
import할 함수의 type 설정
종류의 함수를 실제로 호출
261
실습 (3)
(3)
Resource dll
Dll
작성
MFC
dll with static linked library
사용자의
아이디와 암호 입력을 받아들이는 login dialog 생성
다이얼로그
클래스 정의
Login
dialog를 띄우는 dll 함수 정의
def에
export할 함수 추가
컴파일해서
Dll을
lib과 dll 생성
호출할 프로그램 작성
GetProcAddress를 이용하여 로그온 다이얼로그를
띄우고 아이디와 암호를 메시지 박스로 보여주기
LoadLibrary,
262
10.Memory, File I/O, Clipboard
Win32 메모리 구조 (1)

Win32 메모리 모델

메모리 관리의 단순화
 small, large, huge 모델이 사라짐 (near, far 메모리 구별도 없다)

디스크의 일부를 메모리로 사용
 메모리의 총량
 물리적인 메모리 + 하드 디스크의 paging file
264
Win32 메모리 구조 (2)

Virtual Memory
Physical
Logical
Memory with
infinite capacity
265
Win32 메모리 구조 (3)

Virtual Memory


메모리에 프로그램이 적재될 때 반드시
연속적으로 적재될 필요는 없다
가상 주소 공간과 실 주소 공간의 분리
 가상 주소 공간 : 현재 진행중인 프로세스가
생성하는 주소의 집합
 실 주소 공간 : 주 기억 장치에서 사용가능한 주소

사용자에게는 실제 메모리의 특성을 감춘다.
 사용자는 컴퓨터가 2n byte의 메모리를 가지고 있는
것으로 생각한다.
 가상 메모리의 일부만이 실제 메모리에 할당된다.
266
267
Win32 메모리 구조 (5)

Win32 메모리 모델

각 프로세스의 주소공간은 독립적
 프로세스 생성시마다 4GB의 주소공간을 생성
 가상적인 주소 공간
 물리적인 메모리와 연결될 수 있는 메모리 번지
 프로세스가 사용하는 주소는 메모리의 실제 물리적 위치를
나타내지 않음
 프로세스간에 영향을 끼치지 않는다

Virtual Address Translation

Page Table
 물리적인 메모리와 논리적인 주소 공간을 대응
268
Win32 메모리 구조 (6)

Virtual Address Translation
269
Memory Allocation

Win32 API : 전역할당과 지역할당 동일
 Win16
 지역할당 - 프로세스의 주소 공간 안에
 전역할당 - 프로세스의 주소 공안 외부에
 Win32 : 두 종류의 메모리를 모두 프로세스용 주소 공간에 할당

메모리 할당(Handle)
 메모리 할당시 실제 시작 주소 대신에 handle을 리턴
 메모리 관리를 OS가 처리
 Lock을 걸면, 핸들대신에 주소가 리턴
ex) hMem=GlobalAlloc(..);
hMem 은 핸들 테이블에서 인덱스를 가리킨다.

메모리 관리가 필요한 이유
 프로그램은 최상의 속도로 실행되어야 한다.
 저장 공간의 차별화 (램, 디스크..)

메모리 관리 방법
 가상 메모리 관리자 : 프로그램이 큰 가상 메모리 블록을 예약한 후 그 예약된
가상 메모리 블록을 나중에 할당
 지역 힙 관리자 : 프로그램이 새 힙 관리자로 복수의 서로 다른 힙을 만듬
270
Memory Type

전역 메모리와 지역 메모리


Win32에서는 전역 힙과 지역 힙을 구분하지 않는다.
디스크의 용량의 일부를 메모리로 간주




제한된 물리적 메모리 + 페이징 파일
실제 메모리= RAM + SWAP file
4KB 단위의 페이지 단위로 관리
할당받는 순서
 Free Page --> Reserved page --> Committed page

Page Table : 캐쉬 메모리
 보통은 시스템에서 관리
 프로그램 실행시 코드 이동을 결정
271
Memory Type

가상 메모리 관리자
 프로그램은 실제 메모리를 다루지 않음
 각 프로세스에게 개별적인 주소 공간을 제공
 각 프로세스는 0x00000000에서 0xffffffff 범위의 메모리가 있는
것으로 인식
 쓰레드는 해당 프로세스에 속한 메모리만 access 가능

힙(Heap)


프로그램에서 힙을 생성하면 0x7fffffff부터 시작하는 힙을
키움
개별 힙의 메모리는 그 힙을 만든 프로세스에서만 사용
 DLL에서 힙을 생성시
272
Heap Memory Functions (1)

표준 메모리 함수



malloc, calloc, realloc
ex) char *data = malloc(512); // calloc(512) // realloc(512)
윈도우 메모리 함수

HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes);
 The GlobalAlloc function allocates the specified number of
bytes from the heap
GMEM_FIXED
고정된 형태로 메모리 설정
GMEM_MOVEABLE
메모리가 이동이 된다
GPTR
FIXED && ZEROINIT
GHND
MOVEABLE && ZEROINIT
GMEM_ZEROINIT
모두 0으로 초기화
GMEM_SHARE
메모리를 공유
273
Heap Memory Functions (2)

GlobalLock(할당한 메모리 핸들)
 The GlobalLock function locks a global memory object and
returns a pointer to the first byte of the object's memory block
LPSTR datapoint;
LPSTR datapoint2;
HANDLE hdata;
hdata = GlobalAlloc(GHND,512);
datapoint = (LPSTR)GlobalLock(hdata);
// 데이터 사용
GlobalUnlock(hdata);
datapoint2 = (LPSTR)GlobalLock(hdata);
// 데이터 사용
274
Heap Memory Functions (3)

HGLOBAL GlobalFree(메모리 핸들);
 The GlobalFree function frees the specified global memory
object and invalidates its handle

HGLOBAL GlobalDiscard(메모리 핸들);
 Although GlobalDiscard discards the object's memory block,
the handle to the object remains valid.
 The process can subsequently pass the handle to the
GlobalReAlloc function to allocate another global memory
block identified by the same handle

HGLOBAL GlobalReAlloc(HGLOBAL hMem, SIZE_T
dwBytes, UINT uFlags);
 The GlobalReAlloc function changes the size or attributes of a
specified global memory object. The size can increase or
decrease.
 ex) hdata = GlobalRealloc(hdata, GHND, 1024);
275
Heap Memory Functions (4)

VOID GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);
ex) MEMORYSTATUS ms;
GlobalMemoryStatus(&ms);
if (ms.dwAvailVirtual < msize)
{ // 메모리 부족 }
else { // 메모리 할당 }
276
Virtual Memory (1)

Virtual Memory Functions



Win32 API provides a set of virtual memory functions
That enable a process to manipulate or determine the status
of pages in its virtual address space
이점

메모리를 예약 상태로 할당할 수 있다.
 물리적인 메모리를 소비하지 않으면서, 주소 공간만 미리 할당
 필요할 경우에 확정해서 사용


메모리의 액세스 권한을 지정
LPVOID VirtualAlloc(LPVOID lpAddress, DWORD
dwSize, DWORD flAllocationType, DWORD flProtect)


The VirtualAlloc function reserves or commits a region of
pages in the virtual address space of the calling process
lpAddress : 메모리 시작 번지 , 처음 시작시에는 항상 NULL
277
Virtual Memory (2)

flAllocation Type
 MEM_COMMIT – 지정한 페이지 영역에 대해 물리적 기억 장치
할당 (메모리나 디스크에 있는 페이징 파일)
 MEM_RESERVE - 물리적 기억 장치를 할당하지 않고
프로세스의 가상 주소 공간의 범위를 예약
 MEM_TOP_DOWN - 사용할 수 있는 최상위 주소에서
메모리를 할당

flProtect
PAGE_READONLY
일기 전용
PAGE_READWRITE
읽고 쓰기
PAGE_EXCUTE
실행 가능한 데이터
PAGE_EXCUTE_READ
실행 가능하며 읽기
PAGE_EXCUTE_READWRITE
실행 가능하며 읽고 쓰기
278
Virtual Memory (3)

BOOL VirtualFree(LPVOID lpAddress, DWORD dwSize,
DWORD dwFreeType);
 MEM_DECOMMIT : 할당된 페이지를 할당 해제한다.
 MEM_RELEASE : 예약된 페이지를 예약 해제한다.
279
Virtual Memory (4)

예약과 할당

가상메모리는 “Page” 단위로 구성
 Intel : 4KB

가상 메모리를 구성하는 각 페이지의 상태
 Free : 사용되지 않는 자유 영역
 Reserved : 장래 사용을 위해 예약만 되어 있는 페이지
 Commit : 물리적 메모리가 할당되어 있는 상태, 바로 사용 가능

할당 단위


64KB 단위로 할당
보호 속성

BOOL VirtualProtect(LPVOID lpAddress, DWORD dwSize,
DWORD flNewProtect, PDWORD lpflOldProtect);
 The VirtualProtect function changes the access protection on a region
of committed pages in the virtual address space of the calling process
280
Virtual Memory (5)

메모리 잠금

속도가 중요한 프로그램일 경우
 특정 데이터가 반드시 RAM에만 존재하게 할 수 있다.
 BOOL VirtualLock(LPVOID lpAddress, DWORD dwSize);
 The VirtualLock function locks the specified region of the
process's virtual address space into physical memory, ensuring
that subsequent access to the region will not incur a page fault
 BOOL VirualUnlock(LPVOID lpAddress, DWORD dwSize);
281
Heap (1)

정의 및 장점


가상 메모리 공간상의 예약된 주소 공간
프로세스 생성시
 1MByte의 디폴트 힙 생성
 단순히 예약

작은 메모리 블록을 할당하는데 사용
 요구한 만큼만 할당, 경제적이다.


Win32에서는 힙의 구분이 없고, 지역 힙만이 존재
필요에 따라 다수 개의 힙을 생성할 수 있다.
282
Heap (2)

할당

HANDLE GetProcessHeap(VOID)
 The GetProcessHeap function obtains a handle to the heap of
the calling process
 This handle can then be used in subsequent calls to the
HeapAlloc, HeapReAlloc, HeapFree, and HeapSize functions



LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags,
DWORD dwBytes);
BOOL HeapFree(HANDLE hHeap, DWORD dwFlags,
LPVOID lpMem);
LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags,
LPVOID lpMem, DWORD dwBytes);
 The HeapReAlloc function reallocates a block of memory from
a heap
 This function enables you to resize a memory block and
change other memory block properties
283
Heap (3)

새로운 힙 생성
 HANDLE HeapCreate(DWORD flOption, DWORD dwInitalSize,
DWORD dwMaximumSize);
 The HeapCreate function creates a heap object that can be used
by the calling process
 The function reserves space in the virtual address space of the
process and allocates physical storage for a specified initial
portion of this block
 BOOL HeapDestroy(HANDLE hHeap);
 The HeapDestroy function destroys the specified heap object
 HeapDestroy decommits and releases all the pages of a private
heap object, and it invalidates the handle to the heap
284
File I/O (1)

파일을 열거나 생성

HANDLE CreateFile(LPSTR lpFileName, DWORD
dwDesiredAccess, DWODD dwShardMode,
LPSECURITYATTRIBUTS lpSecurityAttributes, DWORD
dwCreationDistribution, DWORD dwFlagAndAttributes,
HANDLE hTempleteFile);
 The CreateFile function creates or opens the following
objects and returns a handle that can be used to access
the object
 lpfileName : 파일명
 dwDesiredAccess
 읽고 쓰기 모드 (GENERIC_READ, GENERIC_WRITE)
 dwCreationDistribution
 Specifies which action to take on files that exist
 CREATE_NEW, CREATE_ALLWAYS, OPEN_EXISTING,
OPEN_ALWAYS
285
File I/O (2)


ex) HANDLE hFile = CreateFile("test.c", GENERIC_READ |
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, 0)
파일 읽기와 쓰기


BOOL WriteFile( 파일 핸들, 기록할 데이터, 바이트 수 , 실제로
쓰여진 바이트, I/O overlapped 구조체)
BOOL ReadFile( 파일 핸들, 기록할 데이터, 바이트 수, 실제 읽혀진
바이트, I/O overlapped 구조체)
 I/0 overlapped 구조체 : 디바이스 파이프 통로, 일반 파일에서는 NULL
286
File I/O (3)

파일 닫기와 기타함수

CloseHandle(hfile)
MoveFile
특정 파일을 다른 파일 이름으로 변경, 이동
CopyFile
특정 파일을 새로운 파일로 복사
CreatDirectory
디렉토리를 만듬
DeleteFile
특정 파일을 지움
GetFileSize
파일의 크기를 얻음
FindFirstFile
특정 파일을 찾음
FindNextFile
FindFirstFile에 의해서 찾은 다음에 특정 파일 찾음
287
Clipboard (1)

클립보드



클립보드 지원 (Edit 컨트롤)




프로그램간에 또는 프로그램 내부적으로 교환할 데이터를
잠시 저장해 두는 곳
시스템이 관리, 시스템 전체를 통틀어 하나밖에 없다.
WM_CUT
WM_COPY
WM_PASTE
클립보드에 들어갈 수 있는 데이터

텍스트, 비트맵, RTF, 메타파일
288
Clipboard (2)

Text

복사하기
 메모리 할당
 클립보드를 연다
 BOOL OpenClipboard(HWND hWndNewOwner);
 클립보드를 연 윈도우 핸들이 인수로 전달
 클립보드를 비운다.
 EmptyClipboard();
 클립보드에 데이터 저장
 HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);
uFormat
CF_BITMAP
CF_TEXT
CF_WAVE
설명
비트맵
널 종료 문자열
오디오 데이터
 클립보드를 닫는다.
 CloseClipboard();
289
Clipboard (3)

붙여넣기
 클립보드에 원하는 포맷의 데이터가 있는지 확인
 BOOL IsClipboardFormatAvailable(UINT format);
 클립보드를 연다.
 보관된 데이터의 핸들을 얻어온다.
 HANDLE GetClipboardData(UINT uFormat);
 The GetClipboardData function retrieves data from the clipboard
in a specified format
 The clipboard must have been opened previously
 클립보드를 닫는다.
290
Clipboard (4)

클립보드 조작


OpenClipBoard(), CloseClipBoard();
BOOL IsClipboardFormatAvailable(UINT format)
ex)
BOOL check;
OpenClipBoard();
if(ISClipBoardFormatAvailable(CF_TEXT))
{ //클립보드에서 데이터를 얻는다 }
CloseClipBoard();

EmptyClipBoard(); // 클립보드의 데이터 삭제
291
Clipboard (5)

클립보드에서 데이터 얻기와 데이터 쓰기

GetClipboardData();
ex) 클립보드의 내용을 사용
HANDLE hClip; LPSTR pClip;
hClip= GetClipboardData(CF_TEXT);
pClip= GlobalLock(hClip);
// Pclip 사용
ex) 클립보드의 내용을 자신의 프로그램에 복사
OpenClipboard(hwnd);
hClip=GetClipboardData(CF_TEXT);
if(!hClip)
{
CloseClipboard(); return 0; }
szBuf = GlobalReAlloc(szBuf, GlobalSize(hClip),GMEM_MOVEABLE);
pBuf = (LPSTR)GlobalLock(szBuf);
pClip = GlobalLock(hClip);
// 복사
}
292
Clipboard (6)

SetClipboardData(포맷, 메모리 핸들);
 The SetClipboardData function places data on the clipboard in a specified
clipboard format
 ex) 데이터 수정 후 클립보드에 설정
SetClipBoardData(CF_TEXT, szBuf);
293
실습

CreateDirectory
 다이얼로그를 생성하여 사용자가 입력한 경로에 디렉토리 생성

DeleteAllFiles
 사용자가 입력한 디렉토리 아래 있는 모든 파일을 삭제

DeleteDirectory
 사용자가 입력한 디렉토리 안에 있는 파일을 다 삭제하고 디렉토리까지 삭제

파일 읽어서 보여주기
 다이얼로그를 띄우면 사용자가 파일을 선택할 수 있도록 파일 열기 다이얼로그를
띄우고, 사용자가 선택한 파일을 읽어들여서 화면에 출력

파일 찾기
 사용자가 디렉토리와 키워드를 입력하면 지정한 디렉토리 아래서 찾기
 파일 제목이나 내용으로 선택해서 검색 가능
 찾은 개수를 메시지 박스로 출력
294
11. Process & Thread
Introduction (1)

Process




정의 : 실행중인 프로그램
Code region + Data Region +
Running Context
GUI Process와 Console Process의
2종류가 존재
프로세스마다 주소 공간을 따로 가짐
Process Control Block (PCB)
296
Introduction (2)

Thread



CPU 할당의 기본 단위, 즉 실행 단위
자신만의 PC(program counter), register, stack을 가짐
같은 프로세스에 속할 경우 같은 주소 공간 사용
 같은 프로세스에 속한 다른 쓰레드와 code, data, system
resource 공유


Primary thread : WinMain의 실행을 담당하고 추가적인
작업을 위한 쓰레드를 생성
Multi-threading : 여러 개의 thread가 존재
297
Introduction (3)
Single
and Multithreaded Processes
298
Introduction (4)
주소공간
 Win32에서의 주소 공간
Win32
응용 프로그램
Win32
응용 프로그램
프로세스 시작
16 bit
응용프로그램
프로세스 시작
Primary thread 하나만 동작,
실행 경로가 단일하다
프로세스 끝
16 bit
응용프로그램
여러 쓰레드가 존재하기 때문에, 쓰레드 간의
동기화가 필요하다
프로세스 끝
 단일 쓰레드와 멀티 쓰레드의 비교
299
Introduction (5)

Benefits

Responsiveness
 프로세스를 쓰는 경우 프로세스가 blocking되면 다른 작업이
불가능하지만, thread를 쓰면 한 thread가 blocking되어도 다른
thread는 작업을 계속할 수 있다.

Resource Sharing
 부모 프로세스의 자원 공유 가능

Economy
 프로세스간에 작업을 전환할 때 필요한 context switching
overhead가 없다.
300
Introduction (6)

쓰레드를 사용하는 것이 유리한 경우

일을 효율적으로 분담하려는 경우
 여러 개의 일을 동시에 진행할 경우
 MDI Child 윈도우를 쓰레드로 작성

Background processing을 하는 경우
 우선 순위에 따라 일을 처리할 경우
 UI관련(마우스, 키보드)한 경우 높은 우선 순위 부여
 계산이나 프린팅 작업의 경우 낮은 우선 순위 부여

Multi-client를 지원하는 서버를 작성하는 경우
 네트워크 상에서 동작하는 서버 프로그램
 쓰레드 간의 동기화 작업
301
Introduction (7)
요구 대기 쓰레드
 요청마다 별도의 쓰레드를
만들어 처리한다
 루프를 돌며 client로부터의
요청이 오기를 기다린다
 client로부터 요청이
들어오면
처리 쓰레드
 쓰레드를 이용한 client의 요구 처리
302
프로세스 생성

생성함수

UINT WinExec(LPCSTR lpCmdLine, UINT uCmdShow);
 lpCmdLine에서 지정한 프로그램을 실행시킨다
 16bit 윈도우와의 호환을 위해 제공하는 것으로, WIN32
프로그램에서는 CreateProcess API를 사용해야 한다

DWORD LoadModule (LPCSTR lpModuleName, LPVOID
lpParameterBlock);
 LpModuleName에서 지정한 프로그램을 실행시킨다
 16bit 윈도우와의 호환을 위해 제공하는 것으로, WIN32
프로그램에서는 CreateProcess API를 사용해야 한다

BOOL CreateProcess(…)
 WIN32 API
 새로운 프로세스와 primary thread를 생성한다
 생성한 프로세스는 파라미터로 지정한 프로그램을 실행한다
303
CreateProcess(1)

BOOL CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
304
CreateProcess(2)

CreateProcess API의 인자 설명

LPCTSTR lpApplicationName
 실행 파일 이름
 실행 파일을 찾는 경로
 현재 디렉토리CreateProcess를 호출한 프로세스의 현재
디렉토리 윈도우 시스템 디렉토리 윈도우 디렉토리 Path
환경 변수에 들어 있는 디렉토리
 NULL일 경우 2번째 인자에 실행 파일 이름이 명시됨

LPTSTR lpCommandLine
 새로 생성할 프로세스에게 주어질 명령행 인자
 LPCTSTR lpApplicationName == NULL이면 실행 파일 이름이
인자로 들어감

LPSECURITY_ATTRIBUTES lpProcessAttributes
 프로세스의 보안 속성
305
CreateProcess(3)

CreateProcess API의 인자 설명(cont’d)

LPSECURITY_ATTRIBUTES lpThreadAttributes,
 메인 쓰레드의 보안 속성
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength; // 구조체의 크기
LPVOID lpSecurityDescriptor; //소유자,그룹 식별
정보
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES;

BOOL bInheritHandles
 TRUE면 부모 프로세스의 자윈 사용 가능
FALSE면 부모 프로세스의 자윈 사용 불가능
User Object
자원=>
GDI Object
Kernel Object
윈도우 관리와 관련 있는 객체, ex)Window, Menu, Icon
그래픽과 관련이 있는 객체,
ex)Brush, Pen, Palette, Bitmap, Font, DC
메모리 관리와 관련이 있는 객체,
ex) Process, Thread, File, Event
계승가능
306
CreateProcess(4)

CreateProcess API의 인자 설명(cont’d)


DWORD dwCreationFlags
프로세스의 생성 방법, 우선 순위 정보 설정 가능
 CREATE_SUSPEND
 실행 준비를 끝낸 상태에서 중지
 The primary thread of the new process is created in a suspended
state and does not run until the ResumeThread function is called
 CREATE_NEW_CONSOLE
 부모와는 별개로 새로운 콘솔을 가진 child process 생성
 CREATE_NEW_PROCESS_GROUP
 새로운 프로세스 그룹의 root 프로세스를 생성
 DETACHED_PROCESS
 콘솔 프로세스에 적용되며, 새로운 프로세스는 부모의 콘솔에 접근할
수 없다.
 새로운 프로세스는 이후에 AllocConsole 함수로 콘솔을 생성해서
사용해야 한다.
307
CreateProcess(5)
 DEBUG_PROCESS
 해당 사건이 일어나면 부모 프로세스에게 이벤트를 발생시킴
 BOOL WaitForDebugEvent(LPDEBUG_EVENT lpde, DWORD dwTimeout);
EXCEPTION_DEBUG_EVENT
Exception이 발생했을 때
CREATE_THREAD_DEBUG_EVENT 쓰레드가 생성되었을 때
CREATE_PROCESS_DEBUG_EVENT 프로세스가 실행되기 시작했을 때
EXIT_THREAD_DEBUG_EVENT
쓰레드가 끝날 때
EXIT_PROCESS_DEBUG_EVENT
프로세스가 끝날 때
LOAD_DLL_DEBUG_EVENT
프로세스가 DLL을 load할 때
UNLOAD_DLL_DEBUG_EVENT
프로세스가 DLL을 더 이상 사용하지 않을 때
OUTPUT_DEBUG_STRING_EVENT 프로세스가 OutputDebugString을 호출했을 때
PIR_EVENT
프로세스가 시스템 디버깅 에러를 야기했을 때
308
CreateProcess(6)

우선 순위 조정
 REALTIME_PRIORITY_CLASS
 가장 높은 우선순위 부여
 HIGH_PRIORITY_CLASS
 사용자 입력에 즉각 반응하는 프로세스에 할당
ex) Window Task Manager(CTRL+ESC)
 NORMAL_PRIORITY_CLASS
 Foreground로 실행될 경우 background보다 우선순위가 높다
 디폴트 우선순위
 IDLE_PRIORITY_CLASS
 실행중인 프로세스가 없을 경우에 실행되는 프로세스

우선순위를 알려고 할 때, 변경할 때
 DWORD GetPriorityClass(HANDLE hProcess);
 BOOL SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass);
309
CreateProcess(7)

CreateProcess API의 인자 설명(cont’d)

LPVOID lpEnvironment
 새로 생성되는 프로세스의 환경 변수 블록
 NULL이면 부로 프로세스의 환경 변수를 그대로 사용
 이름1=값1\0이름2=값2\0 …….\0 이름N=값N\0
 BOOL SetEnvironmentVariable(LPCTSTR lpName, LPCTSTR lpValue);
 DWORD GetEnvironmentVariable(LPCTSTR lpName, LPTSTR lpBuffer,
DWORD nSize);
 LPVOID GetEnvironmentStrings(VOID)
 The GetEnvironmentStrings function returns a pointer to the environment block
of the calling process
 This should be treated as a read-only block

LPCTSTR lpCurrentDirectory
 새로 생성되는 프로세스의 작업 디렉토리
 NULL이면 부모 프로세스와 같은 작업 디렉토리
310
CreateProcess(8)

CreateProcess API의 인자 설명(cont’d)

LPSTARTUPINFO lpStartupInfo
 윈도우의 좌표나 크기 등의 디폴트 값을 줄 때 사용
 VOID GetStartupInfo(LPSTARTUPINFO lpStartupInfo);
311
CreateProcess(9)
typedef struct _STARTUPINFO
{
DWORD cb; // 이 구조체의 크기
LPSTR lpReserved; // 예약 영역
LPSTR lpDesktop; // 데스크탑의 이름(없을 경우 새로 만듬)
LPSTR lpTitle; // 콘솔 프로세스의 윈도우 캡션
DWORD dwX; // 윈도우의 디폴트 시작 X좌표
DWORD dwY; // 윈도우의 디폴트 시작 Y좌표
DWORD dwXSize; // 윈도우의 디폴트 폭
DWORD dwYSize; // 윈도우의 디폴트 높이
DWORD dwXCountChars; // 콘솔 윈도우의 폭을 글자수로 명시
DWORD dwYCountChars; // 콘솔 윈도우의 높이를 글자수로 명시
DWORD dwFillAttribute; // 콘솔의 문자색과 배경색을 명시
DWORD dwFlags; // 이 구조체의 어느 부분을 프로세스가 사용할 것인지 명세
WORD wShowWindow; // GUI 프로세스의 디폴트 윈도우의 표시 플래그
WORD cbReserved2; // 예약 영역
LPBYTE lpReserved2; // 예약 영역
} STARTUPINFO, *LPSTARTUPINFO;
312
CreateProcess(10)
STARTF_USESIZE
dwXSize, dwYSize를 사용할 것
STARTF_USESHOWWINDOW
dwShowWindow를 사용할 것
STARTF_USEPOSITION
dwX, dwY를 사용할 것
STARTF_USECOUNTCHARS
dwXCountChars, dwYCountChars를 사용할 것
STARTF_USEFILLATTRIBUTE
dwFillAttribute를 사용할 것
STARTF_FORCEONFEEDBACK 프로세스 생성시에 모래시계 커서 사용
STARTF_ FORCEOFFFEEDBACK프로세스 생성시에 모래시계 커서 사용 중지
313
CreateProcess(11)

CreateProcess API의 인자 설명(cont’d)

LPPROCESS_INFORMATION lppiProcInfo
 프로세스의 생성이 성공적으로 끝났을 경우에, OS에서 채워준다
typedef struct _PROCESS_INFORMATION
{
HANDLE hProcess;
HANDLE hThrea;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
 hProcess
 A handle to the newly created process
 The handle is used to specify the process in all functions that perform operations
on the process object.
314
CreateProcess(12)
 hThread
 A handle to the primary thread of the newly created process
 The handle is used to specify the thread in all functions that perform operations on
the thread object.
 dwProcessId
 A global process identifier that can be used to identify a process
 The value is valid from the time the process is created until the time the process is
terminated.
 dwThreadId
 A global thread identifiers that can be used to identify a thread
 The value is valid from the time the thread is created until the time the thread is
terminated
315
프로세스의 종료

종료

VOID ExitProcess(UINT fuExitCode);





프로세스와 연결된 모든 DLL의 DllMain 함수 호출
모든 열려진 핸들을 닫는다.
실행중인 모든 프로세스를 종료
ExitProcess() 아래의 코드는 실행되지 않는다.
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);
 자기 자신이 아닌 다른 프로세스를 종료할 수 있다.
 DLL에게 종료 사실을 알리지 않는다.
 어쩔 수 없는 경우에만 사용
316
프로세스의 핸들 (1)

커널 객체



프로세스와 스레드
프로세스 객체는 만들 수 있는 권리가 필요
Process Specific
 커널 객체를 만든 프로세스만이 자신이 가진 핸들로 해당 객체를
액세스할 수 있다.
 핸들을 다른 프로세스로 전달하는 것은 의미가 없다

다른 프로세스가 이용하기 위해서는
 ID를 가지고 새로운 핸들값을 부여 받아야 한다
 HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL
bInheritHandle, DWORD dwProcessld);
 함수가 성공하면 지정한 프로세스에 대한 핸들을 리턴한다
 이렇게 구한 핸들은 접근 권한을 가지고 있는 한 wait function과 같이 핸들을
가지고 프로세스에 접근하는 모든 함수에 사용할 수 있다
 핸들에 대한 사용이 끝나면 반드시 CloseHandle 함수를 사용하여 닫는다
317
프로세스의 핸들 (2)

ID
 시스템 전역적인 값

핸들과 ID를 구하는 함수
 HANDLE GetCurrentProcess(VOID)
 This function returns a pseudohandle for the current process
 A pseudohandle is a special constant that is interpreted as the
current process handle
 This handle has the maximum possible access to the process
object
 The pseudohandle need not be closed when it is no longer
needed
 HANDLE GetCurrentProcessId(VOID)
 This function retrieves the process identifier of the calling process
318
CreateThread(1)
HANDLE CreateThread
(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
319
CreateThread(2)

CreateThread API의 인자 설명

LPSECURITY_ATTRIBUTES lpThreadAttributes
 보안 속성

DWORD dwStackSize,
 물리적 메모리에 할당할 스택의 크기 지정
 0 이상일 때는 명시한 크기만큼 committed page에 할당
 0일 때는 부모 프로세스와 같은 크기의 스택 할당

LPTHREAD_START_ROUTINE lpStartAddress
 쓰레드의 실행 함수에 대한 포인터
 DWORD WINAPI ThreadFunc(LPVOID lpvThreadParam);

LPVOID lpParameter
 쓰레드 실행 함수의 인자에 대한 포인터
320
CreateThread(3)

CreateThread API의 인자 설명(cont’d)

DWORD dwCreationFlags





0을 주면 생성과 동시에 실행
CREATE_SUSPEND를 주면 중지 상태에서 대기
DWORD ResumeThread(HANDLE hThread);
DWORD SuspendThread(HANDLE hThread)
LPDWORD lpThreadId
 생성된 쓰레드의 ID를 저장
 NULL을 주면 에러 발생

쓰레드의 종료


VOID ExitThread(DWORD fdwExitCode);
BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);
321
CreateThread(4)

Pseudo Handle





오직 자신의 문맥에서만 유효
CloseHandle() 같이 프로세스나 스레드 객체에 영향을 주는 함수의 인자로
사용불가!
HANDLE GetCurrentProcess(VOID)
HANDLE GetCurrentThread(VOID)
진짜 핸들을 얻고자 할 때는 DuplicateHandle API를 이용





This function duplicates an object handle
The duplicate handle refers to the same object as the original handle
Therefore, any changes to the object are reflected through both handles
For example, the current file mark for a file handle is always the same for both
handles
기타 API

DWORD GetCurrentThreadId(VOID)
322
CreateThread(5)
o 진짜 핸들이 필요할 경우
-예
DWORD WINAPI ParentThread(LPVOID
lpvThreadParam)
{
DWORD IDThread;
HANDLE hThreadParent = GetCurrentThread();
CreateThread(NULL, 0, ChildThread,
(LPVOID)hThreadParent,
0, &IDThread);
…..
}
DWORD WINAPI ChildThread(LPVOID
lpvThreadParam)
{
HANDLE hThreadParent =
(HANDLE)lpvThreadParam;
SetThreadPriority(hThreadParent,
THREAD_PRIORITY_NORMAL);
…..
}
- DuplicateHandle 함수를 이용하여 pseudo-to-real
핸들 변환을 해야 함
- BOOL DuplicateHandle(
HANDLE hSourceProcess, // 수도
// 핸들이 한정적으로 의미를 가지는
// 프로세스 핸들.
HANDLE hSource, // 변환 대상이 되는
// 프로세스 혹은 스레드의 수도 핸들.
HANDLE hTargetProcess, // 새로운
// 진짜 핸들이 한정적으로 의미를 갖게
// 될 프로세스의 핸들.
LPHANDLE lphTarget, // 새로운 진짜 핸
// 들이 저장될 위치.
DWORD fdwAccess, // 핸들 액세스
// 방법 지정.
BOOL fInherit, // 새로운 핸들의 상속 속
// 성 지정.
DWORD fdwOptions); // 복사 옵션 들.
323
CreateThread(6)
- 수정 코드 예
DWORD WINAPI ParentThread(LPVOID
lpvThreadParam)
{
DWORD IDThread;
HANDLE hThreadParent;
DuplicateHandle(GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
&hThreadParent, 0,
FALSE,
DUPLICATE_SAME_ACCESS);
CreateThread(NULL, 0, ChildThread,
(LPVOID)hThreadParent, 0, &IDThread);
…..
}
DWORD WINAPI ChildThread(LPVOID
lpvThreadParam)
{
HANDLE hThreadParaent =
(HANDLE)lpvThreadParam;
SetThreadPriority(hThreadParent,
THREAD_PRIORITY_NORMAL);
CloseHandle(hThreadParent);
…..
}
- 위의 수정 코드에서 CloseHandle에 유의: 진짜
핸들의 생성은 커널 객체의 사용 계수 증가를
동반하므로 반드시 닫아 주어야 한다.
324
우선순위 (1)

스케줄링
스레드 A
스레드 B
CPU
스레드 C
스레드 D
스레드 E

우선순위


우선순위 클래스와 우선순위 레벨 값의 조합
설정
 BOOL SetThreadPriority(HANDLE hThread, int nPriority);
 int GetThreadPriority(HANDLE hThread)
325
우선순위 (2)
프로세스의 우선순위 클래스
스레드의
상대
우선순위
idle Background Foreground Foreground
High Realtime
Normal
Normal(+1) Normal(+2)
(4)
(7)
(8)
(9)
(13)
(24)
--------------------------------------------------------Time
15
15
15
15
15
31
Critical
Highest
6
9
10
11
15
26
Above
Normal
5
8
9
10
14
25
Normal
4
7
8
9
13
24
Below
Normal
3
6
7
8
12
23
Lowest
2
5
6
7
11
22
Idle
1
1
1
16
1
1
326
우선순위 (3)

Base Priority
 0~31


대부분의 스레드는 7~11
동적 우선순위(Dynamic priority)



실제로 적용되는 우선순위는 계속 변하게 된다.
스케줄러가 쓰레드를 실행할 때 적용하는 값
Priority Boost
 The system can boost and lower the dynamic priority
 Only threads with a base priority between 0 and 15 receive dynamic
priority boosts
 To ensure that it is responsive and that no threads are starved for
processor time

Base Priority보다 낮아지지는 않는다
327
우선순위(4)
우선 순위 클래스
의미
THREAD_PRIORITY_LOWEST
프로세서의 우선 순위 클래스 보다 두 단계 밑
THREAD_PRIORITY_BELOW_NORMAL
프로세서의 우선 순위 클래스 보다 한 단계 밑
THREAD_PRIORITY_NORMAL
프로세서의 우선 순위 클래스와 동일
THREAD_PRIORITY_ABOVE_NORMAL
프로세서의 우선 순위 클래스 보다 한 단계 위
THREAD_PRIORITY_HIGHEST
프로세서의 우선 순위 클래스 보다 두 단계 위
THREAD_PRIORITY_IDLE
프로세서의 우선 순위가 realtime이 아니면,
우선 순위 레벨을 가장 낮은 1로 설정
THREAD_PRIORITY_TIME_CRITICAL
프로세서의 우선 순위 클래스가 realtime이면,
우선 순위 레벨을 가장 높은 31로 만들고, 나머지
경우는 16으로 만듬
328
실습

간단한 task manager






사용자가 선택한 프로그램을 실행하고, 실행시킨 프로그램을
종료시킨다.
메뉴나 버튼을 선택하면 common file open dialog 생성
실행할 프로그램을 선택하면 파일 경로를 저장
CreateProcess로 선택한 프로그램을 실행
종료 메뉴를 버튼을 선택하면 TerminateProcess로 생성한
프로세스를 종료
2가지 다른 종류의 작업을 하는 worker thread

2가지 종류의 worker thread 생성
 Thread procedure를 다르게 정의
 하나는 숫자 세기, 하나는 그림 그리기


메뉴로 쓰레스 생성, 중지, 재시작
Thread priority 조정
329
12. IPC
InterProcess Communication
벽
Process A
Address Space
IPC
Process B
Address Space
윈도우 3.1에서와는 달리 별도의 주소 공간이 할당되기 때문에
서로간에 데이터를 주고 받을 방법이 필요하다

IPC


프로세스간의 통신 방법
Win32 환경에서는 주소공간의 분리로 인해 쉽지 않다.
331
IPC 사용

고려요소





네트웍 지원이 필요한가?
통신대상이 다른 운영체제에서 실행되는 프로그램인가?
통신 대상이 고정되어 있는가?
통신 속도가 중요한가?
일회적인 교환인가? 지속적인 교환인가?
332
IPC의 종류 (1)


Win32는 다수의 IPC 방법을 제공
Clipboard



DDE (Dynamic Data Exchange)



DDE 메시지를 사용한 지속적인 정보 교환
Win32에서는 네트워크 상에서도 동작
RPC (Remote Procedure Call)



중앙 저장소를 통한 대량의 정보 교환
Win32에서는 네트워크 상에서도 동작
원격 함수 호출 사용
서로 다른 플랫폼 위에서 동작하는 프로세스들간에 주로 사용
메시지

시스템 메시지 및 사용자 정의 메시지로 정보 교환
333
IPC의 종류 (2)

File Mapping


Pipe


파이프 사용
MailSlot


파일 공유
메일슬롯 사용
OLE(Object Linking & Embedding), Netbios
334
메시지

특징




가장 간단하고 빠른 방법
크기가 크지 않은 정보를 전달
메시지는 메모리를 거치지 않고 운영체제에 의해 직접 전달
방법


두 윈도우의 핸들을 알고 있어야 한다.
기존 메시지를 이용할 것이 아니라면 교환할 사용자 메시지를
정의해야 한다
 Message ID (ex. WM_USER+100)
 wParam, lParam에 들어갈 정보의 의미


약속된 메시지의 wParam, lParam를 통해 정보 교환
제약

문자열이나 구조체같은 큰 데이터는 전달할 수 없다
 wParam, lParam  8 byte

일반적으로 사실 통보의 목적으로만 사용됨
335
WM_COPYDATA (1)

특징


IPC를 위해 정의된 메시지
방법


wParam : 정보를 보내는 윈도우 핸들
lParam : 정보가 저장되어 있는 구조체의 포인터
 구조체
typedef struct tagCOPYDATASTURCT {
DWORD dwDATA; // 정수값
DWORD cbDATA; // lpDATA의 크기
PVOID lpDATA; // 문자열
} COPYDATASTRUCT;

장점

구조체나 배열 등 크기가 큰 데이터도 전달 가능
336
WM_COPYDATA (2)

주의 사항

lpData에는 받는 쪽에서 읽을 수 있는 값만 전달
 이진 포맷의 데이터의 경우


받는 데이터는 읽기 전용이므로 변경해서는 안된다
SendMessage()를 이용할 것
337
Memory Map file (1)

정의


하드 디스크에 존재하는 파일의 내용을 프로세스의 주소 공간에
연결(MAP)하는 기법
특징

포인터를 이용해서 파일 I/O 수행
 파일을 메모리처럼 조작
 프로그램하기가 쉽다

Win32에서 프로세스간 통신에 사용
 둘 이상의 프로세스가 File mapping object에 동시에 접근 가능
 각 프로세스는 포인터를 사용해 파일 조작해서 정보를 주고 받음
 동기화 오브젝트의 사용이 필수적
 정보를 갱신하면 이를 알릴 방법이 필요하다

로컬 시스템에서만 사용 가능
338
Memory Map file(2)

방법


File mapping object 생성
공유 방법
 Inheritance
 부모 프로세스가 file mapping 객체를 만든 후에 자식
프로세스에게 넘겨줌 ( 부모- 자식 프로세스에서만 가능)
 Named File Mapping
 이름을 통해 file mapping object를 공유
 File mapping object를 open해서 공유


파일 포인터를 얻어서 내용 조작
다른 IPC나 동기화 오브젝트를 통해 변경 사실을 알림
339
Memory Map file (2)

Object 생성
HANDLE CreateFileMapping (
HANDLE hfile,
// 파일 맵핑의 대상이 되는 파일의 핸들
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 보안
DWORD flProtect, // 맵핑 오브젝트의 보호 속성
DWORD dwMaximumSizeHigh, // 맵핑 오브젝트 (상위 32bit)
DWORD dwMaximumSizeLow. // 맵핑 오브젝트 (하위 32bit)
LPCTSTR lpName // 파일 맵핑 오브젝트의 이름
};



hFile이 0xffffffff이면 새로운 파일을 열어서 파일 맵핑 오브젝트 생성
flProtext : PAGE_READLYON or PAGE_READWRITE
lpName을 지정해야 다른 프로세스에서 이름을 가지고 파일 맵핑 오브젝트를 열어서
사용 가능
340
Memory Map file (3)

Object 열기

이미 생성된 파일 맵핑 오브젝트를 여는데 사용
HANDLE OpenFileMapping (
DWORD dwDesiredAccess. // FILE_MAP_READ, FILE_MAP_WRITE
DWORD bInheritHandle, // 계승 가능 여부 지정
LPCTSTR lpName // 파일 맵핑 오브젝트의 이름
);

lpName
 CreateFileMapping에서 지정한 이름을 입력해야 두 프로세스간에 파일
맵핑 오브젝트 공유 가능
341
Memory Map file (4)

Object에 대한 포인터 얻기

실제로 파일 맵핑 오브젝트를 조작하는데 사용
LPVOID MapViewOfFile(
HANDLE hfileMappingObjet. // 파일 맵핑 오브젝트의 핸들
DWORD dwDesiredAccess, // 접근 속성
DWORD dwFileOffsetHigh, // 접근하려는 오브젝트의 위치( 상위 32bit)
DWORD dwFileOffsetLow. // 접근하려는 오브젝트의 위치 ( 하위 32bit)
DWORD dwNumberOfByteToMap // 맵핑 하려는 파일의 바이트 수 (0 이면 전체)
);

dwDesiredAccess
 FILE_MAP_READ or FILE_MAP_WRITE
342
Pipe (1)

정의


두 프로세스간에 정보를 주고 받을 수 있는 통로
특징

연속적인 바이트 스트림을 교환할 때 사용
정보를 보낸다
프로세스 A

정보를 받는다
프로세스 B
종류


One-Way Pipe , Two-Way Pipe
Anonymous pipe , Named Pipe(NT)
343
Pipe (1)

익명 파이프 (Anonymous pipe)


이름이 없는 단방향 파이프
특징
 핸들을 이용해 통신하기 때문에 부모-자식 프로세스간의
통신에 적합
 네트워크 상의 다른 컴퓨터끼리는 사용할 수 없다
 9x 계열에서 사용 가능
 파이프 생성
 읽기용과 쓰기용의 2개의 핸들 생성
BOOL CreatePipe(
PHANDLE hReadPipe, // 읽기 전용의 파이프 핸들
PHANDLE hWritePipe. // 쓰기 전용의 파이프 핸들
LPSECURITY_ATTRIBUTES lpPipeAttributes, // 보안 관련 변수에 대한 포인터
DWORD nSize // 파이프를 할당하는 버퍼의 크기
344
);
Pipe (2)
 파이프의 한쪽끝을 통신하고자 하는 프로세스에게 전달
 부모가 자식에게 핸들을 상속
 DDE, 메모리 맵 파일등의 다른 IPC를 사용
 파일을 보낼 경우
 읽기 핸들을 전달, 자신을 쓰기 핸들에 데이터 기록
 파일을 받을 경우
 쓰기 핸들을 전달, 읽기 핸들로 데이터 받음
 읽고 쓰는 방법은 파일과 동일
 ReadFile, WriteFile API 이용
345
Pipe (3)

지명 파이프 (Named Pipe)

특징
 문자열로 된 이름을 가짐
 이름을 알고 있는 프로세스는 누구나 파이프를 열 수 있다.
 핸들 전달 필요 없음
 네트워크 상의 프로세스에서도 작동
 네트워크 프로토콜에 상관없이 동작 가능
 양방향으로 데이터 전달 가능

구성
 서버 프로세스와 클라이언트 프로세스로 구성
 서버 : 파이프를 만든 프로세스
 클라이언트 : 파이프 인스턴스에 접속하려는 프로세스
 하나의 서버는 여러 개의 프로세스와 통신
 각 파이프 인스턴스는 고유의 핸들과 별도의 버퍼
346
Pipe (4)

생성
HANDLE CreateNamedPipe(
LPCTSTR lpName, // 지명 파이프 이름
DWORD dwOpenMode, // 파이프의 생성 모드
DWORD dwPipeMode, // 파이프의 타입
DWORD nMaxInstances, // 생성될 파이프의 최대 개수
DWORD nOutBufferSize, // 전송 버퍼의 크기
DWORD nInBufferSize, // 수신 버퍼의 크기
DWORD nDefaultTimeOut // 타임아웃 값
LPSECURITY_ATTRIBUTE lpSecurityAttributes
);

lpName
 대소문자 구별 없으며 256자까지 가능
 \\시스템 이름\pipe\[path] 파이프 이름
 시스템 이름이 .이면 자신의 로컬 시스템
 ex. \\alanis\pipi\mypipe
347
Pipe Mode
방
향
설
정
양방향 통신 가능, 클라이언트에서 CreateFile할 때,
(GENERIC_READ | GENERIC_WRITE) 옵션 사용
PIPE_ACCESS_INBOUND
클라이언트에서 서버쪽으로 데이터를 쓰는 것만이 가능,
클라이언트에서 GENERI_WRITE 옵션 사용
PIPE_ACCESS_OUTBOUND
서버에서 클라이언트쪽으로 데이터를 쓰는 것만이 가능,
클라이언트에서 GENERI_READ 옵션 사용
FILE_FLAG_WRITE_THROUGH 바이트타입만 적용가능, 동기화된 I/O, 블록킹 I/O
-
동
기
비
동
기
PIPE_ACCESS_DUPLEX
FILE_FLAG_OVERLAPPED
비동기화된 I/O, ReadFile, WriteFile를 호출한 후 이벤트가
발생하기를 기다린다. 이벤트를 이용하지 않을 경우는
ReadFileEx, WriteFileEx를 사용
348
Pipe Type
PIPE_TYPE_BYTE
데이터를 스트림으로 써넣는다,
읽기 모드의 경우는 PIPE_READMODE_BYTE가 사용
데이터가 파이프에 메시지로 쓰여진다, 읽기 모드의 경우는
PIPE_TYPE_MESSAGE PIPE_READMODE_BYTE, PIPE_READMODE_MESSAGE 모두 가능
메시지 단위로 나누어 써도, 읽는 쪽에서 바이트 스트림으로 읽기 가능
읽 PIPE_READMODE_BYTE
기
모 PIPE_READMODE_MESSAGE
드
바이트 스트림으로 읽는다, 파이프 타입이
PIPE_TYPE_MESSAGE, PIPE_TYPE_BYTE이건 상관 없다.
메시지 단위로 읽는다, 파이프 타입이
PIPE_TYPE_MESSAGE일 때만 가능하다
대
블로킹 I/O를 할 때 사용
기 PIPE_WAIT
모 PIPE_NOWAIT 마이크로소프트 랜매니저 2.0과 호환성을 위해서 존재, 거의 사용안 함
드
349
Pipe (5)
 nDefaultTimeOut
클라이언트가 서버 파이프에 접속하는데 실패한 경우 이용가능한 파이프가
생길때까지 대기하는 시간


클라이언트의 접속

CreateFile이나 CallNamedPipe 이용
서버
-ex)
HANDLE hPipe = CreateNamedPipe(\\.\\pipe\\mypipe, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE |PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 4096, 4096, 1000, NULL);
클라이언트
HANDLE hPipe = CreateFile((\\alanis\\pipe\\mypipe,
GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

ReadFile or WriteFile을 이용해 통신
350
MailSlot (1)

정의

프로세스간의 단방향 통신 방법
 수신 전용



메모리에 존재하는 파일 or 우편함
파일처럼 파일 I/O로 조작하지만 임시적으로만 존재
특징



여러 개의 메시지를 한번에 보낼 수 있음
메시지의 크기는 최대 64K
메일 슬롯의 이름은 문자열
 \\.\mailslot\[path]Name



목적에 따라 그룹을 나눌 수 있다.
메모리 상에만 존재, 핸들을 닫으면 저장된 모든 메시지 삭제
Broadcasting 가능
 여러 프로세스들이 같은 이름으로 메일슬롯을 만든 경우 그 이름을
사용하면 해당하는 모든 프로세스의 메일슬롯으로 데이터 전송
351
MailSlot (2)

단점



단방향으로만 통신 가능
통신이 제대로 되었는지 확인 불가능
통신방법


MailSlot 서버와 클라이언트로 구성
MailSlot 서버
 MailSlot을 생성하고 클라이언트가 메시지를 보낼때까지 대기

MailSlot 클라이언트
 MailSlot의 위치와 이름을 가지고 접근
 데이터 기록해서 전송
352
MailSlot (3)

서버

생성
HANDLE CreateMailSlot(
LPCTSTR lpName,
DWORD nMaxMessageSize,
DWORD lReadTimeout,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
 lpName : 파이프와 동일한 형식
 생성에 성공하면 핸들을 리턴
 메시지를 꺼내거나 메일 슬롯 파괴시 사용

Timeout을 변경
BOOL SetMailslotInfo(HANDLE hMailslot, DWORD IReadTimeout);
353
MailSlot (4)

읽기
 서버 프로세스에서만 가능
 데이터를 읽기 위해서는 우선 데이터의 크기를 알아내야 한다
 GetMailSlotInfo 이용
BOOL GetMailSlotInfo(
HANDLE hMailSlot, // 메일 슬롯 핸들
LPDWORD lpMaxMessageSize, // 읽어올 수 있는 메시지의 최대 크기
LPDWORD lpNextSize, // 다음에 읽어올 메시지 크기
LPDWORD lpMessageCount, // 타임아웃 정보
LPDWORD lpReadTime // 타임아웃 시간 정보
);
 데이터의 크기를 알아낸 다음 ReadFile을 이용해 데이터를
읽어들임
 Message count가 0이 될때까지 loop을 돌면서 메시지를
읽어들이면 됨
354
MailSlot (5)

클라이언트

특징
 메일 슬롯에 메시지를 넣는 프로세스
 파일 입출력 함수만으로 메시지를 넣을 수 있다
 쓸 수 있는 데이터 양 제한
 일반적인 경우 : 64K


CreateFile API로 mailslot을 오픈
WriteFile API로 데이터 기록
355
MailSlot (6)
ex) 쓰기
// 먼저 메일 슬롯을 open한다.
//Wrinkle이란 시스템에 있는 sample이란 이름의 메일 슬롯이다.
hFile = CreateFile(\\wrinkle\mailslot\sample, GENERIC_READ, FILE_SHARE_READ,
FILE_ATTRIBUTE_NORMAL, (LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
// 다음으로 메일 슬롯에 데이터를 써 넣는다.
WriteFile(hFile, hey! How about learning API, 31, &cbWritten, NULL);
// 메일 슬롯을 닫는다.
CloseHandle(hFile);
ex) 읽기
fResult = GetMailslotInfo(hSlot1, NULL, &cbMessage, &cMessage, NULL);
while(cMessage != 0)
ReadFile(hSlot1, lpszBuffer, cbMessage, &cbRead, NULL);
… // 읽어 들인 데이터로 하고 싶은 일을 수행한다.
GetMailslotInfo(hSlot1, NULL, &cbMessage, &cMessage, NULL);
-
356
PIPE Vs MailSlot
Named Pipe
-양방향 통신이 가능
-네트워크 상에서도 동작 가능
-broadcasting이 불가능
-송수신이 보장됨
-서버는 NT에서만 동작
MailSlot
-단방향 통신만 가능
-네트워크 상에서도 동작 가능
-broadcasting이 가능
-데이터그램을 사용하기에 송수신이
보장됨이 안됨
-NT, 윈도우95 모두에서 동작
357
실습 (1)

IPC 테스트


다양한 IPC 방법을 사용해본다
IPC 방법대로 메뉴 구성





사용자 정의 메시지
WM_COPYDATA
Simple file mapping
File mapping with event object
사용자 정의 메시지
 송신 프로그램과 수신 프로그램들 별도의 프로젝트로 생성
 사용자 메시지 정의
 SendMessage로 송신하고 수신하면 받았다는 메시지 박스를
화면에 출력
358
실습 (2)
 WM_COPYDATA
 COPYDATASTRUCT 구성
 Common color dialog와 edit를 올린 다이얼로그를 사용해서 color와 text를
입력받은 후, 이 내용으로 COPYDATASTRUCT 구성
 SendMessage(수신 윈도우, WM_COPYDATA, ~~)
 수신 윈도우는 수신후 받은 내용과 색으로 화면에 내용 출력
 Simple file mapping
 송신 윈도우는 file mapping object를 생성하고 내용 기록
 수신 윈도우는 file mapping object를 열어서 내용을 화면에 출력
 File mapping with event object
 송신 윈도우는 thread를 하나 생성한 후, file mapping object와 event object
생성
 WaitForSingleObject로 수신 윈도우가 데이터를 기록해서 이벤트가 일어날
때까지 기다림
 수신 윈도우는 file mapping object와 이벤트를 열고 데이터를 기록한 후
이벤트 발생시킴
 송신 윈도우는 이벤트를 받으면 받은 내용을 메시지 박스로 출력
359
13. Synchronization
MultiThread (1)

특징

동시에 여러 개의 작업 수행
361
MultiThread (2)

문제점

복수개의 코드가 같은 주소 영역에서 실행
 서로 간섭하고 영향을 줄 수 있다

공유 자원을 보호하기 어렵다
 메모리 영역의 전역변수
 동일한 프로세스의 스레드는 전역변수를 공유
 Race condition 발생
 The situation where several processes access and manipulate shared data
concurrently
 The final value of the shared data depends upon which process finishes last
count++ could be implemented as
register1 = count
(LOAD R1, COUNT)
register1 = register1 + 1
(ADD R1, 1)
count = register1
(STORE R1, COUNT)
count-- could be implemented as
register2 = count
(LOAD R2, COUNT)
register2 = register2 - 1
(SUB R2, 1)
count = register2
(STORE R2, COUNT)
362
MultiThread (3)

쓰레드간의 실행 순서를 제어하기 힘듬
 Deadlock이 발생할 수 있다
 Two or more processes are waiting indefinitely for an event that can be
caused by only one of the waiting processes
 Let S and Q be two semaphores initialized to 1
P0
P1
wait (S);
wait (Q);
wait (Q);
wait (S);
.
.
.
.
.
.
signal (S);
signal (Q);
signal (Q);
signal (S);
 Starvation
 Indefinite blocking

해결방법

동기화
363
Thread Synchronization(1)
Thread A
Thread B
동기화 오브젝트
사건이 발생한 것을
통보 받고 실행된다
특정한 사건이
발생했음을 알린다
쓰레드 동기화의 예
1. Event
2. Critical Section
3. Mutex
4. Semaphore
364
Thread Synchronization(2)

Event



Critical Section



다수가 공유하는 데이터에 대해 한번에 하나의 쓰레드만 접근할 수
있도록 제한
단 하나의 프로세스 속한 쓰레드에서만 사용 가능
Mutex(Mutual Exclusion)



쓰레드간의 동기화에 가장 많이 사용
서로 다른 프로세스에 속한 쓰레드 간의 동기화에도 사용
다수가 공유하는 데이터에 대해 한번에 하나의 쓰레드만 접근할 수
있도록 제한
여러 프로세스에 속한 쓰레드간에도 사용 가능
Semaphore


공유 데이터에 대해 동시에 N(N≧1)개의 쓰레드가 접근할 수 있도록
허용
서로 다른 프로세스에 속한 쓰레드 간의 동기화에도 사용
365
Thread Synchronization(3)
Primary Thread
Primary Thread
Other Threads
 쓰레드를 생성하고 그 쓰레드가 종료되어야 다음
작업을 진행한다면 쓰레드를 사용하는 의미가 없다
단일 쓰레드 프로그램과 잘못 작성한 멀티 쓰레드 프로그램의 비교
366
Event Object(1)

Event Object




쓰레드간의 작업 순서나 시기를 조정하기 위해 사용
하나 이상의 쓰레드에게 특정 사건이 일어났음을 알려준다.
Signal state, Non-signal state
Auto-reset event vs Manual-reset event
 auto-reset event : signal 상태가 되면 자동으로 non-signal 상태가 된다
 manual-reset event : signal 상태가 되었을 경우, ResetEvent를 이용해서
non-signal 상태로 만든다
Event
이벤트 오브젝트의 역할
T1
T2
Tn
WaitForSingleObject
대기중인 쓰레드들
367
Event Object(2)

Creating Event Object
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 접근 권한 정보
BOOL bManualReset, // 수동 리셋 이벤트인지, 자동 리셋 이벤트 표시
BOOL bInitialState, // 초기 상태, True->Signal, False->Non-signal
LPCTSTR lpName
// 이벤트 오브젝트의 이름
);
이벤트 오브젝트의 이름은 다른 프로세스에 속한 이벤트에 대한
핸들을 얻고자 할 때(OpenEvent API 사용)사용
368
Event Object(3)

Opening Event Object
HANDLE OpenEvent(
DWORD dwDesiredAccess, // 이벤트 오브젝트 핸들에 대한 접근 권한 제어
BOOL bInheritHandle, // 계승 가능 여부, TRUE->계승가능, FALSE->계승불허
LPCTSTR lpName
// open할 이벤트의 이름
);
dwDesiredAccess
의미
SYNCHRONIZE
Open한 이벤트의 상태를 바꿀 수는 없고, 동기화를 위해서만
사용가능, SetEvent나 ResetEvent를 호출할 수는 없고, 단지
WaitForSingleObject와 같은 API를 호출해 동기화 가능
EVENT_MODIFY_STATE
SYNCHRONIZE와는 반대로 open한 이벤트의 상태를 바꾸는
것만이 가능하고, 동기화를 위해서 사용할 수는 없다
EVENT_ALL_ACCESS
위의 두가지가 다 가능하다
369
Event Object(4)

Changing Event Object’s State
Signal 상태가 되면, 하나의 쓰레드가
방출되고, 다시 non-signal이 된다.
Signal 상태로 변경한다. 대기 중인
쓰레드가 모든 방출된다.
ResetEvent
아무런 영향이 없다.
상태를 non-signal 상태로 만든다.
PulseEvent
SetEvent와 동일하다.
대기중인 모든 쓰레드를 방출하고,
다시 non-signal 상태로 만든다.
SetEvent
370
Critical Section(1)

Critical Section


공용 자원(파일이나 메모리)에 두 개 이상의 쓰레드가 접근하여
자원의 완전성을 파괴하는 것을 방지하기 위해 사용
같은 프로세서에 속한 쓰레드들에서만 사용 가능
serialize
Critical section
공용 자원
n
3
2
1
371
Critical Section(2)
ex) Critical Section으로 구현한 자원 접근의 일렬화
do {
entry section
critical section
exit section
} while (1);
CRITICAL_SECTION CSObject;
InitializeCriticalSection(&CSObject);
………………
EnterCriticalSection(&CSObject);
[공용 자원에 대한 접근이 이루어지는 코드]
LeaveCriticalSection(&CSObject);
372
Critical Section(3)

방법


공유 자원이 있는 곳을 크리티컬 섹션으로 둘러싸준다.
초기화 및 파괴
 VOID InitializeCriticalSection(LPCRITICAL_SECTION lpcsCSObject);
 VOID DeleteCriticalSection(LPCRITICAL_SECTION lpcsCSObject);
 Critical_SECTION형의 변수 지정
 반드시 전역변수로 지정해야 한다.

크리티컬 섹션 구성
 VOID EnterCriticalSection(LPCRITICAL_SECTION lpcsCSObject);
 VOID LeaveCriticalSection(LPCRITICAL_SECTION lpcsCSObject);

단점


잘못할 경우 deadlock이 발생 할 수 있다.
쓰레드끼리 작업 시기를 제어하기에는 적당하지 않다
 주로 공유 변수나 자원에 대한 접근 제한
373
Synchronization Object

동기화 객체


동기화에 사용되는 객체
일정 시점에서 한가지 상태 유지
 Signaled : 쓰레드의 실행을 허가하는 상태
 Nonsignaled : 쓰레드의 실행을 허가하지 않는 상태

대기함수(Wait Function)와 같이 사용
 일정한 조건에 따라 쓰레드의 실행을 블록 또는 허가
 조건이 만족할 때까지 대기
 대기 중에는 CPU 시간을 거의 소비하지 않는다.
DWORD WaitForSignalObject(HANDLE hHandle, DWORD dwMilliseconds);
 핸들이 지정하는 동기화 객체가 신호상태가 되기를 기다림
 리턴하기 전의 동기화 객체의 상태를 변경
 예) 신호상태의 동기화 객체  비신호상태로
374
Mutex (1)

Mutex Object

특징
 이름을 가진다.
 프로세스간에도 사용가능
 오직 한 쓰레드에 의해서만 소유될 수 있다.
 소유시 비신호 상태로 변경

Mutex Object 생성
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 보안 관련 구조체
BOOL bInitialOwner, // 생성과 동시에 소유 여부 지정
LPCTSTR lpName // 뮤텍스 오브젝트의 이름
};
// NULL일 경우 다른 객체에서 open할 수 없다
375
Mutex (2)

Mutex Object 열기
HANDLE OpenMutex(
DWORD dwAccess, // SYNCHRONIZE, MUTEX_ALL_ACCESS
BOOL bInherit,
// 계승 여부 표시
LPTSTR lpszMutexName // 뮤텍스 오브젝트의 이름
);
 리턴되는 핸들값은 프로세스에 한정적이다.

Mutex Object 파괴
BOOL CloseHandle( HANDLE hMutex );

Mutex Object 양도
BOOL ReleaseMutex( HANDLE hMutex );
376
Mutex(3)
EX) Mutex로 구현한 자원 접근의 일렬화
HANDLE hMutex;
hMutex = CreateMutex(……..);
………….
WaitForSingleObject(hMutex, INFINITE);
[공용 자원에 대한 접근이 이루어지는 코드]
ReleaseMutex(hMutex);
377
Semaphore Object(1)

Semaphore Object



최대 N(N≧1)개의 쓰레드가 동시에 작업을 수행할 수 있도록 함
Mutex Object와 사용 방법이 동일
Semaphore Object의 생성
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 보안 관련 구조체
LONG lInitialCount,
// 세마포어의 시작카운트
LONG lMaximumCount, // 세마포어를 소유할 수 있는 최대 개수
LPCTSTR lpName
// 세마포어의 이름
);
378
Semaphore Object(2)

Semaphore Object 열기
HANDLE OpenSemaphore(
DWORD dwDesiredAccess, // 접근 권한
BOOL bInheritHandle,
// 계승 여부 표시
LPCTSTR lpName
// 세마포어 오브젝트의 이름
);
dwDesiredAccess
SYNCHRNIZE
의미
Open한 세마포어를 동기화하는 데에만 사용
SEMAPHORE_MODIFY_STATE
세마포어의 상태를 변경하기 위해서 사용
SEMAPHORE_ALL_ACCESS
세마포어를 위의 둘다 가능하게 open 가능
379
Semaphore Object (3)

Semaphore Object의 양도
BOOL ReleaseSemaphore(
HANDLE hSemaphore, // 양도 대상이 되는 세마포어 핸들
LONG lReleaseCount, // release하는 개수
LPLONG lpPreviousCount // 이전까지의 세마포어 카운트(비어 있던 자리수)
);
380
14. An Overview of TCP/IP
Networking
381
Packet Forwarding

Name, Address & Routing



Name: What you are
Address: Where you are
Routing: How to reach you
382
Address

IP Address



Each internet host has universally unique IP address
4 bytes
Net ID
Host ID
Type
7
0
24
Net ID
Host ID
Class A
14
10
16
Net ID
Host ID
21
1 10
1 11 0
Net ID
Multicast Address
Class B
8
Host ID
Class C
Class D
383
Address

Ex)

All hosts on a network have the same network prefix
gateway
128.211
128.10
128.211.6.5
128.10.0.1
128.10.0.2
10
10.0.0.37
gateway
192.5.48.3
gateway
192.5.48
10.0.0.49
384
DNS

IP address ↔ Name(Character string for human use)

etc/hosts file
/etc/hosts
127.0.0.1 localhost localhost.snu.ac.kr
147.46.59.101 popeye.snu.ac.kr popeye loghost
147.46.59.102 brutus.snu.ac.kr brutus
147.46.59.103 olive.snu.ac.kr olive
147.46.59.104 wimpy.snu.ac.kr wimpy

Distributed Name Server
 Setup : /etc/resolve.conf
/etc/resolv.conf
domain snu.ac.kr
nameserver 147.46.80.1
nameserver 147.46.60.18
nameserver 147.46.80.2
385
DNS
Root
name
server
1
cheltenham.cs.arizona.edu
Client
192.2.69.60
Local
name
server
4
cheltenham.cs.arizona.edu
cs.arizona.edu,192.12.69.5
5
Arizona
name
server
CS
name
server
386
IP Packet

IP Packet Format
Max = 64 KB

4
8
4
VER
16
HLEN Service Type
ID
TTL
Total Length
Flags
Protocol
Fragment Offset
Header Checksum
SA
DA
IP Options (If Any)
Padding
Data
.
387
Fragmentation & Reassembly

MTU (Maximum Transfer Unit)


Maximum frame size that a physical network can transmit
Different physical networks have different MTUs
 Ethernet - 1500 Byte
 FDDI - 4500 Byte, TR - 8000 Byte

Fragmentation



Partitioning of a datagram into multiple smaller fragments
Sizes <= MTU of next physical network
Reassembly


Concatenation of fragments into the original datagram
Protocol principle
2015-04-13
Fragmentation & Reassembly
MTU = 1500
MTU = 532
Original =
20 + 1400 Byte
Fragments = 20 + 512 Byte
Fragments = 20 + 512 Byte
Fragments = 20 + 376 Byte
2015-04-13
Fragmentation
& Reassembly
Start of header
ID=x
1
Offset=0
Rest of header
512 data bytes
Start of header
ID=x
0
Start of header
Offset=0
ID=x
1
Rest of header
Rest of header
1400 data bytes
512 data bytes
512
Start of header
ID=x
0
1024
Rest of header
376 data bytes
390
Protocol

TCP
Application
 Reliable End-to-end Protocol
 Connection-based

UDP
TCP
UDP
IP
 Best-effort datagram service
 Connectionless
Data Link
Physical
TCP Header
Data
IP Header
Network header
Data
Data
TCP Segment
IP Datagram
Network-Level Packet
391
Port

Application Program using TCP/IP

Use port
 16 bit number

Well-known port



port numbers below 256
reserved for standard services (RFC 1700)
ex. FTP : port 21, TELNET: port 23
/etc/services
#
Network services, Internet style
#
netstat 15/tcp
ftp 21/tcp
telnet 23/tcp
smtp 25/tcp
.
392
Physical Network
Transport &
Upper layers
Network
Router
Network
Physical
Physical
Physical
Logical
Network
Use Logical
Address
Physical
Network
Use Physical Route within
Address
Physical net
Transport &
Upper layers
Network
Physical
Route over
internet
Physical Address (MAC Address) : 6 Bytes
393
How to Find Mac Address?

Linux uses ARP(Address Resolution Protocol)



Send ARP request packet( with IP address)
Responds with an ARP reply( with Physical hardware
address)
RARP


Physical address  IP address
Used by gateways
394
Client ↔ Server

Server


Client


Client 에게 서비스를 하기 위해 기다림
Server에게 서비스를 요청
작업 순서




서버는 자신의 통신 포트를 열고 기다림
클라이언트는 연결 요청
요청이 수락되면 서비스 요청
서버가 서비스
395
소켓 프로그램 시나리오
Server
Socket()
bind()
Client
listen()
Socket()
accept()
blocks until
connection from client
read()
connect()
Data(Request)
write()
Process Request
Data(Reply)
write()
read()
396
기본 네트워크 API (1)

Socket


SOCKET PASCAL FAR socket (int family, int type, int
protocol); // 16bit 정수를 반환 (socketfd)
Family 유형
AF_UNIX
1
Local to host
AF_INET

Socket 유형
2
TCP,UDP
AF_IMPLIMK 3
Arpanet
AF_IPX
IPX
6
SOCKET_STREAM 1
Stream socket
SOCKET_DGRAM
2
Datagram socket
SOCKET_RAW
3
Raw-Protocol interface
SOCKET_RDM
4
Reliably-delivered Message
397
기본 네트워크 API (2)
<프로토콜 사용가능 조합>
Family
Type
Protocol
Actual
Protocol
AF_INET
SOCKET_DGRAM
IPPROTO_UDP
UDP
AF_INET
SOCKET_STREAM
IPPROTO_TCP
TCP
AF_INET
SOCKET_RAW
IPPROTO_ICMP
ICMP
AF_INET
SOCKET_RAW
IPPROTO_RAW
raw
398
기본 네트워크 API (3)

Bind System call


Int PASCAL FAR bind (SOCKET s, const struct sockaddr
FAR *addr, int namelen);
서버
 시스템의 알려진 주소를 등록

클라이언트
 스스로 자신의 주소를 등록

Connect system call


Int PASCAL FAR connect (SOCKET s, const struct
socketaddr FAR *name, int namelen);
연결 설정 성공 값을 반환
399
기본 네트워크 API (4)

Listen System call

Int Pascal FAR listen(SOCKET s, int backlog);
 Blacklog : 얼마나 많은 클라이언트를 받아들일 것인가?


클라이언트의 연결을 기다리게 하는 함수
Accept System call



실제 연결 요청이 오면 서버가 그 연결을 받아들이라는
명령으로 사용
SOCKET PASCAL FAR accept (SOCKET s, struct sockaddr
FAR *addr, int FAR *addrlen);
반환값은 클라이언트와 통신한 새로운 socketfd 이고
클라이언트와의 통신은 새로운 socketfd을 통해서
이루어진다.
400
기본 네트워크 API (5)

send, recv System call



Int PASCAL FAR send (SOCKET s, const char FAR *buf, int
len, int flags);
Int PASCAL FAR recv(SOCKET s, char FAR *buf, int len, int
flags);
Closesocket System call


Int PASCAL FAR closesocket (SOCKET s);
프로세스에서 사용한소켓은 마지막으로 닫아 주고
프로세스를 종료해야 한다
401
기본 네트워크 API (6)

주소 변환

실제 컴퓨터가 인식하는 주소
 In_addr 형태


Unsigned long PASCAL FAR inet_addr(const char FAR *
cp);
Char FAR * PASCAL FAR inet_ntoa (struct in_addr in);
402
Network in Windows 95


최근의 32bit OS는 네트워크를 기본으로 내장
WNet API


윈도우 95나 NT에서 네트워크를 통해 다른 시스템에 있는 파일,
프린터를 공유할 때 사용
Winsock처럼 네트워크 환경에 무관한 인터페이스 제공
403
WNet API

WNet API

네트워크나 프로토콜에 관계없는 단일한 인터페이스 제공
네트워크 루트
도메인 #1
호스트#1
도메인 #2
도메인 #3
호스트#2
공유 포인터 #1
공유 포인터 #2
<Wnet API로 검색해 볼 수 있는 네트워크 구성>
404
대화상자를 통해 연결-해제
DWORD dwResult;
DWORD dwError, dwNameBufSize;
char ErrorBuf[128], NameBuf[64];
dwResult = WNetConnectionDialog(hWnd, RESOURCETYPE_DISK);
if(dwResult != NO_ERROR)
{
WNetGetLastError(&dwError, &ErrorBuf, 128, &NameBuf, 64);
}
WNetDisconnect의 실행
WNetConnectionDialog의 실행
405
네트워크 리소스를 검색하기

NETRESOURCE 구조체
필드명
DWORD dwScope
DWORD dwType
DWORD dwDisplayType
의미
탐색할 네트워크 리소스의 범위를 구한다.
- RESOURCE_CONNECTED : 현재 연결된 리소스들만 탐색
-RESOURCE_GLOALNET : 모든 리소스를 탐색
-RESOURCE_REMEMBERED : 로그온할 때마다 자동으로
연결되는 리소스들을 대상으로 검색
어떤 종류의 리소스를 탐색할 것인지를 나타냄
- RESOURCETYPE_ANY : 모든 리소스
- RESOURCETYPE_DISK : 디스크 리소스
- RESOURCETYPE_PRINT : 프린트 리소스
검색된 리소스가 어떤 리소스인지 나타낸다
- RESOURCEDISPLAYTYPE_DOMAIN : 도메인이다.
- RESOURCEDISPLAYTYPE_SERVER : 서버이다.
- RESOURCEDISPLAYTYPE_SHARE : 공유포인터이다.
- RESOURCEDISPLAYTYPE_GENERIC : 모든 리소스
406
필드명
의미
LPTSTR lpLocalName
검색 API에서 채워 주는 부분, dwScope의 값이
RESOURCE_CONNECTED, RESOURCE_REMEMBERED이면,
로칼 디바이스 이름
DWORD dwUsage
dwScope의 값이 RESOURCE_GLOBALNET인 경우에만 의미 있음
- RESOURCEUSAGE_CONNECTABLE : 공유 포인터
- RESOURCEUSAGE_CONTAINER : 컨테이너 리소스
LPTSTR lpRemoteName
dwScope의 값이 RESOURCE_CONNECTED이거나
RESOURCE_REMEMBERED이면, 리소스의 이름을 나타낸다.
LPTSTR lpComment
네트워크 제공자가 제공한 설명 문자열을 가리킨다. 대부분 NULL
이 사용된다.
LPTSTR lpProvider
이 네트워크 리소스를 제공한 네트워크 제공자의 이름을 나타낸다
이름이 알려져 있지 않으면 NULL이 쓰인다.
407
DWORD WNetOpenEnum(DWORD dwScope, DWORD dwType, DWORD dwUsage,
LPNETRESOURCE ipNetResource, LPHANDLE iphEnum);
네트워크 리소스에 대한 검색을 수행하기 위해 네트워크
검색 핸들을 open하는 데 사용
인자
dwScope
의미
탐색할 범위를 결정, NETRESOURCE의 dwScope와 같다.
dwType
어떤 리소스를 탐색할 지 결정, NETRESOURCE의 dwType와 같다
dwUsage
dwScope가 RESOURCE_GLOBALNET일 때만 의미가 있다.
- 0 : 모든 리소스를 연결 대상으로 삼는다
- RESOURCEUSAGE_CONNECTABLE : 연결 가능한 모든 리소스를 대상
- RESOURCEUSAGE_CONTAINER : 모든 컨테이너 리소스를 대상
lpNetResource
네트워크 계층도상의 노드 중에 어디서부터 검색해야 할지를 나타낸다.
lpNetResource가 NULL이면 루트부터 검색한다.
lphEnum
이 필드가 가리키는 영역으로 네트워크 리소스 검색 핸들이 리턴된다.
WNetEnumResource API에 이 핸들을 인자로 사용하여 원하는 노드에
408
포함된 네트워크 리소스를 검색
DWORD WNetEnumResource(
HANDLE hEnum,
// 검색하고자 하는 네트워크 리소스의 검색핸들
LPDWORD lpcCount;
// 그 리소스에 포함된 리소스의 개수
LPVOID lpBuffer, // 포함된 리소스에 대한 데이터를 얻어올 버퍼
LPDWORD lpBufferSize); // 버퍼의 크기
인자
의미
hEnum
WNetOpenEnum API에 의해 리턴된 리소스의 검색 핸들
lpcCount
가능한 모든 리소스를 검색하려면 0xFFFFFFFF,
검색된 리소스의 개수가 리턴된다.
lpBuffer
검색 결과가 리턴되는 버퍼, NETRESOURCE로 표현, 보통 16K 버퍼
lpBufferSize
lpBuffer가 가리키는 버퍼의 크기
409
BOOL FAR PASCAL EnumAllResource
(HWND hWnd, HDC Hdc, LPNETRESOURCE lpnr, HTREEITEM hItem) {
DWORD dwResult, dwResultEnum;
HANDLE hEnum;
DWORD cbBuffer = 16384;
DWORD cbEntries = 0xFFFFFFFF; // 모든 포함된 리소스를 검색
LPNETRESOURCE lpnrLocal;
// lpnr이 가리키는 네트워크 리소스를 open하여, hEnum으로 네트워크
// 검색 핸들을 얻어온다.
dwResult = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCE_ANY,
0, lpnr, &hEnum);
if(dwResult != NO_ERROR) {
DWORD dwError;
char ErrorBuf[128], NameBuf[128];
WNetGetLastError(&dwError, &ErrorBuf, 128, &NameBuf, 64);
MessageBox(hWnd, ErrorBuf, NameBuf, MB_OK);
}
410
do {
// 검색 결과를 돌려 받을 버퍼를 할당한다.
Lpnr = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
// 검색을 수행한다.
dwResultEnum = WNetEnumResource
(hEnum, &cbEntries, lpnrLocal, &cbBuffer);
if(dwResultEnum == NO_ERROR) {
// 네트워크 리소스를 display한다.
for(DWORD i=0; i<cbEntries; i++)
DisplayNetResource(hDC, &lpnrLocal[i], hItem);
}
else if(dwResultEnum != ERROR_NO_MORE_ITEMS) break;
} while(dwResultEnum != ERROR_NO_MORE_ITEMS)
dwReuslt = WNetCloseEnum(hEnu);
if(dwResult != NO_ERROR)
return FALSE;
return TRUE;
}
411
네트워크 리소스에 연결-해제
WNetAddConnection
WNetAddConnection2
WNetCancelConnection
WNetCancelConnection2
WNetGetConnection
네트워크 리소스에 연결하기
네트워크 리소스와의 연결 해제
연결된 네트워크 리소스에 대한 정보 얻기
DWORD WNetAddConnection(
LPTSTR lpRemoteName,
// 공유 포인터의 이름
LPTSTR lpPassword,
// 패스워드
LPTSTR lpLocalName
// 지정한 로컬 디바이스로 첫번째 네트워크의
);
// 공유 포인터 추가
DWORD WNetAddConnection2(
LPNETRESOURCE lpNetResource,
LPCSTR lpPasswd,
LPCSTR lpUsername,
DWORD dwFlags
);
412
DWORD WNetCancelConnection(
LPTSTR lpName,
BOOL fForce
);
DWORD WNetConnection2(
LPTSTR lpName,
DWORD dwFlags
BOOL fForce
);
DWORD WNetGetConnection(
LPTSTR lpLocalName,
LPTSTR lpRemoteName,
LPDWORD lpnLength;
);
413
Download