홍승아블로그

Windows API

windows programming

  • 윈도우즈의 장점

    1. 그래픽 기반의 운영체제
    • 화면 처리를 문자 단위가 아닌 디지털 표현의 최소 단위인 픽셀로 처리해서 화면 처리 가능
    1. 멀티 태스킹이 가능하다.
    • 한번에 여러가지 일을 수행함.
    1. 장치에 영향을 받지 않는다.
    • 디바이스 드라이버에 의해 주변 장치들을 제어하고 관리한다. 장치가 바뀌면 디바이스 드라이버만 교체해주면 되고 소프트웨어는 이에 영향을 받지 않는다.
    1. 일관성
    • 인터페이스 구성이 표준화됨에 따라서 한 번 배우기만 하면 어떤 프로그램이든지 유사한 방법으로 사용 가능함.
  • 윈도우즈 프로그램을 링크하여 실행 파일을 생성할 때는 개발 환경에서 제공하는 특별한 ‘임포트 라이브러리’와 링크해야 한다. 임포트

    라이브러리에는 DLL 이름과 더불어 프로그램이 사용하는 모든 윈도우즈 함수 호출을 위한 참조 정보가 들어 있다.

  • 임포트 라이브러리 확인 : Project - Setting - Link Tab에서 확인가능

  • 링커는 이 정보를 토대로 실행 파일(.EXE) 안에 테이블을 생성하고, 윈도우즈는 프로그램을 로드할 때 이 테이블 정보를 수정하여 실제

    윈도우즈 함수를 호출 할 수 있다.

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MessageBox(NULL, TEXT(“Hello Windows!”), TEXT(“HelloMsg”), 0);

return 0; }

  • 헤더파일(#include <windows.h>)
  1. WINDEF.H : 기본 타입 정의

  2. WINNT.H : 유니코드 지원을 위한 타입 정의

  3. WINBASE.H : Kernel 함수

  4. WINUSER.H : 사용자 인터페이스 함수

  5. WINGDI.H : 그래픽 장치 인터페이스 함수

  • 프로그램 진입점

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

  1. #define WINAPI __stdcall
  • 컴파일, 링크, 실행
  1. 컴파일 단계에서 컴파일러는 C소스 코드 파일로부터 .OBJ 파일을 생성한다.

  2. 링크 단계에 링커는 .OBJ 파일과 .LIB 파일을 겹합하여 .EXE 파일을 만든다.

-KERNEL32.LIB, USER32.LIB, GDI32.LIB 파일은 윈도우즈 서브시스템을 사용하기 위한 ‘임포트 라이브러리’임.

  1. 비주얼 C++에서는 Debug, Release 환경 설정을 이용해서 프로그램을 컴파일 및 링크할 수 있다.

유니코드

  • 유니코드와 DBCS 차이점
  • 유니코드는 와이드 문자(16비트)를 항상 사용한다(8비트 문자는 아무 의미가 없다.)

  • DBCS(Double Byte Character set)는 여전히 8비트 값을 나타낸다.

  • 와이드 문자와 윈도우즈

    1. 윈도우즈 헤더 파일 타입
    • typedef char CHAR;

    • typedef wchar_t WCHAR;

    1. 8비트 문자열

    typedef CHAR *PCHAR; typedef CHAR *LPCH, *PCH;

    typedef CHAR *NPSTR; typedef CHAR *LPSTR, *PSTR;

    typedef CONST CHAR *LPCCH, *PCCH;

    typedef CONST CHAR *LPCSTR, *PCSTR;

    1. 16비트 문자열

    typedef WCHAR *PWCHAR; typedef WCHAR *LPWCH, *PWCH; typedef WCHAR *NWPSTR; typedef WCHAR *LPWSTR, *PWSTR;

    typedef CONST WCHAR *LPCWSTR, *PCWSTR;

    typedef CONST WCHAR *LPCWCH, *PCWCH;

  • 윈도우즈 함수 호출 : UNICODE 식별자 정의에 따라 다른 MessageBox 호출됨.

  1. int WINAPI MessageBox(HWND, LPCSTR, LPCSTR, UINT)

    • WINUSERAPI int WINAPI MessageBoxA(HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType); WINUSERAPI int WINAPI MessageBoxW(HWND hWnd , LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); #ifdef UNICODE #define MessageBox MessageBoxW #else #define MessageBox MessageBoxA #endif // !UNICODE
  • 윈도우즈의 문자열: UNICODE 식별자 정의에 따라 다른 문자열 함수가 호출됨.

WINBASEAPI int WINAPI lstrlenA( LPCSTR lpString ); WINBASEAPI int WINAPI lstrlenW( LPCWSTR lpString ); #ifdef UNICODE #define lstrlen lstrlenW #else #define lstrlen lstrlenA #endif // !UNICODE

  • 윈도우즈에서 printf 사용하기

윈도우즈와 메시지

// hInstance : 인스턴스 핸들, hPrevInstance : WIN16와 호환성을 위해 남겨둠,

// lpCmdLine : 프로그램에 전달되는 명령행 인자, nCmdShow : 처음 뜰 때 메인 윈도우 화면에 표시하는 방법(SW_SHOWNOMAL 등)

#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); HINSTANCE g_hInst; LPCTSTR lpszClass=TEXT(“First”);

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance ,LPSTR lpszCmdParam,int nCmdShow) { HWND hWnd; MSG Message; WNDCLASS WndClass; g_hInst=hInstance;

WndClass.cbClsExtra=0; WndClass.cbWndExtra=0; WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.hCursor=LoadCursor(NULL,IDC_ARROW); WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION); WndClass.hInstance=hInstance; WndClass.lpfnWndProc=WndProc; WndClass.lpszClassName=lpszClass; WndClass.lpszMenuName=NULL; WndClass.style=CS_HREDRAW | CS_VREDRAW; //윈도우 사이즈 변경시 WM_PAINT 호출 RegisterClass(&WndClass);

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,(HMENU)NULL,hInstance,NULL); 1번째 : 윈도우 클래스 이름을 나타내는 포인터

2번째 : 윈도우 이름을 나타내는 포인터

3번째 : 윈도우 스타일

  • WS_OVERLAPPEDWINDOW : WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX,

    WS_MAXIMIZEBOX 속성을 모두 갖는 윈도우를 생성한다.

  • 4번째 : 시스템이 적절한 디폴트 위치에 윈도우를 생성

ShowWindow(hWnd,nCmdShow);

UpdateWindow(hWnd);

while (GetMessage(&Message,NULL,0,0)) { TranslateMessage(&Message); DispatchMessage(&Message); } return (int)Message.wParam; }

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam) { switch (iMessage) { case WM_DESTROY: PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd,iMessage,wParam,lParam)); }

  • 윈도우 : 사용자로부터 입력을 받거나 텍스트와 그래픽 형태로 출력하는 하면의 직사각형 영역을 말한다.

  • 윈도우 종류

    • 애플리케이션 윈도우 : 툴바, 스크롤바

    • 대화상자

    • 자식윈도우, 컨트롤윈도우, 자식 윈도우 컨트롤 : push button, radio button, check box, list box, scroll bar

  • 윈도우 프로시저

while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }

- 메시지 처리 함수 : 메시지가 발생할 때 프로그램의 반응을 처리하는 일을 하며 WinMain 함수와는 별도로 WndProc이라는 이름으로

                            존재한다.

- WndProc은 WinMain에서 호출하는 것이 아니라 윈도우즈에 의해 호출된다.

- WinMain내의 메시지 루프는 메시지를 메시지 처리 함수로 보내주기만 할 뿐이며 WndProc은 메시지가 입력되면 윈도우즈에 의해

  호출되어 메시지를 처리한다.

- 운영체제에 의해 호출되는 응용 프로그램내의 함수를 콜백(CallBack) 함수라고 한다.

- 메시지 큐에 쌓이지 않고 곧바로 윈도우 프로시저에 전달되는 것은 ?
  • 대기 메시지와 비대기 메시지

    • 대기 메시지는 메시지 큐에 쌓인 메시지를 윈도우 프로시저에 전달하고 비대기 메시지는 윈도우즈가 직접 윈도우 프로시저에 전달함.

    • 대기메시지 : 주로 사용자의 행위로 인한 결과(WM_KEYDOWN, WM_LBUTTONDOWN 등)

    • 비대기메시지 : 특정 윈도우즈 함수를 호출함으로써 종종 발생한다.

      1. CreateWindow() 호출하면, 윈도우를 생성하고 그 과정에서 윈도우 프로시저에 WM_CREATE 메시지를 보내다.
  • 윈도우 함수 호출

  • GetStockObject() 그래픽 객체를 얻는다.

  • RegisterClass() 프로그램의 윈도우를 위한 윈도우 클래스를 등록한다.

  • ShowWindow() 윈도우를 화면에 표시한다.

  • UpdateWinow() 윈도우가 자기 자신을 그리도록 명령한다.

  • GetClientRect() 윈도우의 클라이언트 영역 치수를 얻는다.

  • PostQuitMessage() : 메시지 큐에 종료(quit) 메시지를 삽입한다.

  • DetWindowProc() : 메시지에 대한 디폴트 처리를 담당한다.

  • 새로운 데이터 타입

    • MSG : 메시지 구조체

    • WNDCLASS : 윈도우 클래스 구조체

    • PAINTSTRUCT : 그리기 구조체

    • RECT : 직사각형 구조체

  • 핸들( 단순히 숫자(흔히 32비트 크기)로서 객체를 참조한다.

    • HINSTRANCE : 프로그램 자체 인스턴스 핸들

    • HWND : 위도우 핸들

    • HDC : 디바이스 컨텍스트 핸들.

  • 헝가리안 표기법

  • 윈도우 클래스 등록하기(RegisterClass(&wndclass) // WNDCLASS wndclass;

  • 애플리케이션 윈도우를 생성하려면 우선 RegisterClass()를 호출함으로써 윈도우 클래스를 등록해야한다.

  • WNDCLASS ASCII 버전

typedef struct tagWNDCLASSA { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; } WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;

  • 10개의 필드를 초기화 한후 RegisterClass()를 호출함.
  1. 2번째 필드(lpfnWndProc)

    • WndProc을 윈도우 클래스의 윈도우 프로시저로 설정한다.

    예) wndclass.lpfnWndProc = WndProc

    • WndProc은 이 윈도우 클래스를 기반으로 생성한 모든 윈도우에 전달되는 메시지를 처리한다.
if(!RegisterClass(&wndclass))
{
  MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);

  return 0;
}

//프로그램 컴파일시 UNICODE 식별자를 정의하고 WINDOWS NT계열에서 RegisterClassW() 구현되어 있어서 돌아감.

// 하지만 Windows 0x 계열에서는 RegisterClassW() 구현안되므로 위에 코드처럼 사용자에게 알려주고 0을 리턴하게 함.

  • 윈도우 생성하기
  • 윈도우, 윈도우 클래스의 차이

예) 푸시 버튼 윈도우 공통된 윈도우 클래스와 연관된 윈도우 프로시저는 윈도우즈 내부에 존재함.

    동일한 동작에 대한 정의 : 윈도우 프로시저/ 문자열, 화면위치 변경 등 이런 특성은 윈도우 정의에 일부분으로 설정
hwnd = CreateWindow(szAppName, //생성하고자 하는 윈도우의 클래스를 지정하는 문자열
  TEXT("The Hello Program"),
  WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  NULL,
  NULL,
  hInstance,
  NULL);

-CreateWindow는 HWND 타입에 윈도우 핸들을 리턴하고 프로그램들은 핸들을 이용하여 윈도우를 참조할 수 있다

  • 윈도우 표시하기

ShowWindow(hwnd, iCmdShow); : 윈도우가 화면에 드러나게 한다.

  1. hwnd : CreateWindow()로 방금 생성한 윈도우 핸들

  2. iCmdShow : 초기에 윈도우가 화면에 떠허게 표시될지를 결정함(정상, 최소화, 최대화 중 하나)

  3. 윈도우 클래스에 지정한 배경 브러시로 윈도우 클라이언트 영역 지워짐

  • ShowWindow() ,UpdateWindow() 차이점
  1. 같은 점 : WM_PAINT 메시지를 윈도우 프로시저로 보냄

  2. 다른 점 : UpdateWindow를 메시지 큐에 저장하지 않고 바로 윈도우 프로시저로 보냄으로써 윈도우를 빠르게 화면에 출력하게 함.

            과거에는 컴퓨터 처리속도가 느려서 ShowWindow 하나만 했을 경우에 느리게 나오는 문제가 있어서 UpdateWindow를 쓰게
    
            되었지만 현재는 컴퓨터 속도이 빨라져서 안써도 상관은 없다.
  • 메시지 루프
  1. 윈도우즈는 현재 수행되고 있는 각 윈도우즈 프로그램마다 ‘메시지 큐’를 유지한다.

    -입력 이벤트가 발생시 윈도우즈는 이벤트를 ‘메시지로 바꾸어 프로그램의 메시큐에 저장해 둔다.

typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time; // 메시지가 메시지 큐에 들어간 시간
POINT pt; // 메시지가 메시지 큐에 들어갈때 좌표.
} MSG, *PMSG, NEAR *NPMSG, FAR \*LPMSG;
  1. GetMessage(&msg, NULL, 0, 0) : 메시지 필드가 WM_QUIT이 아니라면 0이 아닌 값을 리턴함. 맞다면 0을 리턴해서 메시지 수신을

                                                못하게 함.
  • MSG 구조체 타입 변수인 msg의 포인터를 윈도우즈에 넘겨준다.

  • 윈도우즈는 메시지 큐로부터 메시지를 꺼낼 올 때마다 메시지 구조체의 각 필드를 채운다.

    ● hwnd : 메시지가 향할 윈도우를 나타내는 핸들.

    ● message : 메시지 식별자로서, 메시지를 나타내는 숫자이다. 예) 마우스 왼쪽을 누를시 WM_LBUTTONDOWN 이 된다.

  1. TranslateMessage(&msg)
  • msg 구조체를 윈도우즈에 넘겨서 키보드 메시지 변환을 한다.

  • WM_KEYDOWN인지와 눌려진 키가 문자키인지 검사하고 조건이 맞을경우 메시지큐에 WM_CHAR 메시지를 만들어서 붙인다.

  1. DispatchMessage(&msg)
  • msg 구조체를 윈도우즈에 넘기고 윈도우즈는 이 메시지를 적절한 윈도우 프로시저에 보내서 처리하도록 한다.

    이것은 윈도우즈가 윈도우 프로시저를 호출한다는 것이다.

WndProc가 리턴을 해야지 DispatchMessage도 리턴하게 되고 그 이후에 GetMessage로 넘어가게 됨

  • 윈도우 프로시저
  • 윈도우가 클라이언트 영역에 표시하는 내용과 사용자의 입력에 대한 반응을 결정하는 것을 말한다.

  • MSG 구조체의 처음 필드 네개와 동일하다.

  • 프로그램이 간접적으로 자신의 윈도우 프로시저를 호출하기 위해서 SendMessag를 사용할 수 있다.

  • 메시지 처리하기
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch(message)
  {
    case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  }
  return DefWindowProc(hwnd, message, wParam, lParam);
}
  • 윈도우 프로시저가 받는 모든 메시지는 숫자로 확인할 수 있는데, 이 숫자는 message 매개변수에 전달된다.

  • 윈도우 프로시저가 처리하지 않기로 한 메시지는 윈도우즈 함수인 DefWindowProc에 전달해서 디폴트로 처리되도록 해야한다.

  • WM_PAINT 메시지

    • 윈도우의 클라이언트 영역 일부 또는 전체가 ‘무효’ or ‘갱신’되어야 함을 프로그램에 알리는 역할을 한다.

    • 윈도우가 처음 생성될 때는 프로그램이 화면에 아무것도 그리지 않은 상태이므로 클라이언트 영역 저네가 무효화된다.

    • WinMain() : ShowWindow, UpdateWindow를 호출시 윈도우 프로시저에 지시하여 클라이언트 영역에 무언가를 그리게 한다.

    예) hdc = BeginPaint(hwnd, &ps);

      EndPaint(hwnd, &ps);
    • BeginPaint()를 호출했을 때, 윈도우즈는 클라이언트 영역이 아직 지워지지 않았을 경우, 클라이언트 영역의 배경을 지운다.

      배경을 지울 때는 윈도우 클래스를 등록할 때 WNDCLASS 구조체의 hbrBackground 필드로 지정한 브러시를 사용함.

      현재, wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 이므로 흰색으로 칠하게 된다.

    • BeginPaint() 호출은 전체 클라이언트 영역을 유효화하고, 디바이스 컨텍스트 핸들을 리턴한다.

    • 디바이스 컨텍스트 : 물리적 출력 장치와 관련 디바이스 드라이버를 통틀어서 나타내는 개념으로 윈도우의 클라이언트 영역에

      텍스트와 그래픽을 출력하기 위해서 디바이스 컨텍스트 핸들이 필요하다.

    • EndPaint()는 디바이스 컨텍스트 핸들을 해제하여 더 이상 유효하지 않게 한다.

  • WM_DESTROY 메시지

    • 윈도우즈가 사용자에 명령에 따라 윈도우를 파괴하는 중임을 나타낸다. (종료버튼, 시스템 메뉴 - 닫기)

    • PostQuitMessage(0) -메시지 큐에 WM_QUIT 메시지를 삽입

    • return msg.wParam -PostQuitMessage() 에 넘겨준 값(보통 0)이 그대로 들어 있다.

  • WM_SYSCOMMAND, WM_CLOSE, WM_DESTROY

  1. WM_SYSCOMMAND : 창 사용자 (시스템 또는 컨트롤 메뉴 라고도 함)는 창 메뉴에서 명령을 선택 하는 경우에 메시지를 수신 또는

                                최대화 단추를 선택 하는 경우 최소화 단추, 복원 단추, 닫기 단추 -매개변수에 SC_CLOSE 호출될 경우
  2. WM_CLOSE : 윈도우가 닫히기 전에 메시지가 전달 된다. 아직 윈도우가 파괴된 것은 아니므로 윈도우가 파괴되는 것을

                     중간에 제어 할 수 있다. -DestroyWindow() 호출(윈도우 프로시저 : WM_DESTROY 호출)
  3. WM_DESTROY : 윈도우가 메모리에서 파괴될 때 발생한다. -PostQuitMessage() 호출함으로써 메시키큐에 WM_QUIT 넣고

  4. WM_QUIT : 프로그램을 끝낼 때 발생하는 메시지이다. -WinMain()의 메시지 루프가 종료되고 프로그램이 끝난다.

텍스트 출력

  • WM_PAINT()
  • UpdateWindow() 메시지는 클라이언트 영역을 다시 그려야 함을 윈도우 프로시저에 알린다.
  • 윈도우 프로시저는 다음과 같은 이벤트 중 하나가 발생하면 WM_PAINT 메시지를 처리한다.

    • 사용자가 윈도우를 이동하거나 드러냄으로써 이전에 가려진 윈도우 영역이 드러날때.

    • 사용자가 윈도우의 크기를 조정할 때(윈도우 클래스 스타일에 CS_HREDRAW, CS_VREDRAW 비트 설정했을 때)

    • 프로그램에서 ScrollWindow() 또는 ScrollDC()를 사용하여 클라이언트 영역의 일부를 스크롤할 때

    • 프로그램에서 InvalidateRect() 또는 InvalidateRgn()을 사용하여 명시적으로 WM_PAINT 메시지를 생성할 때

  • WM_PAINT 메시지를 큐에 넣는경우

    • 윈도우 위에 놓여 있는 대화상자나 메시지 상자를 윈도우즈가 제거할 때

    • 메뉴가 열렸다가 닫혔을 때

    • 툴 팁(tool tip)이 표시될 때

  • GDI 개요

  • 윈도우의 클라이언트 영역에 무언가를 그리기 위해서는 윈도우즈의 그래픽 장치 인터페이스(Graphics Device Interface,GDI) 함수사용
  • 디바이스 컨텍스트
  • 디바이스 컨텍스트 핸들은 윈도우가 GDI 함수를 사용하기 위한 일종의 허가증이라고 할 수 있다.

  • CreateDC() 호출로 생성한 디바이스 컨텍스트를 제외하고는, 메시지 한 개를 처리할 때 얻은 디바이스 컨텍스트 핸들을 저장해

    두었다가 다른 메시지를 처리할 때 사용해서는 안된다.

  • 디바이스 컨텍스트 핸들 얻기: 1번째 방법
  • BeginPaint(), EndPaint()

    1. BeginPaint는 무효 영역의 배경을 지움으로써, 그리기 위한 준비를 한다. Return 값은 디바이스 컨텍스트 핸들이다.

    2. WM_PAINT 메시지를 처리하는 동안 반드시 BeginPaint(), EndPaint()를 쌍으로 호출해야함.

  • WM_PAINT(), 메시지를 처리하지 않는 경우 메시지를 DdfWindowProc()에 전달해야함.

case WM_PAINT:

 BeginPaint(hwnd, &ps);

 EndPaint(hwnd, &ps);

 return 0;
  • InvalidateRect() 호출함으로써 클라이언트 영역의 직사각형을 무효화한다면, 마지막 인자로 배경을 지울지 여부를 지정함.

    TRUE : 배경을 지움 / 배경을 지움, FALSE : 배경을 지우지 않음

  • 디바이스 컨텍스트 핸들 얻기 : 2번째 방법

    • GetDC(), ReleaseDC()

      1. GetDC(), RelaseDC()도 쌍으로 호출해야 한다. 메시지를 처리하는 동안 GetDC() 호출된다면 윈도우 프로시저 탈출하기 전에

        반드시 ReleaseDC()를 호출해야한다.

    hdc = GetDC(hwnd);

    ReleaseDC(hwnd, hdc);

  • GetDC(), GetWindowDC() 차이점

    ● GetDC()는 윈도우 클라이언트 영역에 출력할 수 있는 /GetWindowDC() 윈도우 전체에 출력할 수 있는

                    디바이스 컨텍스트 리턴                               디바이스 컨텍스트 핸들 리턴 - 윈도우타이틀바 출력가능
  • BeginPaint(), EndPaint() / GetDC(), ReleaseDC() 차이점

    1. BeginPaint, EndPaint는 WM_Paint 메시지를 처리할 때 사용한다. / GetDC, ReleaseDC는 WM_Paint 메시지 이외의 처리

                                                                                             클라이언트 영역 일부를 그릴 때
    2. WM_PAINT 메시지 루틴에서만 사용 : BeginPaint, EndPaint / DC핸들 얻기 위한 일반적인 방법 : GetDC, ReleaseDC

      ( 메시지 내에서 그림 그리기 위한 전문적인 함수)

    3. BeginPaint, EndPaint 호출하면 무효영역-유효화 됨 / GetDC, ReleaseDC는 무효 영역을 유효화하지 않음

                                                                              하려면 ValidateRect(hwnd, NULL) 호출해서 영역전체 유효화
    4. BeginPaint, EndPaint 얻은 디바이스 컨텍스트 핸들의 / GetDC로 얻은 디바이스 컨텍스트 핸들의 디폴트 클리핑 영역은

      디폴트 클리핑 영역은 무효영역 클라이언트 영역이다.

    • 클리핑 영역 : 화면에 보이는 가시영역
  • TextOut() 세부사항<TextOut(hdc, 100, 100, TEXT(“HI”), 2);

    1. 첫번째 인자는 GetDC(), BeginPaint()의 호출하여 얻은 리턴값

    2. 2~3번째는 문자열이 출력될 좌표, 4번째는 문자열, 5번째는 문자열의 길이 -TextOut 함수는 널 종료문자열을 사용하지 않음.

                                                                                                    아스키제어(\n, \0등) 사용시 상자나 채워진 블록모양출력
  • 문자 정렬방법 - SetTextAlign(HDC hdc, UINT fMode) : 예) SetTextAlign(hdc, TA_CENTER);

  • 글자크기

  • 텍스트의 치수를 알아내려면, 디바이스 컨텍스트 핸들을 얻은 후 GetTextMetrics() 호출한다.

    TEXTMETRIC tm;

    hdc = GetDC(hwnd);

    GetTextMetrics(hdc, &tm);

    ReleaseDC(hwnd, hdc);

  • TEXTMETRIC 구조체는 디바이스 컨텍스트에 현재 선택된 포트에 관한 다양한 정보를 제공한다.

  • 시스템 폰트의 치수는 윈도우즈를 다시 부팅되기 전까지는 변하지 않으므로, GetTextMetrics 사용 위치는 윈도우

    프로시저에서 WM_CREATE 메시지를 처리할 때 사용하는게 가장 좋은 위치이다.

  • GetSystemMetrics

Windows 응용 프로그램 프로그래밍 인터페이스 (API) 함수 GetSystemMetrics()를 사용 하 여 너비 및 높이 창 디스플레이의 다양한 요소의 얻을 수 있습니다.

예) int x = GetSystemMetrics(SM_CXSCREEN); Width of screen int y = GetSystemMetrics(SM_CYSCREEN); Height of screen

  • 클라이언트 영역 크기
  • GetSystemMetrics(), GetClientRect(), WM_SIZE에 lParam이용

  • WM_SIZE : 윈도우의 크기가 변경될때 윈도우 프로시저에 WM_SIZE 메시지를 보낸다.

    cxClient = LOWORD(lParam);

    cyClient = HIWORD(lParam);

  • 스크롤 바
  • 윈도우 스타일 식별자인 WS_VSCROLL, WS_HSCROLL 을 CreateWindow() 세번째 인자에 포함시키면 생성됨.

  • 스크롤바가 차지하는 공간은 클라이언트 영역에 포함안됨

  • 수직 스크롤바의 폭, 수평 스크롤바의 높이는 GetSystemMetrics 호출로 가능하다.

  • SetScrollRange : 스크롤 바의 범위, setScrollPos : 스크롤 바의 위치

그리기 기초

  • GDI(Graphics Device Interface) : 비디오 디스플레이와 프린터에 그래픽을 표시하는 역할을 하는 서브시스템
  • 윈도우즈의 그래픽은 GDI32.DLL 이 외부에 공개하는 함수에 의해 주로 처리한다.
  • GDI 함수 호출

    • 디바이스 컨텍스트 핸들

      1. WM_PAINT 메시지 처리 : BeginPaint, EndPaint / 그 외는 GetDC,ReleaseDC
    • GetTextMetrics : 현재 선택된 폰트의 치수 정보를 얻기 위해서

    • TextOut : 클라이언트 영역에 텍스트를 표시 / 텍스트 색상 변경 : SetTextColor

    • SetTextAlign : 텍스트 시작 위치 정렬

    • CreatePen, CreatePenIndirect, ExtCreatePen : 펜의 여러 속성 지정함.

  • 디바이스 컨텍스트

    • 프로그램이 DC를 얻는다는 것은 장치를 사용할 수 있도록 윈도우즈가 허가한다는 뜻이다.

    • 디바이스 컨텍스트는 많은 속성들을 포함하고 있어서 TextOut 호출시 속성 관련 세팅을 하지 않아도 DC에 속성을 따르게 되는 것이다.

      변경하고 싶으면 속성 변경하는 함수를 호출하면 된다.

  • 디바이스 컨텍스트 핸들 얻기

    1. 비디오 디스플레이의 특정 윈도우와 연관된 디바이스 컨텍스트를 얻기 위해사용(BeginPaint, GetDC, GetWindowDC)
    • BeginPaint,EndPant에 PAINTSTRUCT 구조체에 3번째 인자 rcPaint 필드가 있어서 윈도우 클라이언트 영역에서 무효 영역을

      둘러싸는 직사각형을 정의함.

    • GetDC, ReleaseDC() : 윈도우 클라이언트 영역에 적용

    • GetWindowDC, ReleaseDC : 윈도우 전체에 적용되는 디바이스 컨텍스트 핸들을 얻을 수 있다.

      이 디바이스컨텍스는 클라이언트 영역,윈도우 타이틀바, 메뉴, 스크롤바, 프레임을 포함.

    1. 디바이스 컨텍스트 핸들을 얻기 위한 다른 방법
  • CreateDC() : 특정 장치에 대 한 장치 컨텍스트를 만듭니다.

  • CreateIC() : 특정 장치에 대한 정보 컨텍스트를 만듭니다.이 디바이스 컨텍스트를 만들지 않고 해당 장치에 대한 정보를 빠르게 제공

  • CreateCompatibleDC(hdc) : 다른 장치 컨텍스트와 호환되는 메모리 디바이스 컨텍스트를 만듭니다. 메모리에 이미지를 준비하기위해

  • CreateMetaFile : GDI 호출은 화면에 표시되지 않지만 메타피일의 일부로 저장된다.

    -메타파일 : 다른 파일을 설명하거나 정의하는 정보를 담고 있는 파일(GDI 함수포함, 벡터방식 : 화면깨짐이 없다.)

  • 디바이스 컨텍스트 정보 얻기

    • GetDeviceCaps : 물리적 디스플레이 장치(비디오 디스플레이, 프린터 등)에 대한 정보를 얻을 때 쓰인다.

      GetDeviceCap(hdc, iIndex) - hdc가 화면 디바이스 컨텍스트 핸들이면, GetSystemMetrics와 정보가 동일하다

      iIndex - WINGDI.H 파일에 명시
      1. GetDeviceCaps(hdc, HORZRES); GetDeviceCaps(hdc, VERTRES);

      2. GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) 인자 사용시 동일하다.

  • 색상에 대해서 알아보기

  • GetDeviceCaps을 사용하면 장치가 다양한 종류의 그래픽을 처리할 수 있는 능력이 있는지 여부를 결정할 수 있다.

    • GetDeviceCaps(hdc, PLANES) : 색상 편면의 개수 / GetDeviceCaps(hdc, BITSPIXEL) : 픽셀당 색상 비트수

      GetDeviceCaps(hdc, NUMCOLORS) : 비디오 카드에서 동시에 표시할 수 있는 색상 수

  • COLORREF : GDI 함수 호출에서는 특정 색상을 참조할 때 사용함. #define DWORD COLORREF

    COLORREF의 원색 값을 추출 할때 GetRValue, GetGValue, GetBValue 매크로를 사용

  • GetNearestColor - 디더링(혼합)을 사용함으로써 실제 장치가 표시할 수 있는 색상보다 많은 색상을 표현함.

  • 디바이스 컨텍스트 속성

    • 윈도우즈는 디바이스 컨텍스트를 사용하여 ‘속성’을 저장함으로써 GDI 함수가 화면에 작동하는 방식을 좌우한다.

    • 프로그램이 디바이스 컨텍스트를 얻으면, 윈도우즈는 모든 속성을 디폴트 값으로 설정함.

  • 디바이스 컨텍스트 저장하기

    • GetDC(), BeginPaint() 호출 -모든 속성을 디폴트로 설정한 DC 리턴

    • ReleaseDC(), EndPaint() 호출 -DC해제, 수정한 모든 속성값은 사라짐

    • 속성값을 미리 변경 : 윈도우 클래스 등록때 스타일로 포함시킴

    • SaveDC, RestoreDC : DC 속성 변경 후 다시 그전 DC 상태로 변경시 사용함.

      idSaved = SaveDC(hdc); // SaveDC(hdc);

      RestoreDC(hdc, idSaved); // 리턴값 저장 시 // RestoreDC(hdc, -1); // 가장 최근에 SaveDC() 저장한 상태로 DC 복원

  • 직선

  • Polyline(), PolylineTo() 일련의 연결된 직선을 그린다.

    Polyline, PolylineTo 다른점

    1. Polyline은 현재 위치를 사용하지도 변경하지도 않는다.

    2. PolylineTo : 현재 위치를 시작 위치로 사용하고 마지막으로 그린 선의 끝점으로 현재 위치를 이동시킨다.

    Polyline, LineTo

    LineTo를 여러번 호출하면 플로터나 혹은 다른 그리기 모드에서 출력 결과가 보기 좋게 안나오고, 또한 Polyline을 이용시 쉽게 선을

    그릴 수 있다.

  • MoveToEx(hdc, xBeg, yBeg, NULL) : DC에 속성 중 현재 위치 값을 설정함. 마지막 인자는 이전의 현재 위치값을 POINT로 담아둔다.

  • LineTo(hdc, xEnd, yEnd); 현재 위치에서 이낮로 지정한 점까지 직선을 그린다.

  • GetCurrnetPositionEx(hdc, &pt) : 현재 위치 값을 구해줌.(MoveTo로 현재의 위치를 변경가능)

  • 경계 상자 함수 : 직사각형 형태의 “경계 상자”로부터 만들어진다는 점
  • Rectangle() 직사각형을 그리는 것

  • Ellipse() : 타원을 그리는 함수

  • RoundRect() : 모서리가 둥근 직사각형

  • Arc : 호는 채워진 영역이 아니라 타워 곡선, Pie : 윈도우즈는 호의 양 끝점과 타원의 중심을 선으로 연결한다.

  • Chord, Pie로 그린 그리믜 내부에 현재 브러시로 채워진다.

  • 곡선
  • Bezier(HDC hdc, CONST POINT* lppt, DWORD cPoints);

  • 곡선의 시작점과 끝점 그리고 두 개의 조절점으로 구성된 배열을 두 번째 인수로 넘겨주고 세번째 인수 cPoints에 점의 개수를 주면

    곡선이 그려진다.

  • 곡선하나를 그리는데는 4개의 점이 필요하지만 두 개 이상의 곡선을 그릴때는 다음 공식만큼의 점이 필요하다.

    =필요한 점 = 그려질 곡선 수*3 +1

  • 내장 펜 사용하기
  • 내장 펜 중 하나에 대한 핸들을 얻으려면 GetStockObject()를 호출한다.

    hPen = GetStockObject(WHITE_PEN);

  • 디바이스 컨텍스트에 펜을 선택해야한다.

hPen(이전 디바이스컨텍스트) = SelectObject(hdc, hPen);

=한 문자으로 요약가능 SelectObject(hdc, GetStockObject(WHITE_PEN))

  • 펜 생성, 선택, 삭제
  • 펜과 같은 GDI 객체를 사용할 때는 세 가지 규칙을 지켜야 한다.
  1. 생성한 모든 GDI 객체는 결국 삭제해야한다.

  2. 유효한 디바이스 컨텍스트에 선택되어 있는 GDI 객체는 삭제해서는 안된다.

CreatePen - // hPen = SelectObject // SelectObject(hdc, hPen) // DeleteObject

  1. 내장 객체는 삭제해서는 안되다.
  • 펜 생성(CreatePen, SelectObject, DeleteObject)

  • CreatePen, CreatePenIndirect (논리펜 생성)

  1. CreatePenIndirect에서 서로 다른 펜을 직접 초기화하여 사용할 경우 더욱 효과적이다.(LOGPEN 구조체를 이용)
  • LOGPEN 구조체 값을 얻어올 수 있다.
  1. GetObject(hPen, sizeof(LOGPEN), (LPVOID)&logpen);
  • 현재 선택된 펜 핸들이 필요하다면 다음과 같이 호출하면 된다.
  1. hPen = GetCurrentObject(hdc, OBJ_PEN);
  • 틈새 채우기
  • SetBkColor(hdc, crColor) // GetBKMode : 배경 모드를 얻을때 쓰임

    틈새를 채우기 위해서 배경색상을 바꿀때 사용함. 배경모드를 TRANSPARENT로 변경시 틈색을 채우지 않고 또한 배경색상을 무시한다.

  • 그리기 모드

    • 윈도우즈가 선을 그리기 위해 펜을 사용할 때는 실제로 펜의 픽셀과 목적지 화면의 픽셀 사이에 비트별 Boolean 연산을수행함.

      여기서 픽셀은 펜과 하면의 색상을 결정함. 픽셀에 대해 비트별 부울 연산을 수행하는 것을 ‘래스트 연산’ 혹은 ‘ROP’라 한다.

  • 채워진 영역에 그리기

  • 윈도우즈는 여섯개의 내장 브러시를 정의함(WHITE_BRUSH,BLACK_BRUSH,NULL_BRUSH,LTGRAY_BRUSH,DKGRAY_BRUSH,

                                                           GRAY_BRUSH)
  • 윈도우즈 브러시 핸들 : HBRUSH

    1. HBRUSH hBrush = GetStockObject(GRAY_BRUSH); //핸들을 얻을 수 있다.

    2. SelectObject(hdc, hBrush) // 디바이스 컨텍스트 선택

    3. SelectObject(hdc, GetStockObject(NULL_PEN)) // 경계가 없는 그림

    4. SelectObject(hdc, GetStockObject(NULL_BRUSH)) // 그림 경계 or 내부 채우지 않으려면

  • 다각형 함수와 다각형 채우기 모드
  • Polygon(hdc, apt, iCount) : 경계가 있고 내부가 채워진 그림을 그리는 여섯번째 함수

  • PolyPolygon(hdc, apt, aiCounts, iPolycount)은 여러개의 다각형을 그린다.

    1. 내부를 채우는 방식 : SetPolyFillMode(hdc, iMode) : iMode(ALTERNATE, WINDING)
  • 브러시로 내부 채우기

    • 윈도우즈는 논리 브러시 만들 수 있게 다섯개의 함수 제공

      1. CreateSolidBrush(COLORREF) : 특별한 Solid Color를 가지는 논리 브러시를 만들어준다.

      2. CreateHatchBrush(fnStyle, COLORREF) : 특별한 Hatch Pattern과 생상을 가지는 논리 브러시를 만들어준다.

      3. CreatePatternBrush(HBITMAP) : 특정 비트맵 패턴을 가지는 논리 브러시를 만들어준다.

      4. CreateDIBPatternBrush(HGLOBAL, UINT) : 장치 독립적인 특정 비트맵을 가지는 논리 브러시를 만들어준다.

      5. CreateBrushIndirect(LOGBRUSH) : 특별한 Hatch, Stype, Color 가지는 논리 브러시를 만들어준다ㅏ.

    typedef struct tagLOGBRUSH { UINT lbStyle; COLORREF lbColor; LONG lbHatch; } LOGBRUSH, *PLOGBRUSH, NEAR *NPLOGBRUSH, FAR *LPLOGBRUSH;

  1. SelectObject() : 디바이스 컨텍스트 선택
  • 장치 좌표계

    • 모든 장치 좌표계에서 단위는 픽셀로 표현한다.

    • 화면 좌표 : 전체 화면을 사용한다면 화면 좌표를 사용함.

      CreateDC() “DISPLAY” 인자를 사용한다면 GDI 함수의 논리 좌표는 디폴트로 화면 좌표에 매핑됨

    • 전체윈도우좌표 : 타이틀바, 스크롤바, 테두리 등을 포함한 프로그램의 애플리케이션 윈도우 전체를 나타낸다.

      GetWindowDC() 디바이스 컨텍스트를 얻으면 GDI 함수의 논리 좌표가 전체 윈도우 좌표에 매핑됨

    • 장치 좌표계 : 클라이언트 영역 좌표 // GetDC(), BeginPaint() 디바이스 컨텍스트를 얻으면 클라이언트 좌표로 변환됨

    • ClientToScreen() : 클라이언트 영역 좌표 -화면좌표 // ScreenToClient() : 화면좌표 -클라이언트 영역 좌표

  • 뷰포트와 윈도우

  • 매핑모드 : 윈도우(논리좌표)에서 뷰포트(장치좌표)로의 매핑을 정의

  • 뷰포트 지정 : 장치 좌표(Pixel) 사용한다.

  • 윈도우 지정 : 논리 좌표(피셀, 밀리미터, 인치등) 사용한다.

  • 장치점을 논리점으로 변환 - 논리점을 장치점으로 변환

    DPtoLP(hdc, pPoint, iNumber); LPtoDP(hdc, pPoint, iNumber)

    GetClientRect(hwnd, &rect);

    DPtoLP(hdc, (PPOINT)&rect, 2);

  • SetViewportOrgEx(hdc, xViewOrg, yViewOrg, NULL) 바꾸면 논리점(0, 0)은 장치점(xViewOrg, yViewOrg)에 매핑된다.

    SetWindowOrgEx(hdc, xWinOrg, yWinOrg, NULL) 바꾸면 논리점(xWinOrg, yWinOrg)는 장치점(0,0) 매핑된다.

    GetViewportOrgEx(hdc, &pt); / GetWindowOrgEx(hdc, &pt) // 현재의 뷰포트와 윈도우 원점을 얻을 수 있다.

  • 메트릭 매핑 모드

    • 윈도우는 논리 좌표를 물리적 치수로 표현(다섯개의 매핑모드 제공)

      1. MM_LOENGLISH/MM_LOMETRIC/MM_HIENGLISH/MM_TWIPS/MM_HIMETRIC
  • 사용자 정의 매핑모드

    • MM_ISOTROPIC과 MM_ANISOTROPIC은 뷰포트 범위와 윈도우 범위를 변경할 수 있는 유일한 매핑 모드이다.
  • 직사각형, 리전, 클리핑

  • 직사각형 작업하기

    1. FillRect(hdc, &rect, hBrush) : 지정한 브러시로 직사각형을 채운다.

    2. FrameRect(hdc, &rect, hBrush) : 브러시를 이용하여 직사각형 프레임을 그리지만, 내부를 채우지 않는다.

    3. InvertRect(hdc, &rect) : 직사각형 내의 모든 픽셀을 반전시킨다.(1->0 , 0->1)

  • Rect 구조체 조작할 수 있는 9개의 함수 제공

    1. SetRect(&rect, xLeft, xTop, xRight, Bottom) : Rect 구조체의 네 개의 필드를 특정 값으로 설정해줌

    2. OffsetRect(&rect, x, y) : x,y축 따라 일정 단위만큼 이동시킨다.

    3. InflateRect((&rect, x, y) : 직사각형의 크기를 증가 혹은 감소시킨다.

    4. SetRectEmpty(&rect) : 직사각형의 모든 필드를 0으로 설정한다.

    5. CopyRect(&DestRect, &SrcRect) : 한 직사각형을 또다른 직사각형에 복사한다.

    6. IntersectRect(&DestRect, &SrcRect1, &SrcRect2) : 두 직사각형의 교집합

    7. UnionRect(&DestRect, &SrcRect1, &SrcRect2) : 두 직사각형의 합집합

    8. bEmtyp = IsRectEmpty(&rect) : 직사각형이 비어 있는지 알려줌

    9. bInRect = PtInRect(&rect, point) : 점이 직사각형 내에 있는지 알려줌

  • 리전 생성과 그리기
  • 리전 : 사각형, 타원형, 다각형 등의 각종 도형으로 구성된 영역

  • CreateRectRgn(xLeft, yTop, xRight, yBottom) or CreateRectRgnIndirect(&rect); // 리전은 직사각형을 기술한다.

  • CreateEllipticRgn(xLeft, yTop, xRight, yBottom) or CreateEllipticRgnIndirect(&rect); // 타워형 리전

  • CreatePolyonRgn(&point, iCount, iPolyFillMode) iPolyFillMode : ALTERNATE or WINDING

  • CreatePolyPolygonRgn() 사용하면 여러개의 다각형으로 구성된 리전을 만들 수 있다.

  • CombineRgn(hDestRgn, hSrcRgn1, hSrcRgn2, iCombine)

    hSrcRgn1, hSrcRgn2 두 개의 리전을 합쳐 새로운 리전 hDestRgn을 만든다. iCombine은 결합방법을 지정한다.

    리턴값은 4개로 나뉘며(NULLREGION:비어있다/SIMPLEREGION:하나의 사각형으로 구성된 리전

                                /COMPLEXREGION:복수 개의 사각형 또는 곡선으로 구성된 리전/ERROR : 에러 발생)
  • 리전 핸들로 FillRgn, FramRgn, InvertRgn, PaintRgn 쓰이게 된다.

  • 직사각형과 리전으로 클리핑하기

    • invalidateRgn(hwnd, hRgn, bErase) : 클라이언트 리전 영역을 무효화시킨다.

      validateRgn(hwnd, hRgn) : 클라이언트 리전 영역을 유효화시킨다.

키보드

  • 키보드 기초
  • 키보드 입력은 메시지 형태로 프로그램의 윈도우 프로시저에 전달된다.

  • 특정 키보드 이벤트는 입력 포커스를 가진 윈도우를 받는다.(입력 포커스를 가진 윈도우에 키 이벤트가 전달됨)

  • 활성윈도우가 자식윈도우(리스트박스, 체크박스등) 가지고 있다면 자식 윈도우가 입력포커스를 가진다.

    자식윈도우가 활성윈도우는 아니라는 사실을 명심해야한다.

* 큐의 동기화

사용자가 키를 누르고 뗄 경우 -하드웨어 스캔 코드(디바이스드라이버) -시스템 메시지 큐 -애플리케이션 메시지 큐

  • 시스템 메시지 큐 -애플리케이션 메시지 큐

    윈도우의 포커스가 변경될 경우 시스템 메시지큐에 메시지를 다른 윈도우에 전달하기 위해서

* 키누름 메시지

  • WM_KEYDOWN, WM_KEYUP

  • WM_SYSKEYDOWN, WM_SYSKEYUP : Alt 키와 함께 눌러지는 키보드 메시지, 시스템의 내부적인 용도로 사용할 때 쓰임

                                                        이 메시지를 처리할 경우 반드시 DefWindowProc으로 이 메시지를 보내야 한다.
  • GetMessageTime()을 호출하면 키를 누르거나 뗐을 때의 상대적인 시간을 얻을 수 있다.

  • 가상 키 코드(wParam 확인)
  • 가상 키 코드는 wParam 매개변수에 저장되어 있다.

  • WINUSER.H에 VK_로 시작하는 이름으로 정의되어 있음.

  • lParam 정보(WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP)
  • 키누름을 해석하는데 유용한 부가 정보가 들어감.
  1. 반복카운트(0~15 : 16비트) : 키누름 메시지가 나타내는 키누름의 개수다.

  2. OEM 스캔코드(16~23 : 8비트) : 키보드 하드웨어가 발생시키는 코드

  3. 확장키 플래그(24) : IBM 확장 키보드에 있는 추가적인 키에 누름이 발생했을 1로 세팅

  4. 컨텍스트코드(29) : Alt키가 눌려져 있으면 1로 세팅

  5. 이전키상태(30) : 키를 이전에 뗀 상태라면 0이고, 키를 이전에 누른 상태라면 1이다.(KeyUp은 항상 1로 세팅됨)

  6. 전환상태(31) : WM_KEYDOWN : 0, WM_KEYUP : 1(키를 누르면 0, 키를 떼는 중이면 1)

  • 시프트상태(시프트키(Shift,Ctrl, Alt), 토클키(Caps Lock, NumLock) 눌렸는지 알기위해서)

    1. 리턴값(GetKeyState, GetAsyncKeyState)

0x8000 은 현재 키가 눌려진 상태를 뜻하고, 0x0001은 지난번 호출과 이번 호출사이에 키가 눌려진 적이 있었다라는 것을 뜻한다.

예) if( GetAsyncKeyState(VK_RETURN) & 0x8000 ) // 하는 이유는 정확한 시점에서 키의 상태를 확인하기 위해서

  • SHORT GetKeyState(int nVirtKey)
  1. GetKeyState 함수의 리턴값이 0x8xxx 경우에는 해당키가 눌린 상태이고,0x8xxx가 아닐 경우는 해당키가 눌리지 않은 상태이다.
  • GetAsyncKeyState / GetKeyState 다른점
  1. GetAsyncKeyState : 메시지큐와 상관없이 입력되는 순간 즉각적으로 읽어들여서 동작한다.

    GetKeyState: 메시지큐에 저장된 메시지에 따라 반환되는 값이 다르다.

  2. GetKeyState는 해당키가 눌렸으면 음수값(0xffffff80, oxffffff82) 아닐 경우 0을 반환, 이전에 누르고 호출시점에 안눌릴경우 1로 남는다.

  • 문자메시지
  1. GetMessage로 문자 메시지 - TranslateMesage : 키누름메시지(WM_KEYDOWN, WM_SYSKEYDOWN),

                                                                       Shift key(Shift, Ctrl, Alt), 토글키(Caps Lock, Num Lock, Scroll Lock)

    =메시지 큐에 WM_CHAR( 문자메시지를 넣게 된다)

  • 네 개의 문자 메시지
  • WM_KEYDOWN -WM_CHAR, WM_DEADCHAR

  • WM_SYSKEYDOWN -WM_SYSCHAR, WM_SYSDEADCHAR

  • WM_CHAR : wParam, lParam 인자 설명

    1. wParam : TCHAR str = (TCHAR)wParam -ANSI or Unicode 문자코드

    2. lParam : 키누름메시지(WM_KEYDOWN,WM_SYSKEYDOWN)의 lParam과 동일하다.

  • fUnicode = IsWindowUnicode(hwnd) -fUnicode 변수가 TRUE(유니코드 메시지)

  • GetKeyNameText() : 키보드 메시지, 키누름 메시지에 대해 가상 키 코드와 키 이름을 보여줄때 사용함.

  • 메시지순서

    • 문자메시지 : WM_KEYDOWN - WM_CHAR - WM_KEYUP

      WM_KEYDOWN 메시지로부터 TranslateMessage 호출되므로 WM_CHAR 사이에 끼게 된다.

  • 제어 문자 처리

  • WM_KEYDOWN : Insert, Shift, Ctrl, Alt 읽어야 할 경우

  • WM_CHAR : 키보드 문자 입력을 읽어야 할 경우

    Backspace, Tab, Escape, Enter : WM_CHAR 에서 미리 지정된 ANSI C 이스케이프로 구분해서 사용함.

case WM_CHAR:

if(wParam == ‘\b’) // if(wParam == ‘\t’)

  • 데드문자 메시지

    • 데드키란 단독으로 문자를 구성할 수 없는 키이며, 이키에 의해 발생된 데드 문자는 다음에 입력되는 문자와 조합되어 하나의 문자를

      만든다.

WM_KEYDOWN WM_DEADCHAR WM_KEYUP WM_KEYDOWN WM_CHAR WM_KEYUP

  • 캐럿
  • 프로그램에 텍스트를 입력할 때 일반적으로 작은 밑줄이나 수직 막대 혹은 상자가 나타나서 다음에 입력한 글자가 화면의 어느 위치에

    나타날지 알려준다.

    1. 커서 : 마우스 위치를 나타내는 작은 비트맵 이미지 - 캐럿과 다른 의미
  • 캐럿 관련 함수

  1. BOOL CreateCaret(HWND, HBITMAP, nWidth, nHeight)

  2. BOOL DestroyCatret(VOID)

  3. BOOL ShowCaret(hwnd) // 주기적으로 계속 깜박이며 다음 삽입 위치를 기다린다.

  4. BOOL HideCaret(hwnd)

  5. BOOL SetCaretPos(int X, int Y) : 캐럿의 위치를 지정(캐럿의 숨겨져 있어도 위치 변경가능)

  6. BOOL GetCaretPos(LPPOINT)

마우스

  • 마우스 기초
  • fMouse = GetSystemMetrics(SM_MOUSEPRESENT) : 마우스 존재 여부 검사(TRUE : 설치 O, FALSE : 설치 X)

  • cButtons = GetSystemMetrics(SM_CMOUSEBUTTONS) : 마우스의 버튼 수를 알려줌

  • SystemParametersInfo() : 더블 클릭 속도등 각종 마우스 파라미터를 직접 설정하거나 얻을 때 사용함.

  • 클라이언트 영역 마우스 메시지
  1. 키보드 메시지, 마우스 메시지 다른점
  • 키보드 메시지 : 입력 포커스(EditBox)를 가진 윈도우에게만 키보드 메시지를 보냄

  • 마우스 메시지 : 윈도우 위, 활성 x, 입력포커스를 가지고 있지 않은 경우에도 윈도우 프로시저는 마우스 메시지를 받는다.

  1. 마우스 위치값
  • x = LOWARD(lParam) / y = HIWARD(lParam)
  1. wParam : 마우스 버튼, Shift, Ctrl 키의 상태를 나타낸다.

MK_CONTROL, MK_LBUTTON, MK_RBUTTON, MK_MBUTTON, MK_SHIFT 조합키 상태를 알려줌.

  • 알게된 내용

    int ShowCursor(BOOL bShow);

    리턴값은 내부 카운트값으로서 TRUE일 경우에는 내부 카운트가 증가하고, FALSE일경우에는 내부 카운트가 감소한다.

    내부카운트가 0과 같거나 클 경우 화면에 커서가 보인다.

GetCursorPos(&point) // point 값은 스크린 좌표값이다. 클라이언트로 영역으로 바꿀경우 ScreenToClient 함수를 써야함.

SetCursorPos(x, y) //x ,y 값도 클라이언트 좌표가 아닌 스크린 좌표값이다.(클라이언트 좌표값이면ClientToScreent 함수를 이용해야함

  • 마우스 더블클릭

    • 윈도우 프로시저가 더블 클릭 마우스 메시지를 받기 원한다면, RegisterClass()를 호출하기 전에 윈도우 클래스 구조체의 style 필드를

      초기화 할때 CS_DBLCLKS 식별자를 포함한다.

  • 비클라이언트 영역 마우스 메시지

    • 윈도우 비클아이언트 영역 : 타이틀 바, 메뉴, 윈도우 스크롤 바를 포함한다.

    • 비클라이언트 영역 마우스 메시지는 DefWindowProc()에 전달하여 윈도우즈가 시스템 기능 수행하게 함.

      wParam : 마우스를 움직이거나 클릭한 곳이 비클라이언트 영역의 어느 부분인지 나타낸다.

      lParam : 하위워드(x) , 상위워드(y) -클라이언트 좌표가 아닌 스크린 좌표이다.

    예) xPos = GET_X_LPARAM(lParam); yPos = GET_Y_LPARAM(lParam);

타이머

타이머 CH8.타이머 / Windows 프로그래밍
2013. 4. 18. 20:33 수정 삭제 복사https://blog.naver.com/ssinga1030/90171478579 통계보기

  • 윈도우즈 타이머의 활용

    1. 멀티태스킹 : 많은 프로그램이 많은 양을 처리해야한다면, WM_TIMER 메시지를 받을 때마다 각 조각들을 처리가능

    2. 실시간 갱신 : 시스템 리소스 표시같은 끊임없이 변하는 정보를 타이머로 갱신한다.

    3. 자동저장 : 특정 주기에 맞게 사용자 작업을 저장한다.

    4. ‘데모’버전 프로그램 종료 : 데모버전 전달 후 일정시간이 지나서 종료하도록 설계한다.

    5. 움직임 속도 조절 : 자동으로 연속된 화면을 보여줄때 속도를 조절할 때.

    6. 백그라운드에서 작업중인 시각적인 정보를 갱신할 때 타이머를 사용

  • 시스템과 타이머

  • 윈도우는 사용자가 설정한 타이머의 카운트 값을 설정하고 하드웨어 타이머 틱이 발생 될때마다 카운트를 감소 시킨 후 0이 되었을 때

    WM_TIMER 메시지를 전달하고 다시 원래 카운트로 리셋한다.

  • 타이머 메시지는 비동기적이지 않다.
  • 자신의 프로그램이 WM_TIMER 메시지 처리를 위해 비동기적으로 중단되지 않는다.

  • WM_PAINT처럼 메시지 큐에 저장되어서 순차적으로 처리가 된다.

  • 타이머 사용
  1. 첫번째 방법
  • SetTimer(hwnd, 1, uiMsecInterval, NULL);

    1번째인자 : 윈도우 핸들, 2번째 인자 : 타이머의 번호, 3번째 인자 : 1/1000 타이머의 주기, 4번째 인자 : 콜백함수

    KillTimer(hwnd, 1) : 1번째 인자 : 윈도우 핸들, 2번째 인자 : 타이머의 번호

  • WM_TIMER

  1. 두번째 방법(콜백함수)
  • SetTimer(hwnd, 1, uiMsecInterval, TimerProc);

  • 윈도우즈가 타이머 발생시 함수를 호출 할 수 있게 해주는 것이다.

  • VOID CALLBACK TimerProc( HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime );

1번째 인자 : 윈도우 핸들/ 2번째 인자 : 항상 WM_TIMER / 3번째 인자 : 타이머 ID/4번째 인자 : 윈도우즈가 시작후 경과된 시간

  1. 세번째 방법
  • iTimerID = SetTimer(NULL, 0, wMsecInterval, TimerProc);

    1번째 매개변수 : hwnd 를 NULL/ 2번째 매개변수 무시한다(0) -함수의 리턴값이 타이머 ID가 된다.

  • KillTimer(NULL, iTimerID)

  • 현재시각 얻기

typedef struct _SYSTEMTIME { // st WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME;

  • GetLocalTime(LPSYSTEMTIME) : 표준시간대를 알려준다.(현재시간)

  • GetSystemTime(LPSYSTEMTIME) : 협정세계시(그리니치 시각)

자식 윈도우 컨트롤

  • 자식 윈도우 컨트롤

    • 자식윈도우에서 부모윈도우 핸들을 얻는 방법

      hwndParent = GetParent(hwnd)

    • 부모윈도우에 메시지를 보내는 방법

      SendMessage(hwndParent, message, wParam, lParam);

    • 자신윈도우 -부모윈도우

      자식윈도우(컨트롤) 자신에게 변화가 있을 경우(Button Click등) 부모 윈도우에게 WM_COMMNAD 통지 메시지를 보냄.

      이 메시지는 자식윈도우(컨트롤)가 기동했음을 알려준다.

      LOWORD(wParam) : 자식 윈도우 ID, HIWORD(wParam) : 알림코드, lParam : 자식윈도우의 핸들

  • 버튼 클래스

    • 오너드로우(Owner Draw)

      비트맵이나 도형이미지를 가지는 경우에는 컨트롤이 직접 비트맵을 출력하지 못하여 이때 컨트롤을 소유한 부모 윈도우가 비트맵을

      그려주는 방식을 오너드로우라고 말한다. 정리하면 컨트롤을 소유한 부모 윈도우가 내용물을 그려주는 형식을 말한다.

    • CreateWindow의 3번째 인자에 BS_OWNERDRAW 스타일을 추가하면 오너드로우 스타일을 적용하라는 의미이다.

      1. WM_MEASUREITEM : 항목의 높이를 지정

      2. WM_DRAWITEM : 자신이 그려야 한다는 사실을 메시지를 통해서 알려준다.

      lPamra : DRAWTIEMSTRUCT 구조체의 포인터가 들어 있다.

  • 오너드로우 사용하는 이유

    1. 리스트박스 자체는 또한 윈도우이다. 그러므로 문자열 추가시 WM_PAINT 호출되어서 출력이 되지만 그 외에 비트맵과 도형이미지

      가지는 경우에는 직접 비트맵을 출력하지 못하므로 부모윈도우에서 대신 그려줘야하는 경우

    2. 실시간으로 변경되는 정보를 표시할 때 항목을 수정하는 것보다는 오너 드로우로 구현하는 것이 편리한 경우

  • 자식윈도우 생성하기

CreateWindow { TEXT(“button), //클래스 이름

         TEXT("PUSHBUTTON);               // 윈도우 텍스트

                   WS_CHILD|WM_VISIBLE             // 윈도우 스타일

                   cxChar                                      // x위치

                   cyChar                                      // y위치

                   20*cxChar                                 // 폭

                   70*cyChar/4                             // 높이

                   hwnd                                       // 부모윈도우

                   (HMENU) i                                 // 자식윈도우 ID

                   ((LPCTREATESTRUCT) lParam)->hIstance  // 인스턴스 핸들

                   NULL                                        // 여분의 매개변수
  • 인스턴스 핸들을 얻는 방법 3가지

    • WM_CREATE시 :

      lParam에 CREATESTRUCT 형식의 구조체에 대한 포인터가 들어 있다.

    • 전역변수를 이용하는 방법

      hInst = hInstance;

    • LONG GetWindowLong(hwnd, GWL_HINSTANCE);

  • 인스턴스 핸들(HINSTANCE), 윈도우 식별자(핸들 - HWND), 컨트롤 ID

    1. 인스턴스 : 실행파일이 메모리상에 올라가 있는 시작주소를 의미한다.

      -실행중인 프로그램들을 구분하기 위한 식별값으로 인스턴스 핸들을 이용한다.

      -GetProcAddress 값이 다른 DLL에서 메모리에 올라간 함수주소를 얻을 경우 나오는 HMODULE과 동일하다.

    2. 윈도우 식별자 핸들(HWND)

      -해당 프로그램의 윈도우들을 구분하기 위한 식별값을 말한다. (부모윈도우, 컨트롤 윈도우 핸들등)

    3. 컨트롤 ID

      -컨트롤의 ID는 컨트롤간의 구분을 위해 사용하는 것이므로 한 부모 아래의 컨트롤끼리 중복되지 않는 ID를 가지기만 하면 된다

       내부적인 리소스로 관리됨.
  • ID값 얻는 방법

    id = GetWindowLong(hwndChild, GWL_ID);

    id = GetDlgCtrlID(hwndChild);

  • 윈도우 핸들 얻는방법(ID와 부모윈도우 핸들을 안다면)

hwndChild = GetDlgItem(hwndParent, id);

  • 자식 윈도우가 부모 윈도우에게 보내는 메시지(자식윈도우 생성시)
  • BN_CLICKED / BN_PAINT / BN_DISABLE 등

  • 자식윈도우에서 부모윈도우에 WM_COMMAND호출(BN_CLICKED) - SendMessage(hwndButton, BM_SETSTATE, TRUE, 0)

  • 부모 윈도우가 자식 윈도우에게 보내는 메시지
  1. BM_GETCHECK, BM_SETCHECK

    • 체크박스와 라디오 단추의 체크표시를 설정하기 위해서 보낸다.
  2. BM_GETSTATE, BM_SETSTATE

    • 한 윈도우를 마우스로 누르거나 Space Bar를 눌렀을 때의 상태를 의미한다.
  3. BM_SETSTYLE

    • 단추가 만들어진 후 단추의 스타일을 변경할 수 있게 한다.
  4. BM_CLICK, BM_GETIMAGE, BM_SETIMAGE

  • 푸시버튼

    • on/off 표시도 하지않고 곧바로 동작을 시작하기 위해서 주로 사용된다.

    • 푸시버튼이 누릴경우 BN_CLICKED인 WM_COMMAND 메시지를 부모 윈도우에 보낸다.

  • 체크박스(텍스트가 같이 표시된 정사각형 상자)

    • 체크박스에 체크표시 생성하려면 wParam : 1, 체크표시를 지우려면 wParam : 0

      SendMessage(hwndButton, BM_SETCHECK, 1, 0); - 체크표시 생성

      SendMessage(hwndButton, BM_SETCHECK, 0, 0); - 체크표시 삭제

      iCheck = (int)SendMessage(hwndButton, BM_GETCHECK, 0, 0); 버튼이 체크되면 TRUE, 그렇지 않으면 FALSE

  • 라디오 버튼

    SendMessage(hwndButton, BM_SETCHECK, 1, 0); - 체크표시 생성

    SendMessage(hwndButton, BM_SETCHECK, 0, 0); - 체크표시 삭제

  • 그룹박스

    • 다른 컨트롤과 달리 키보드, 마우스 입력 처리 x, 부모 윈도우에 WM_COMMAND 메시지도 보내지 않는다.
  • 버튼 텍스트 바꾸기

    • SetWindowText(hwnd, pszString)

      hwnd : 텍스트를 바꿀 대상 윈도우의 핸들, pszString : 널로 끝나는 문자열을 가리키는 포인터

    • iLength = GetWindowText(hwnd, pzxBuffer, iMaxLength); //현재 텍스트를 얻어온다.

    • iLength = GetWindowTextLength(hwnd) : 특정 텍스트 길이에 대비하려면 리턴반은 길이로 텍스트 버퍼를 할당한다.

  • 보이는 버튼과 활성화된 버튼

    • 자식 윈도우가 입력을 받으려면 화면에 표시되고 또한 활성화 되어야 한다.

      자식 윈도우 숨길경우 : ShowWindow(hwndChild, SW_HIDE)

      자식 윈도우 현재 보이는지 확인 : IsWindowVisible(hwndChild)

      자식 윈도우 활성화/비활성화 : EnableWindow(hwndChild, FALSE), EnableWindow(hwndChild, TRUE)

      자식 위도우 활성 여부 : IsWindowEnabled(hwndChild)

  • 버튼과 입력 포커스

  1. 부모윈도우 -자식윈도우 포커스 움직일경우

case WM_KILLFOCUS : ( 부모에 KILLFOCUS -wParam에 입력포커스를 얻은 자식윈도우 핸들이 들어가 있음

for( i=0; i< NUM; i++)

{

    if(hwndChild[i] == (HWND)wParam)

    {

SetFocus(hwnd)

break;

    }

}

  1. 자식 윈도우 -부모 윈도우 포커스 움직일경우

      case WM_KILLFOCUS:
    
      if(hwnd == GetParent((HWND)wParam)
    
      {
    
                  SetFocus(hwnd);
    
                  break;
    
       }
  • 시스템 색상

    • GetSysColor()와 SetSysColor()를 이용하면 이들 색상을 얻거나 설정할 수 있다.
  • WM_CTLCOLORBTN 메시지

    • 버튼 색상을 프로그램에서 우리가 선호하는 색상에 맞추는 방법으로 WM_CTLCOLORBTN 메시지를 처리한다.

      이 메시지는 자식 윈도우가 자신의 클라이언트 영역을 그리려고 할 때 윈도우 프로시저에게 보내는 것이다.

      부모 윈도우는 이 기회를 이용하여, 자식 윈도우 프로시저가 그리기에 사용할 색상을 바꿀 수 있다.

    1. wParam : 버튼의 장치 컨텍스트에 대한 핸들

    2. lParam : 버튼의 윈도우 핸들

    3. SetTextColor를 사용하여 텍스트 색상을 설정함

    4. SetBkColor를 사용하여 텍스트 배경을 설정함.

    5. 자식 윈도우에게 브러쉬 핸들을 반환한다.

  • WM_CTLCOLORBTN의 문제점

    푸시 버튼과 오너 드로우 버튼만 부모 윈도우에 WM_COTCOLORBTN 메시지를 보낼 수 있고, 부모 윈도우가 이 메시지를 처리하여

    배경을 칠할 브러시를 리턴한 경우, 오너 드로우 버튼만 이에 응답할 수 있다.

LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

switch (msg) {
    case WM_CTLCOLORSTATIC: {
        if ((HWND)lParam == filterNameOff) {
        static HBRUSH hBrushColor;

            if (!hBrushColor) {
                hBrushColor = CreateSolidBrush(RGB(0xFF, 0xFF, 0xFF)); // White background is returned
                SetBkColor((HDC)wParam, RGB(0xFF, 0xFF, 0xFF));          // White background for text
            }

            // Background color that is used to repaint the control (doesn't affect text background)
            return (LRESULT)hBrushColor;
        }
    }
  • 오너드로우 버튼

    1. CreateWindow의 3번째 인자에 BS_OWNERDRAW 스타일 추가

    2. BS_OWNERDRAW 스타일로 생성한 버튼은 자신이 다시 그려져야 할 때마다 부모 윈도우에 WM_DRAWITEM 메시지를 보낸다.

      버튼이 처음 생성될 때, 버튼을 누르거나 뗄 때, 입력 포커스를 잃거나 얻을 때, 즉 다시 그려질 때 WM_DRAWITEM 호출된다.

    3. lParam은 DRAWITEMSTRUCT 구조체를 가리키는 포인터.(버튼을 그리는데 필요한 정보가 들어있음)

      • hdc = 버튼의 디바이스 컨텍스트

      • rcItem = 버튼의 크기를 제공하는 Rect 구조체

      • CtlID = 컨트롤 윈도우 ID

      • itemState = 버튼이 눌렸는지 혹은 입력 포커스를 가지고 있는지 나타냄

        만약, 버튼이 눌려있으면 itemState 1로 세팅(ODS_SEELECTED) 상수를 이용하여 검사

  • 스태틱 클래스

    • 마우스, 키보드 입력을 받아들이지도 않고, 부모 윈도우에 WM_COMMAND 메시지를 보내지도 않는다.

    • 스태틱 자식 윈도우 위로 마우스를 옮기거나 클릭 시 자식 윈도우는 WM_NCHITTEST 메시지를 가로채고,

      HTTRANSPARENT를 윈도우에 반환한다.

    • SS_LEFT, SS_RIGHT, SS_CENTER를 포함하는 문자열 정렬

  • 스크롤바 클래스

    • 스크롤바는 부모 윈도우에 WM_COMMAND를 보내지 않는대신, WM_VSCROLL, WM_HSCROLL 메시지를 보낸다.

    • lParam 값 : 윈도우 핸들

      i = GetWindowLong((HWND)lParam, GWL_ID)

    • wParam

      nScrollCold = (int)LOWORD(wParam) // SB_PAGEDOWN, SB_LINEDOWN등

      nPos = (Short int)HIWORD(wParam) // SB_THUMPOSION, SB_THUMTRACK 발생시 Postion값을 변경할 수 있다.

  • 윈도우 서브클래싱

    • 현존하는 윈도우 프로시저에 끼어들어서 프로그램내에서 일부 메시지를 처리하고 나머지는 원래 윈도우 프로시저에 전달하기

      위해서 쓰인다.

    • 이유 : 몇개의 기능만 구현한 프로그램을 실행하고 나머지는 원래 프로시저로 넘기기 위해서 사용된다.

    예) OldScroll = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (LONG)ScrollProc);

    • 그 이후 CallWindowsProc()를 사용하여 이전의 스크롤 바 윈도우 프로시저를 호출하게 된다.
  • 배경 색칠하기

    • DWORD SetClassLong(HWND, int nIndex, LONG INewVal);

    =윈도우의 배경색 뿐만이 아니라 커서, 아이콘등을 윈도우 클래스에 등록한 것을 전부바꿀때 사용됨.

    • 반환값 : 성공시 - 이전 값이 지정된 32비트 정수, 실패시 : 0 이 리턴됨

예) SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB(color[0], color[1], color[2]));

  • 에디트 클래스

    1. 에디트 클래스 스타일

    hwndEdit = CreateWindow(TEXT(“edit”), NULL, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|

                                        WS_BORDER|ES_LEFT|ES_MULTILINE|ES_AUTOHSCROLL|ES_AUTOVSCROLL,
    
                                        0, 0, 0, 0, hwnd, (HMENU) 1, ((LPCTREAESTRUCT)lParam)->hInstance, NULL);
    1. 정렬 : ES_LEFT, ES_RIGHT, ES_CENTER

    2. 행 : 디폴트는 단일행 / 다중 행 MULTILINE

    3. 자동 수평/수직 스크롤 : ES_AUTOHSCROLL, ES_AUTOVSCROLL =끝까지 문자가 입력되었을 때 자동으로 수평/수직 스크롤이됨

    1. 에디트 컨트롤 통지
    1. LOWORD(wParam) : 자식 윈도우 ID

    2. HIWORD(wParam) : 통지코드

    3. lParam : 자식 윈도우 핸들

    • 통지코드

      ● EN_ERRSPACE : 에디트 컨트롤이 메모리 할당 할 수 없을 경우

      ● EM_MAXTEXT : 에디트 컨트롤에 텍스트를 삽입할 공간이 부족할 경우

      =위의 두개의 통지코드에 대한 처리를 해줘야 한다.

    1. 에디트 컨트롤에 보낼 수 있는 메시지
    1. 선택된 내용을 잘라내기 : SendMessage(hwndEdit, WM_CUT, 0, 0);

    2. 선택된 내용을 복사하기 : SendMessage(hwndEdit, WM_COPY, 0, 0); //삽입하기 WM_PASTE

    3. 선택된 내용을 삭제하기 : SendMessage(hwndEdit, WM_CLEAR, 0, 0);

  • 리스트박스 클래스

    1. 리스트 박스 스타일

    hwndList = CreateWindow (TEXT (“listbox”), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER| WS_VSCROLL | LBS_NOTIFY, 10, 20, 200, 300, hwnd, (HMENU) 2, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL) ;

    1) LBS_NOTIFY : 리스트 박스는 어떠한 일이 일어나도 통지 메시지를 보내지 않으므로 통지메시지 사용시 꼭 추가해야함.
    
                            쓰인이유 - 과거 컴퓨터 느릴 시 조금이라도 속도를 빠르게 하기 위해서 사용됨(WM_COMMAND로 받음)
    
    2) LBS_SORT : 리스트 박스내의 항목들을 정렬
    
    3) LBS_MULTIPLESEL, LBS_EXTENDEDSEL : 리스트 박스 디폴트 선택 타입은 단일 선택 타입이다 하지만 2개의 타입을
    
                                                                     추가해주면 다중 or 확장 선택 리스트 박스를 추가할 수 있다.
    
    4) LBS_STANDARD -LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER
    1. 리스트 박스 문자열
    1. 리스트 박스 리턴값

      • LB_ERRSPACE : SendMessage() 리턴이 LB_ERRSPACE는 내용을 저장할 메모리 공간이 부족할 때 리턴됨.

      • LB_ERROR : 다른 이유로 오류가 발생할 경우

      • 성공시 문자열이 추가된 위치의 인덱스 값을 리턴함.

    2. 리스트 박스 문자열 삽입

      • SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)szString);

        =4번째 인자는 널을 끝나는 문자열에 포인터값

          LBS_SORT 사용시 3번째 인자 0으로 세팅, 안할 경우 Index 값을 지정해줘야한다.
    3. 리스트 박스 문자열 삭제

      • SendMessage(hwndList, LB_DELETESTRING, index, 0)

        SendMessage(hwndList, LB_RESETCONTENT, 0, 0);

        차이점 : LB_DELETESTRING은 인덱스에 있는 문자열 삭제, LB_RESETCONTENT는 모든 항목을 제거하는 것이다.

    4. 리스트 박스 갱신

      • SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);

        SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);

      =리스트 박스 윈도우 프로시저는 항목이 추가되거나 삭제될 때 화면을 갱신한다. 막약 추가하거나 삭제할 문자열이 많은 경우

       컨트롤의 다시 그리기 플래그를 끔으로써 갱신 동작을 일시 금지 시키고 이후에 다시 동작시키게 할 수 있다.
      
       또한 스타일에 LBS_NOREDRAW 스타일을 추가할 경우 화면 갱신 플래그를 꺼진 상태로 시작할 수 있다.
    5. 리스트 박스 항목 선택, 빼기

      • 리스트박스 항목의 개수 : iCount = SendMessage(hwndList, LB_GETCOUNT, 0, 0);

      • 항복 선택 : SendMessage(hwndList, LB_SETCURSEL, iIndex, 0);

      • 시작 글자에 기반한 항목 선택 : iIndex = SendMessage(hwndList, LB_SELECTSTRING, iIndex, (LPARAM)szSearchString);

      • 현재 선택된 항목을 알고 싶을 경우 : iIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0);

      • 문자열의 길이 알기 위해서 : ILength = SendMessage(hwndList, LB_GETTEXTLEN, iIndex, 0);

      • 텍스트 버퍼에 저장 : iLength = SendMessage(hwndList, LB_GETTEXT, iIndex, (LPARAM)szBuffer);

      • 특정 항목의 선택 상태 설정 : SendMessage(hwndList, LB_SETSEL, wParam, iIndex);

      • 턱정 항목의 선택 상태 알기 위해 : iSelect = SendMessage(hwndList, LB_GETSEL, iIndex, 0);

    6. 리스트 박스로부터 메시지 받기

      • 자식윈도우 : LOWORD(wParam)

      • 통지코드 : HIWORD(wParam)

      • lParam : 자식 윈도우 핸들

      • WM_COMMAND 통지코드

        LBN_SELCHANGE : 현재 리스트 박스 선택이 변경됨을 알려줌.

  • 알게된 API

    GetEnvironmentVariable(lpName, lpBuffer, nSize) : 환경변수 이름 반환하기.

    =lpName : 환경변수 이름 / lpBuffer : 환경변수가 가지고 있는 정보를 반환하여 저장될 버퍼, nSize : 버퍼에 들어갈 최대 크기

메뉴와 그밖에 리소스

  • 아이콘, 커서, 문자열, 커스텀 리소스
  1. 리소스의 분리
  • 일반적으로 프로그램은 코드와 데이터로 구분됨

  • 코드 : 데이터를 처리하는 수단 / 데이터 : 코드가 아닌 모든 것을 데이터라고 지칭할 수 있음(비트맵, 메뉴, 아이콘 등)

  • 리소스란 : 코드의 논리와 무관한 데이터의 집합

  • 리소스와 코딩 과정이 분리시 장점

  1. 디자이너와 프로그래머가 분담하여 작업을 하기가 편리하다. 프로그래머는 열심히 프로그램의 논리를 만들고 디자이너는 리소스만

    예쁘게 만들어 결합시키면 되기 때문이다.

  2. 리소스를 수정하더라도 프로그램을 일일이 다시 컴파일하지 않아도 되므로 컴파일 속도가 현저히 빨라진다.

  3. 한번 만들어 놓은 리소스를 다른 프로젝트에 쉽게 가져다 쓸 수 있어 리소스의 재사용에 유리하다.

  4. 리소스는 교체가 가능한 모듈이므로 상황에 따라 다른 형태의 리소스를 사용할 수 있다.(다국어 버전, 스킨기능 등)

  5. RC파일 : 사용하고자 하는 리소스의 종류, 모양 등을 작성한 파일

  6. RES : RC파일을 리소스 컴파일러(RC.exe)로 컴파일 하면 RES라는 이진 파일이 생성됨.

-링크과정에서 obj, res 파일이 합쳐져서 .exe 실행파일이 생성됨.

  1. Resource.h : RC파일에서 지정한 Define된 값을 이용하여서 Resource.h파일을 그 리소스에 ID값을 부여함.

    예) *.rc : MENUITEM “&New”, ID_MENUITEM40020

      Resource.h  : #define ID_MENUITEM40020                40020

● 알게된 내용 - DISCARDABLE(윈도우즈가 (필요하다면) 추가적인 공간을 얻기 위해 리소스를 메모리에서 제거할 수 있음을 나타낸다.)

  1. 리소스를 만들고 프로젝트에 포함시키는 과정을 정리

  2. 프로그램에 아이콘 추가하기

  • 아이콘을 추가하기 위해서 insert/Resource 선택해서 Icon을 추가한다.

  • 리소스 폅집기에서 FileName과 ID값을 지정함. < *.rc파일과 resource.h 파일에 추가됨.>

-*.rc : IDI_ICON<IDICON DISCARDABLE “icondemo.ico”

  *.h :  #define IDI_ICON                        101
  • 아이콘 핸들 얻는 방법

    hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));

    HICON LoadIcon( HINSTANCE, LPCTSTR);

#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))

-정수타입의 리소스ID를 문자열 포인터에 대입할 수 없으므로 캐스팅을 할 때 쓰이는 매크로가 MAKEINTRESOURCE 이다.

  • 아이콘의 크기 얻는 방법(32 x 32 : Visual C++ 생성한 아이콘 크기)

    cxIcon = GetSystemMetrics(SM_CXICON);

    cyIcon = GetSystemMetrics(SM_CYICON);

    좀 더 작은 16x16 픽셀의 사이즈를 얻을 경우 XM_CXSMSIZE, SM_CYSMSIZE 쓰인다.

  • 아이콘을 그릴 때 : DrawIcon(HDC, x, y, HICON)

● LoadIcon(NULL, IDI_APPLICATION) - hInstance가 NULL 이므로 윈도우즈가 미리 정의된 아이콘임을 알려준다.

                                                      IDI_APPLICATION은 WINUSER.H 미리 정의되어 있다.

                                                      #define IDI_APPLICAION MAKEINTRESOURCE(32512)
  • 프로그램 실행중에 아이콘을 전환할 경우

    SetClassLong(hwnd, GCL_HICON, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ALTICON))

  • LoadIcon은 핸들을 얻지만 핸들을 파괴할 필요가 없다.

  1. 사용자 맞춤 커서 추가하기
  • 윈도우 클래스를 정의

    wndclass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));

    wndclass.hCursor = LoadCursor(hInstance, szCursor); - 커서를 텍스트 이름으로 정의

  1. 문자열 리소스
  • 문자열 리소스는 주로 프로그램을 다른 언어로 변환하는 것을 쉽게 하기 위해서 사용된다.

  • 문자열 테이블 생성

    insert/Resource - String Table 추가

  • LoadString(hInstance, id, szBuffer, iMaxLength)

    2번째 인자 : 각 문자열 앞쪽에 있는 ID값

    3번째 인자 : 문자열을 받을 버퍼의 주소, 4번째는 szBuffer로 옮길 문자의 최대 개수

    리턴 : 문자열에 들어 있는 문자의 개수를 리턴함.

  • 문자열 리소스는 최대 4K까지의 길이를 가질 수 있다.

  • 문자열 리소스 장점

  1. 우선 첫째로 문자열 자체가 코드와 분리됨으로써 문자열만 따로 관리할 수 있으며 프로젝트를 유지하는데도 큰 도움을 준다.
  1. 문자열 리소스를 사용하는 두번째 이점은 다국어 버전을 쉽게 만들 수 있다는 점이다

    3) 문자열이 소스와 분리되어 있으면 문자열을 고쳐도 소스를 다시 컴파일할 필요가 없어 개발 기간도 빨라진다.

  1. 메뉴

    • 메뉴 추가

      Insert/Resource - Menu 항목 추가

    • 메뉴 속성 변경

      Caption : 사용자에게 보여질 메뉴의 이름 / ID : 프로그램에서 이 메뉴 항목을 지칭하는 이름이다.

    • 메뉴항목의 속성 : ID상위메뉴캡션 : ID_FILE_MENU

    • 윈도우 클래스를 정의

      wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1)

    • 메뉴의 특성

      1. 1번째 특성은 메뉴에 보이는 것 : 텍스트 문자열 or 비트맵

      2. 2번째 특성은 WM_COMMAND에 wParam 하위비트에 각 메뉴의 ID값을 전달해서 메뉴의 선택을 윈도우 프로시저에게 알려줌

      3. 3번째 특성은 메뉴 항목의 속성(비활성, 활성, 체크등을 표시해줌)

● 알게 된 내용

  - HMENU GetMenu(hwnd) - 메뉴의 핸들얻음

  - CheckMenuItem(hMenu, menuID, uCheck)

    예) CheckMenuItem(hMenu, LOWORD (wParam) - ID, MF_CHECKED) ;

  - EnableMenuItem(hMenu, menuID, nEnable)

    예) EnableMenuItem(hMenu, LOWORD (wParam), MF_GRAYED/MF_ENABLED)
  1. 키보드 가속기
  • 키보드 가속기 장점

    1. 메뉴와 키보드 가속기 로직을 프로그래머가 중복 구현할 필요가 없다.

      TranslateAccelerator()에서 지정한 윈도우의 윈도우 프로시저에 윈도우즈가 WM_COMMAND 메시지를 보낸다.

  • 단축키와 키보드 가속기에 다른점

    1. 단축키 : 반드시 Alt키와 함께 사용해야 하며 메뉴에 있는 항목을 키보드로 선택하는 빠른 방법

    2. 키보드 가속기 : 메뉴와 상관없이 언제든지 사용가능하다.

  • 가속기 추가

    Insert/Resource - Accelerator 추가

  • 키보드 가속기의 속성 - ID : 액셀레이터의 ID, KEY : 액셀레이터가 사용할 키, Modifiers : Key와 함께 눌러질 조합키

                                 Type :  아스키코드, 가상키코드
  • 가속시 테이블 로드

    hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));

    1번째 인자 : 프로그램의 인스턴스, 2번째 인자 : 액셀러레이터 테이블의 이름 문자열 포인터

  • 키누름 변환

    TranslateAccelator(HWND, HACCEL, LPMSG)

    1. 키보드 메시지가 WM_COMMAND 메시지로 변경하여 액셀러레이터가 동작할 수 있도록 함.

    2. 동작방식

    KEYDOWN(Ctrl) - TranslateAccelator(FALSE) - TranslateMessage - DispatchMessage - WndProc - 처리완료

    KEYDOWN(A) - TranslateAccelator(TRUE) - WndProc - WM_COMMAND 호출되서 처리되게 함.

HACCEL hAccel;

hAccel=LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1)); while(GetMessage(&Message,0,0,0)) { if (!TranslateAccelerator(hWnd,hAccel,&Message)) { TranslateMessage(&Message); DispatchMessage(&Message); } }

대화상자

WndClass.cbClsExtra=0; WndClass.cbWndExtra=0; WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); WndClass.hCursor=LoadCursor(NULL,IDC_ARROW); WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION); WndClass.hInstance=hInstance; WndClass.lpfnWndProc=WndProc; WndClass.lpszClassName=lpszClass; WndClass.lpszMenuName=NULL; WndClass.style=CS_HREDRAW | CS_VREDRAW; RegisterClass(&WndClass);

BOOL CALLBACK AboutDlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam) { switch (iMessage) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: EndDialog(hDlg,IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg,IDCANCEL); return TRUE; } break; } return FALSE; }

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam) { switch (iMessage) { case WM_LBUTTONDOWN: DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),hWnd,AboutDlgProc); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd,iMessage,wParam,lParam)); }

  • 대화상자

    • 프로그램과 사용자간의 대화, 곧 명령 및 정보 전달을 위한 특별한 윈도우
  • 대화상자 템플릿

  • 대화상자의 모양을 정의하는 이진 데이터

  • 대화상자 자체의 속성은 물론이고 대화상자 내에 생성되는 컨트롤의 위치, 크기 , 속성등도 정의되어 있음.

  • DialogBoxIndirect(HINSTANCE hInstance, LPCDLGTEMPLATE lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc);

  • LPCDLGTEMPLATE 구조체에 위치, 크기 속성( pdt->style = WS_POPUP, pdt->x = 10, pdt->y = 20; )

  • 모드형 대화상자
  • 프로그램이 모드형 대화상자를 표시, 사용자는 대화상자와 프로그램 내의 다른 윈도우 사이에 전환할 수 없다.
  • 대화상자 프로시저
  1. 대화상자 프로시저 정의

    • 윈도우 프로시저가 윈도우에서 발생하는 메시지를 처리하는 것과 마찬가지로 대화상자 프로시저는 대화상자에서 발생하는 메시지를

      처리함.

  2. 대화상자 프로시저 역할

    • 대화상자 생성 시 자식 윈도우 컨트롤 초기화, 자식 윈도우 컨트롤이 발생시킨 메시지 처리, 대화상자의 종료 처리

    • WM_PAINT, 키보드와 마우스 메시지 처리하지 않음

  3. 대화상자, 윈도우 프로시저 다른점

  4. 윈도우 : LRESULT / 대화상자 : BOOL형 리턴 ( 대화상자가 FALSE를 리턴할 경우 그 메시지 나머지는 운영체제가 처리함)

  5. 윈도우 : 특정 메시지 처리하지 않을 경우(DefWindowProc()호출) / 대화상자 : 메시지 처리하면 TRUE, 그렇지 않으면 FALSE

  6. 윈도우 : WM_CREATE / 대화상자 : WM_INITDIALOG 호출됨< 초기화 >

                                   -WM_PAINT, WM_DESTROY 메시지 처리 안함.
  7. WM_COMMAND 호출

    • 대화상자 프로시저에서 주로 처리하는 메시지

    • LOWORD(wParam)에 메시지를 보낸 컨트롤의 ID가 전달, HIWORD(wParam) 통지코드가 전달됨.

  • 대화상자 호출/ 종료

int DialogBox(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc)

  • 1번째 인수 : 리소스를 가진 인스턴스 핸들 / 2번째 인수 : 대화상자 템플릿의 리소스 ID

    3번째 인수 : 대화상자를 소유할 부모 윈도우, 네번째 인수는 대화상자 프로시저의 이름

    예) DialogBox (hInstance, TEXT (“AboutBox”), hwnd, AboutDlgProc) ;

BOOL EndDialog(HWND hDlg, int nResult)

  • 1번째 인수 : 대화상자 프로시저로 전달된 핸들 / 2번째 인수 : 대화상자를 호출한 DialogBox 함수의 리턴값으로 전달됨.
  • 컨트롤과의 통신
  1. 핸들과 ID
  1. 윈도우 핸들 얻는 방법(차일드 ID 알경우)

HWND GetDlgItem(HWND hDlg, int nIDDlgItem) : 1번째 인수는 대화상자의 핸들, 두번째 인수로 컨트롤의 ID주면 핸들값을 얻을 수 있다.

=컨트롤을 이동시키거나 숨길 때 핸들값이 사용됨(ShowWindow, MoveWindow)

  1. 컨트롤의 윈도우 핸들로부터 ID를 구하는데 사용

int GetDlgCtrlID(HWND hwndCtl)

id = GetWindowLong(HWND, GWL_ID);

= 윈도우 핸들로부터 ID값을 구하는데 사용함.

SendDlgItemMessage(HWND, hDlg, int nID, UNIT MSG, WPARAM wParam, LPARAM lPrame)

=SendMessage(GetDlgItem(hDlg, ID) ~ 2개의 함수를 합쳐놓은 API 제공

=SendDlgItemMessage(hdlg, id, BM_SETCHECK, 1,0);

  • 컨트롤의 값 읽기
  1. 문자열을 읽고 출력하는함수
  • UINT GetDlgItemText( HWND hDlg, int nIDDlgItem, LPTSTR lpString, int nMaxCount );
  • BOOL SetDlgItemText( HWND hDlg, int nIDDlgItem, LPCTSTR lpString );
  1. 정수를 읽고 출력하는 함수
  • UINT GetDlgItemInt( HWND hDlg, int nIDDlgItem, BOOL *lpTranslated, BOOL bSigned );

  • BOOL SetDlgItemInt( HWND hDlg, int nIDDlgItem, UINT uValue, BOOL bSigned ); =네번째 인수 bSigned가 TRUE일 경우는 부호있는 정수값을 읽어주며 FALSE일 경우는 부호를 무시하고 무조건 양수로 읽어준다

    세번째 인수는 지정된 BOOL형 포인터에 에러가 있는지 없는지 대입(에러검사가 필요없는 경우 NULL 전달함)
  • Radio Button 컨트롤 사용법(3개의 기능이 모두 같다) - wParam 1이여야지 체크가 됨.
  1. SendMessage(GetDlgItem(hDlg, id), BM_SETCHECK, i == LOWORD(wParam), 0);

for(int I=IDC_BLACK; I<=IDC_WHITE; I++)

SendMessage(GetDlgItem(hDlg, I), BM_SETCHECK, I==LOWORD(wParam), 0);

  1. SendDlgItemMessage(hDlg, id, BM_SETCHECK, i == LOWORD(wParam), 0);

for(int I=IDC_BLACK; I<=IDC_WHITE; I++)

SendDlgItemMessage(hDlg, I, BM_SETCHECK, I==LOWORD(wParam), 0);

  1. CheckRadioButton(hDlg, idFirst, idLast, idCheck)

    -idFirst부터 idLast 끼지 모든 라이오 버튼 컨트롤의 체크 표시를 끄되, 예외적으로 ID가 idCheck인 라디오 버튼만 체크표시한다.

  • 체크박스 컨트롤 사용법

    1.CheckDlgButton(hDlg, idCheckbox, iCheck);

    -iCheck가 1이면 버튼을 체크, 0이면 체크가 제거됨.

  1. iCheck = IsDlgButtonChecked(hDlg, idCheckBox) : 체크 박스의 상태를 얻을 수 있다.
  • 대화상자 프로시저 인자전달
  1. DialogBoxParam(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam)

예)

typedef struct

{

int iColor, iFigure;

} ABOUTBOX_DATA

static ABOUTBOX_DATA ad = { IDC_BLACK, IDC_RECT };

if(DialogBoxParam(hInstance, TEXT(“AboutBox”), hwnd, AboutDlgProc, &ad))

-WM_INITDIALOG 메시지를 받을 때 lParam으로 전달된다.

pad = (ABOUTBOX_DATA*) lParam;

ad = *pad;

  • 모달리스 / 모달 대화상자

    1. 차이점
    1. 모달 : DialogBox() 함수를 이용, 대화상자가 파괴된 후에야 값을 리턴한다

      모달리스 : CreateDialog() 함수를 이용, 윈도우 핸들을 즉시 리턴해준다.

    2. 모달리스형은 흔히 캡션바와 시스템 메뉴를 포함 /모달형은 캡션바와 시스템메뉴 제공하지않음(다른영역 이동X)

    3. 모달리스형은 WS_VISIBLE을 생략한다면 CreateDialog 호출 후 ShowWindow()를 반드시 호출

    예) hDlgModaless = CreateDialog(…);

       ShowWindow(hDlgModaless, SW_SHOW);
    1. 모달리스 구현사항

    hDlgModaless = CreateDialog(hInstance, lpTemplate, hWndParent, lpDialogFunc);

    -DialogBox에 인자와 같다.

    while(GetMessage(&msg, NULL, 0, 0)){

    if(!IsWindow(hDlgModaless) || !IsDialogMessage(hDlgModaless, &msg)) // 모달리스 대화상자 사용시

    {

       if(!TranslateAccelerator(hwnd, hAccel, &msg)) //키보드 가속기 사용시
    
       {
    
     TranslateMessage (&msg) ;
     DispatchMessage  (&msg);

}

}

BOOL IsWindow(HWND) -유효한 윈도우 핸들인지 조사

  • 하는 이유 : 대화상자를 두번 만들지 않게 하기 위해서 사용된다.

BOOL IsDialogMessage(hDlg, lpMsg)

  • 하는 이유 : 메시지를 점검 한 후 대화상자와 관련된 메시지이면 이 메시지를 처리하고 TRUE를 리턴함. 아니라면 FALSE리턴

DestroyWindow(hDlg) -모달은 EndDialog지만 모달리스는 DestroyWindow를 호출하게 된다.

CreateDialog에서 리턴한 핸들을 NULL로 초기화해줘야함.

  • 알게된 내용 : CreateWindow에서 Style중 WS_CLIPCHILDREN 사용하는 이유?

    -프로그램이 대화상자를 지우지 않고도 메인 윈도우를 다시 그릴 수 있게 해주는 Style이다.

  • 공통 대화상자

    • 하나의 표준화된 사용자 인테페이스를 장려하기 위해서 개발되었다.
  1. 파일열기 대화상자

  2. 색상 대화상자

  3. 폰트 선택 대화상자

  4. 찾기 대화상자

클립보드

  • 클립보드 : 프로그램간에 또는 내부적으로 교환할 데이터를 잠시 저장해 두는 곳

  • 힙 할당(TEXT -클립보드)

    • HGLOBAL GlobalAlloc(UNIT uFlags, DWORD dwByte) : 힙에 메모리를 할당하는 함수

    • LPVOID GlobalLock(HGLOBAL hMem) : 메모리의 실제 위치의 포인터 리턴

    • BOOL GlobalUnLock(HGLOBAL hMem)

    • HGLOVAL GlobalFree(HBLOBAL hMem)

  • 비트맵 -클립보드

    hBlt = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP));

    CF_BITMAP 세팅 후 클립보드에 복사하고 읽을 수 있다.

HGLOBAL hmem;

TCHAR *ptr;

hmem=GlobalAlloc(GHND, lstrlen(str)+1); ptr=(TCHAR *)GlobalLock(hmem); memcpy(ptr,str,lstrlen(str)+1); GlobalUnlock(hmem);

if (OpenClipboard(hWnd)) { // 클립보드 독점 EmptyClipboard(); SetClipboardData(CF_TEXT,hmem); CloseClipboard();

}

  • 클립보드 함수

    BOOL OpenClipboard(HWND hWndNewOwner) // 인수 : 윈도우 핸들

    BOOL EmptyClipboard(); // 클립보드 지움

    HANDLE SetClipboardData(UINT uFormat, HANDLE hMem) // uFormat : CF_BITMAP, CF_TEXT등

    -hMem 데이터가 uFormat으로 클립보드에 복사된다. 호출이후부터는 사용자가 hMem 메모리 변경불가능(시스템관리:클립보드)

    -SetClipboardData(CF_TEXT, hmem);

    BOOL CloseClipBoard(); // 클립보드 닫음(생략시 다른사용자가 클립보드 사용X)

    BOOL IsClipboardFormatAvailable(UINT format) // uFormat : CF_BITMAT, CF_TEXT등 클립보드에 있는지 검사

    HANDLE GetClipBoardData(UINT format)

    -hmem = GetClipBoardData(CF_TEXT);

    -HBITMAP hBit = (HBITMAP)GetClipBoardData(CF_BITMAP)

  • 새로운 클립보드 포멧을 등록

    UINT RegisterClipboardFormat(LPCTSTR lpszFormat)

    예)

    MyFormat = RegisterClipboardFormat(“MOVIE”);

    SetClipboardData(MyFormat, hmem);

  • 클립보드 포맷을 관리하는 함수

int CountClipboardFormats(void) // 등록된 포멧의 개수

UINT EnumClipboardFormats(UINT format); // 각 포멧 열거함

int GetClipboardFormatName(UINT format, LPTSTR lpszFomatName, int cchMaxCount); // 포멧의 등록 이름을 구함.

  • 클립보드 뷰어

    • 클립보드 내용의 변화를 통지받는 프로그램

    • 뷰어끼리 체인으로 연결되어 있어, 최근에 설치된 뷰어가 맨앞에 위치하고 체인을 통해서 뒤에 뷰어에게 변화나 상태를 전달함.

    • 클립보드의 내용 변경 : SetClipboardViewer(CF_TEXT, hmem) -윈도우 WM_DRAWCLIPBOARD 호출 ->모든 뷰어에게 추가를 알림

    • 클립보드 뷰어 삭제 : ChangeClipboadChain(hWnd, hNext) -WM_CHANGECBCHAIN -모든 뷰어에게 삭제를 알림

프린터

  • 인쇄과정

프로그램 - GDI - 스풀러 - 디바이스드라이버 - 프린터

  1. 스풀러 : 적절한 프린터 디바이스 드라이버를 메모리 로딩 - 고수준 출력 명령을 저널 레코드로 변환 - 디스크에 파일로 저장

    • 저장된 출력 명령을 바탕으로 백그라운드에서 인쇄 - 저널레코드 (디바이스드라이버 알수있도록 DDI(Device Driver Interface) 변환
  • 프린터 DC

    1. 인쇄대화상자 호출하는 함수

      • BOOL PrintDlg(LPPRINTDLG lppd);

pd.lStructSize = sizeof(PRINTDLG); //구조체 크기 pd.Flags = PD_RETURNDC; // 프린터 DC 구함 pd.hwndOwner = hWndMain; // 윈도우 핸들 pd.nFromPage = 1; pd.nToPage = 1; pd.nMinPage = 1; pd.nMaxPage = 1; pd.nCopies = 1; PrintDlg(&pd); hPrtdc = pd.hDC; // 프린트 DC 사용을 위해 HDC 대입

  1. HDC CreateDC(LPCTSRT lpszDriver, LPCTSTR lpszDevice, LPCTSTR lpszOutput, CONST DEVMODE *lpInitData)

      1. driver name, 2. device name, 3. NULL 4. 디바이스 드라이버에 특정 초기화 데이터
    • 특정 이름의 디바이스의 DC를 구할 때 사용함.

PRINTER_INFO_4 *pi4;

EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &cbNeed, &cbReturn); pi4=(PRINTER_INFO_4 *)malloc(cbNeed); EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE)pi4, cbNeed, &cbNeed, &cbReturn);

hdc = CreateDC(NULL, pi4->pPrinterName, NULL, NULL);

  1. 인쇄의 시작

    • int StartDoc(HDC hdc, Const DOCINFO *lpdi);

doc.cbSize = sizeof(DOCINFO); doc.lpszDocName = TEXT(“TEST Document”); doc.lpszOutput = NULL; // 출력파일 이름, NULL 일 경우 프린터 DC로 출력 doc.lpszDatatype = NULL; StartDoc(hPrtdc, &doc);

  1. 프린터 드라이버에게 데이터를 받아들이도록 준비시킴(새로운 페이지 시작)
  • int StartPage(HDC hdc)

     StartPage(hPrtdc);
  1. 한 페이지 출력을 완료 후 새 용지를 로드
  • int EndPage(HDC hdc);

EndPage(hPrtdc);

  1. 인쇄가 마무리
  • int EndDoc(HDC hdc)

EndDoc(hPrtdc);

DeleteDC(hPrtdc);

  • 폰트의 변경

xpage = GetDeviceCaps(hPrtdc, HORZRES); // 장치크기의 픽셀수 ypage = GetDeviceCaps(hPrtdc, VERTRES); Rectangle(hPrtdc,0,0,xpage,ypage);

dpiY = GetDeviceCaps(hPrtdc, LOGPIXELSY); // 인치당 픽셀수

// 화면 해상도와 프린터의 해상도가 높기 때문에 아래와 같은 계산식이 필요함.

// 1 inch = 72 point = 인치당 픽셀수 구한값(pixel)

 point = n*1/72*dpiY

MyFont = CreateFont(20*dpiY/72, 0,0,0,FW_NORMAL, FALSE,FALSE,FALSE,HANGEUL_CHARSET,3,2,1,

                           VARIABLE_PITCH|FF_ROMAN,TEXT("궁서"));
  • 비트맵 출력

Result=GetDeviceCaps(hPrtdc, RASTERCAPS) & RC_BITBLT; if (!Result) goto end; hbit=(HBITMAP)LoadImage(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION); .. MemDC=CreateCompatibleDC(hPrtdc); OldBitmap=(HBITMAP)SelectObject(MemDC, hbit); StretchBlt(hPrtdc,dpiX,dpiY,4dpiX,4by/bx*dpiY,MemDC,0,0,bx,by,SRCCOPY);

  • 주의사항

    1. 프린터로 비트맵 출력 시 StretchBlt 함수로 출력해야함(Bitblt를 그대로 출력시 프린터에 화면에 나온거보다 작게 출력됨)

    2. 비트맵 출력이 가느한지 조사해야함.

      GetDeviceCaps(hPrtdc, RASTERCAPS) -래스터 출력이 가능한지 확인

      RC_BITBLT -비트맵 전송지원 지원

    3. LoadImage 함수로 읽어야 한다. - 화면색상포맷과 프린터의 색상 포맷이 맞지 않기 때문에(DDB로 불러드리기때문에)

    LR_CREATEDIBSECTION - DIB 섹션으로 읽은 후 출력할 때 비트맵 포맷이 프린터에 맞게 변환된다.

  • 여러 페이지 출력

    1. 문서의 길이 계산

      • 사용자가 선택한 문서의 길이 알아내야함.

        PD_ALLPAGES, PD_PAGENUMS, PD_SELECTION

if (pd.Flags & PD_PAGENUMS) { nFirstPage=pd.nFromPage; nFinalPage=pd.nToPage; } else { nFirstPage=pd.nMinPage; nFinalPage=pd.nMaxPage; }

  1. 시작페이지와 끝페이지 인쇄(for문으로 돌면서 인쇄해야함)

for(nPage = nFirstPage; nPage <= nFinalPage; nPage++)

 {

      StartPage()

      EndPage()

  }

  EndDoc();
  • 취소 프로시저(인쇄 취소시)
  1. 취소 프로시저와 취소 대화상자 필요함.

// 취소대화상자

g_hDlgCancel=CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWndMain, (DLGPROC)AbortDlgProc); // 모달리스로 대화상자 만듦

LRESULT CALLBACK AbortDlgProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: g_bPrint=FALSE; // 취소 버튼 누를시 FALSE 세팅 EnableWindow(hWndMain, TRUE); DestroyWindow(g_hDlgCancel); g_hDlgCancel=NULL; return TRUE; } return FALSE; }

// 최소 프로시저. 이 함수에서 TRUE를 리턴하면 인쇄를 계속하고 FALSE를 리턴하면 인쇄를 취소한다.

SetAbortProc(hPrtdc, (ABORTPROC)AbortProc); // 취소 프로시저 추가

EnableWindow(hWndMain, FALSE); // 인쇄하려는 동안 프로그램을 종료, 다른 작업을 못하게 하기위해서

BOOL CALLBACK AbortProc(HDC hPrtdc, int iError) { MSG msg; while (g_bPrint && PeekMessage(&msg, NULL,0,0,PM_REMOVE)) { // g_bPrint 가 FALSE 가 될시 인쇄가 취소된다. if (!IsDialogMessage(g_hDlgCancel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); }

return g_bPrint;

}

  • 프린터 열거
  1. 프린터 열거
  • 시스템에 설치된 프린터와 프린터서버 등을 열거한다.

  • BOOL EnumPrint(DWORD Flags, LPTSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded,

                       LPDWORD pcReturnd);
    1. Flags : 조사할 오브젝트 종류를 지정함(PRINTER_ENUM_LOCAL,, PRINTER_ENUM_SHARED)

    2. Name : 조사할 대상의 추가정보(대부분 NULL 세팅) - 특정도메인내 프린터목록 조사시 도메인명을 적을 수는 있음.

    3. Level, pPrinterEnum : Level 2 -PRINTER_INFO_2 // 프린터의 원하는 정보를 얻을 때 쓰이며 1~5까지 구성되어 있음

    4. cbBuf : 배열의 크기

    5. pcbNeeded : 필요한 메모리양

    6. pcReturned : 구조체 배열의 크기를 리턴

typedef struct _PRINTER_INFO_4A { LPSTR pPrinterName; LPSTR pServerName; DWORD Attributes; } PRINTER_INFO_4A, *PPRINTER_INFO_4A, *LPPRINTER_INFO_4A;

PRINTER_INFO_4 *pi4;

EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &cbNeed, &cbReturn); pi4=(PRINTER_INFO_4 *)malloc(cbNeed); EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE)pi4, cbNeed, &cbNeed, &cbReturn); for (i=0;i<cbReturn;i++) { wsprintf(Mes,“프린터 이름: %s, 종류:%s ”, pi4[i].pPrinterName, pi4[i].Attributes==PRINTER_ATTRIBUTE_LOCAL ? “로컬”:“네트워크”); TextOut(hdc,10,y++*20,Mes,lstrlen(Mes)); } free(pi4);

  • 속성조사

    1. 해상도, 크기(픽셀), 크기(사이즈)

      GetDeviceCaps(HDC, HORZRES/HORZSIZE/LOGPIXELSX);

    2. 프린터 이름을 토대로 속성 확인(한 부씩 인쇄, 양면인쇄)

      DeviceCapabilities(szPrinter, szPrinter, DC_COLLATE/DC_DUPLEX, NULL, NULL); //한부씩 인쇄, 양면인쇄

    3. OpenPrinter, GetPrinter, ClosePrinter : 프린터 이름으로 핸들값을 얻어서 PRINTER_INFO값을 얻고 세팅가능

      GetPrinter, EnumPrinters PRINTER_INFO의 크기를 같은 방법으로 얻을 수 있음.

비트맵과 Bitblt함수

  • 메모리 DC 쓰는 이유(비트맵)

    • 비트맵과 같은 경우 대용량 데이터 이므로 곧바로 출력할 경우 출력속도가 느리게 되는 단점이 발생함.

      (비트맵 곧바로 화면 출력못하게 되어 있음)

    -메모리 DC에 그려두고 화면 DC에 고속복사해서 보여주게 하기 위해서 사용됨.

  • 메모리 DC -화면 DC에 고속복사 함수

    1. BOOL BitBlt(hdcDest, xDest, xDest, nWidth, nHeight, hdcSrc, nXsrc, nYSrc, dwRop) - 래스터 연산 : 256가지

    dwRop : 래스터 연산 방법을 지정

    -SRCCOPY : 소스 영역을 대상 영역에 복사한다.

    1. 비트맵 전송시 확대 및 축소 가능

      BOOL StretchBlt(hdcDest, xOriginDest, YOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc,

                         nHeightSrc, dwRop) - 래스터 연산 : 256가지
      • StretchBlt(hdc, 0,0,246,320,MemDc,0,0,123,160,SRCCOPY)

      • SetStretchBltMode 모드 변경가능.

  1. BOOL PatBlt(HDC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, DWORD dwRop) - 래스터 연산 : 16가지

    • 지정한 사각영역을 현재 DC에 선택된 브러시로 채움

    • FillRect는 사각영역으로 브러시로 채우지만 PatBlt는 dwRop에 따라서 바뀔 수가 있다.(검정, 흰색으로 채울 경우)

  • GDI 비트맵 객체
  1. DDB 비트맵 생성함수
  • CreateBitmap(cx, cy, cPlanes, cBitsPixel, bits);

  • CreateCompatibleBitmap(hdc, cx, cy) -hdc이용해서 GetDeviceCaps(PLANES(색상면의수), BITPIXEL(픽셀당비트수)) 정보를

    얻음 -내부적으로 CreateBitmap 호출함.

  • CreateCompatibleBitmap(&bitmap) -BITMAP 구조체에 주소를 설정

    ● GetObject(hBitmap, sizeof (BITMAP), &bitmap) -구조체의 값 얻을 수 있음

  • 메모리 디바이스 컨텍스트

    hdcMem = CreateCompatibleDC(hdc);

    1. 인자로 NULL 지정 시 비디오 디스플레이와 호환되는 메모리 디바이스 컨텍스트 생성

    2. DeleteDC 호출 후 파괴

  • 비트맵 리소스 로드

    hBitmap = LoadBitmap(hInstance, szBitmapName);

    1. 시스템 비트맵 로딩 : hinstance =NULL

    2. DeleteObject 삭제

  • 흑백 비트맵 포멧(리소스 생성없이 color array로 흑백비트맵생성)

    static BYTE bits[] = {0x51, ~~};

    1. bitmap.bmBits = (PSTR)bits;

      hBitmap = CreateBitmapIndirect(&bitmap);

    2. hBitmap = CreateBitmapIndirect(&bitmap);

      SetBitmapBits(hBitmap, sizeof(bits), bits);

    3. hBitmap = CreateBitmap(20, 5, 1, 1, bits); //width, height,planes,bitsPixel,color data array

      -DeleteObject 함수 호출해서 해제시켜줘야 한다.

장치독립적인비트맵

  • DIB & DDB 차이점
  • DDB(Device Dependent Bitmap) : 장치 설정대로 출력되는 비트맵(32bit -32bit, 흑백 -흑백)

                                                장점 : 정보가 일치하므로 빠른 속도로 이미지를 출력
    
                                                단점 : 장치의 의존하므로 다른 장치에선 정확히 출력이 안된다.
  • DIB(Device Independent Bitmap) : 장치와 상관없이 헤더에 나온 세팅대로 출력하는 비트맵

                                                 장점 : 어떤한 설정을 가진 장치에서도 동일한 이미지정보를 출력
    
                                                 단점 : 비트맵 출력 속도가 떨어질 수 있음( 비트맵 구성이 다르다면 변환작업이 필요)
  • DIB 구조
  1. BITMAPFILEHEADER 구조체

    • 비트맵 파일 자체에 관한 정보를 가진다.

typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

  1. BITMAPINFOHEADER 구조체

    • BITMAPFILEHEADER 구조체 바로 뒤에 위치하면서 DIB의 크기(가로 폭, 세로 높이)와 색상 포멧에 관한 정보등을 가진 구조체이다.

typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

  1. RGBQUAD 구조체
  • 비트맵에서 사용되는 색상 테이블 정의

typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD;

  1. DIB 출력

    1. SetDIBitsToDevice

BYTE* pRaster;

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);
  • Return : 스캔 라인의 갯수

  • 9번째 인자(cScanLines) : 스캔 라인수 = 비트맵의 높이

                   < 비트맵 >

    BITMAPFILEHEADER *fh = NULL;

    fh = (BITMAPFILEHEADER*)malloc(GetFileSize(hFile, NULL));

    BYTE* lpvBits = (PBYTE)fh+fh->bfOffBits;

  • lpvBits : 비트맵의 실제 모양인 래스터 데이터 포인터(BITMAPFILEHEADER+BITMAPINFOHEADER == bfOffBits(FILEHEADER))

  • fuColorUse : DIB_RGB_COLORS - 색상값 / DIB_PAL_COLORS - 팔레트의 인덱스

    1. StretchDIBits( 확대 출력시 )

int StretchDIBits(HDC hdc,int XDest,int YDest,int nDestWidth,int nDestHeight,int XSrc, int YSrc,int nSrcWidth,int nSrcHeight

                   CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD dwRop);
  • Return : 스캔 라인의 갯수

  • iUsage : DIB_RGB_COLOR(색상테이블 색상값), DIB_PAL_COLORS(팔레트의 인덱스)

  • dwRop : 래스터 연산

  1. DDB 변환

HBITMAP CreateBitmap(HDC hdc, CONST BITMAPINFOHEADER *lpbmih, DWORD fdwInit, CONST VOID *lpbInit

                               CONST BITMAPINFO* lpbmi, UINT fuUsage)'

{

if(hdc)

hBitmap = CreateCompatibleBitmap(hdc, cx, cy);

else

hBitmap = CreateBitmap(cx,cy,1,1,NULL);

if(fdwInit)

{

hdcMem = CreateCompatibleDC(hdc);

SelectObject(hdcMem, hBitmap);

SetDIBitsToDevice(hdcMem,0,0,cx,cy,0,0,0,cy,lpbInit,lpbmi,fuUsage);

DeleteDC(hdcMem);

}

return hBitmap;

}

  • 내부적으로 메모리 DC를 만들고 호환 비트맵에 DIB를 출력하는 일을 한다.(BitBlt로 출력)
  1. DIB 섹션
  • 이점 : 래스터 데이터를 직접 조작, 크기가 큰 파일을 다루기가 편리(파일 매핑 오브젝트)

  • HBITMAP CreateDIBSection(HDC hdc, CONST BITMAPINFO *pbmi, UINT iUsage, VOID **ppvBits,

                                        HANDLE hSection, DWORD dwOffset);
  1. DIB로 변환
  • CreateBitmap, CreateCompatibleBitmap 장치에 의존하므로 속도가 빠르지만 DIB로 저장시에는 아래 API가 호출되어야한다.

  • int GetDIbits(HDC hdc,HBITMAP hBitmap,UINT uStartScan,UINT uScanLines,LPVOID lpvBits,LPBITMAPINFO lpbi, UINT uUsage);

텍스트와 폰트

  • 텍스트 그리기 함수

    1. SetTextAlign(HDC hdc, UINT fMode)

      ● fMode : 지정하는 정렬 Mode를 세팅함.

      TA_UPDATECP : TextOut에서 지정한 x, y 좌표를 무시하고 현재 CP(current position)를 이용한다.

      TA_NOUPDATECP : CP를 사용하지 않고 지정한 좌표를 사용하며 CP를 변경하지 않는다.

    2. TabbedTextOut(hdc, xStart, yStart, pString, iCount, iNumTabs, piTabStops, xTabOrigin)

      • 텍스트 문자열이 탭 문자(‘\t’, 0x09)를 포함한다면,TabbedTextOut()은 인자로 전달된 정수 배열에 기초하여 탭을 공백으로 확장함.

예) int tabstop[4] = {8,16,24,32}

  wsprintf(temp, "tabbedTextOut\t를\t이용한\t출력");

  1) TabbedTextOut(hdc,0,20,temp,strlen(temp),4,tabstop,0);

  =iNumTabs : 탭의 개수,  piTabStops : 탭 위치를 가지는 배열

  =첫 번째 탭에서는 설정된 문자열의 평균 가로크기의 8배, 두번째 탭에서는 16배 공백으로 띄워줌.

  2) TabbedTextOut(hdc,0,20,temp,strlen(temp),1,tabstop,0);

  =탭키를 만날 때마다 tabstop의 첫 번째 값 즉 8값만큼 균일적으로 공백으로 띄어 주게 된다.
  1. ExtTextOut(hdc, x, y,

                 fuOptions, - 텍스트 출력 옵션
    
                 &rect  - 사각영역

lpString,

                   cbCount,

                   lpDx ) - 문자사이 공백값 배열 포인터(int pDx[]={5,6~~} pDx[i] 문자와 오른쪽문자 자간

 - 현재 선택된 글꼴, 배경색, 글자색을 이용하여 문자열을 그린다.

 - &rect, lpDx 둘다 NULL인 경우 TextOut과 같은 기능이다.(TextOut을 내부적으로 보믄 ExtTextOut 호출함.)

1) fuOptions : 어플리케이션이 정의한 사각형을 사용하는 방법을 지정한다.

  ● ETO_CLIPPED : 텍스트가 주어진 사각형으로 클리핑 된다. 영역 안쪽에만 문자열이 출력된다.

  ● ETO_OPAQUE : 현재의 배경 색상으로 채워질 배경 직사각형
  1. DrawText(hdc, pString, iCount, &rect, iFormat);

    • iFormat을 0으로 설정 : 윈도우즈는 텍스트를 캐리지 리턴문자(‘\r’), 라인피드(‘\n’)로 분리된 일련의 행으로 해석함

                                  DT_WORDBREAK : 사각영역의 오른쪽 끝에서 자동 개행되도록 한다.
      
                                  DT_NOCLIP : 사각영역의 경계를 벗어나도 문자열을 자르지 않고 그대로 출력
    • DrawTextEx(hdc, pString, iCount, &rect, iFormat, &drawtextparams)

typedef struct tagDRAWTEXTPARAMS { UINT cbSize; // 구조체의 크기 int iTabLength; // 각 탭 정지점의 크기 int iLeftMargin; //왼쪽 여백 int iRightMargin; //오른쪽 여백 UINT uiLengthDrawn; // 처리된 문자들의 개수를 받는다. } DRAWTEXTPARAMS, FAR *LPDRAWTEXTPARAMS;

  • DWORD GetSysColor(nIndex) : nIndex - 지정된 시스템 칼라를 취득함.(COLOR_MENU, COLOR_WINDOW)

  • 현재글자간의 간격

    • SetTextCharacterExtra(hdc, iExtra) - iExtra 논리단위로서 윈도우는 Pixel로 변환(글자간의 간격을 변경)

    • GetTextCharacterExtra(hdc)

  • 폰트만들기

typedef struct tagLOGFONTW { LONG lfHeight; LONG lfWidth; LONG lfEscapement; // 문자열 각도 LONG lfOrientation; // 개별 문자의 각도 LONG lfWeight; // 문자의 굵기 BYTE lfItalic; // 기울기 BYTE lfUnderline; // 밑줄 BYTE lfStrikeOut; // 취소선 BYTE lfCharSet; // 문자셋 BYTE lfOutPrecision; // 출력정확도(폰트의 높이, 폭, 피치등에 근접한 폰트를 찾을지 지정함) BYTE lfClipPrecision; //클리핑 영역을 벗어날 때의 처리방법 BYTE lfQuality; // 출력품질(글꼴, 폰트의 외형을 중시) BYTE lfPitchAndFamily; // 피치 : 개별 글자의 폭, 폰트의 패밀리 WCHAR lfFaceName[LF_FACESIZE]; //타입페이스 : 폰트의 이름 } LOGFONTW, *PLOGFONTW, NEAR *NPLOGFONTW, FAR *LPLOGFONTW;

-CreateFont의 인자값과 같다. LOGFONT 구조체는 CreateFontIndirect의 인자로 쓰이게 된다.

  • 논리 폰트 : CreateFont 함수에 의해 만들어지는 폰트

    물리 폰트 : 운영체제나 장치에 실제로 존재하는 폰트

    스톡 폰트 : 운영체제에 의해 제공되는 폰트(GetStockObject)

  • 폰트열거

  1. 폰트 열거 함수
  1. int EnumFontFamilies(HDC hdc, LPCTSTR lpszFamily, FONTENUMPROC lpEnumFontFamProc, LPARAM lParam)

    lpszFamily : 조사하고자 하는 폰트 패밀리 지정함(값이 NULL이면 모든 패밀리를 조사한다.)

    lpEnumFontFamProc : 발견된 폰트의 특성을 알려줌

  2. int CALLBACK EnumFontFamProc(ENUMLOGFONT FAR *lpelf, NEWTEXTMETRIC FAR *lpntm, int FontType, LPARAM lParam)

    ENUMLOGFONT - LOGFONT 구조체, ElFullName - 폰트타입 문자열,

    NEWTEXTMETRIC : 폰트의 여러가지 특성값을 가지고 있음.

    FontType : 폰트의 종류(장치, 래스터, 트루타입)

  • 물리폰트

    1. BOOL GetTextMetrics(HDC hdc, LPTEXTMETRIC lptm) : 개별 문자의 폭이나 높이에 대한 정보를 구한 후 간격을 적당히 띄우고자

                                                                                  할 때 사용함.( hdc에 현재 선택된 물리 폰트의 여러 가지 정보)
      • 예) GetTextMetrics(hdc, &tm)

        TextOut(hdc, 0, i*(tm.tmHeight), str, lstrlen(str));

  • BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int cbString, LPSIZE lpSize) : 문자열이 크기 구하기 위해서 사용됨.

     - "ijl", "BMW" 같은 세문자지만 전체 폭은 다르다. 이때 쓰이게 된다.
    
     - 예) GetTextExtentPoint32(hdc, str, lstrlen(str), &sz)
    
             x += sz.cx;
    
             TextOut(hdc, x,0, str, lstrlen(str));
  • 폰트의 설치

    • lpszFilename : 추가/삭제할 폰트의 경로를 전달해준다. (Windows\Font)

    • int AddFontRsource( LPCTSTR lpszFilename)

      ● 설치과정

      1. 폰트파일을 Font 폴더로 복사
      
      2. 폰트등록:AddFontResource
      
      3. WM_FONTCHANGE 방송
      
         SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
      
      4. 레지스트리에 폰트 이름 기록
  • 폰트의 삭제

    • BOOL RemoveFontResource(LPCTSTR lpFileName)

      ● 설치과정

      등록된 폰트를 취소:RemoveFontResource - WM_FONTCHANGE 방송 - 레지스트리에 폰트 이름 삭제 - 폰트파일을 삭제
  • BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInformation)

    • 현재 작동하고 있는 OS의 버전 정보를 제공하는 API
    1. OSVERSIONINFO

       typedef struct _OSVERSIONINFOW {
      DWORD dwOSVersionInfoSize; //Version Info 사이즈
      DWORD dwMajorVersion;        // OS Version 2.1 -2
      DWORD dwMinorVersion;        //OS Version 2.1 -1
      DWORD dwBuildNumber;
      DWORD dwPlatformId;            // OS platformID -VER_PLATFORM_NT, VER_PLATFORM_WIN32_C3 등
      WCHAR  szCSDVersion[ 128 ];     // OS에 추가적인 정보

      } OSVERSIONINFOW, *POSVERSIONINFOW, *LPOSVERSIONINFOW;

  • 패스

    • GDI 함수들에 의해 그려진 도형의 모양

    • 패스는 핸들을 가지지 않고 그려지는데 그것은 여러 개의 패스를 만들어 놓고 교체해 가며 사용할 수 없다는 뜻이다.

    • BeginPath(HDC) 와 EndPath(hWnd) 사이를 패스괄호라고 칭하였고, 이때 GDI함수는 출력을 내보내지 않고 패스에 기록하게 된다.

    StrokePath(HDC): 외곽선, FillPath(HDC) : 패스의 내부, StrokeAndFillPath(HDC) : 외곽선과 패스 내부

    • 클립패스
    1. SelectClipPath(HDC, iMode)
    • SelectClipPath(hdc, RGN_COPY); //RGN_COPY : 핸재 패스가 새 클리핑 영역으로 선택됨
    1. PathToRegion(hdc) - 패스를 리전으로 바꿀 때 사용함(<예hRgn = PathToRegion(hdc) )
  • 확장펜

  • ExtCreatePen(dwPenStyle, dwWidth, LOGBRUSH, dwStyleCount, lpStyle)
  1. PenStyle : PS_SOLID, PS_JOIN_ROUND등 스타일 지정

  2. dwWidth : 선의 굵기

  3. LOGBRUSH : 구조체안에서 선의 무늬, 스타일 지정

  4. dwStyleCount, lpStyle : PS_USERSTYLE 지정(사용자 정의 선을 그을 때 사용 - 안쓸경우 : 인수 두개는 0, NULL로 처리)

    • dwStyleCount : lpStyle 배열의 크기

    • lpStyle : 5픽셀 찍고 다음 5픽셀 찍지말고.

    예) DWORD Style[] = {5,5,4,4,3,3,2,2,1,1};

     hGeo = ExtCreatePen(PS_USERSTYLE|PS_GEOMETRIC, 1, &logBrush, 10, Style)

다중문서 인터페이스

  • 다중문서 인터페이스(Multiple-Document Interface : MDI)

    • 클라이언트 윈도우와 일반 윈도우 차이점

      1. 클라이언트 윈도우는 MDICLIENT로 고정되어 있다.

        CreateWindow(“MDICLIENT”~~), 운영체제에서 미리 정의되어 있으므로 윈도우 클래스 등록할 필요가 없다.

      2. 클라이언트 윈도우는 CreateWindow 마지막 인자 lParam에 CLIENTCREATESTRUCT 구조체에 포인터를 넘겨야함.

  • TranslateMDISysAccel(hWndClient, lpMsg)

    • WM_KEYDOWN, WM_SYSCOMMAND 메시지를 MDI 자식 윈도우에 보내는 역할을 한다.
  • 프레임 윈도우 메시지 처리 / 윈도우 메시지 처리

    1. 인수차이
    • DefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)

    • DefFrameProc(HWND hWnd,HWND hWndMDIClient,UINT Msg, WPARAM wParam, LPARAM lParam)

      =클라이언트 윈도우 핸들이 추가됨.

    1. 메시지 처리

      • 프레임 윈도우 메시지 처리 후 return 0 대신 break문을 사용해서 처리해야함.(포커스 오류)
  • 클라이언트 윈도우

    1. GetSubMenu(GetMenu(), 1)

      메뉴 -기준으로

      서브메뉴 0 (File)

      서브메뉴 1 (Window)

    2. CLIENTCREATESTRUCT 설명

    • hWindowMenu : 차일드 목록 관리에 사용될 메뉴 ID

    • idFirstChild : 첫번째 차일드 윈도우의 목록이 출력될 메뉴 항목(최대 9개까지 출력가능함)

    ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), WINDOWMENU) ccs.idFirstChild = IDM_WINDOWCHILD; // 메뉴에서 첫 차일드 항목 이후 9개의 id가 연속적으로 비어 있어야 한다.

                                                              그래서 따로 연속 될 수 있는 값으로 #define 해야한다.
  1. CreateWindow에 스타일

    • WS_CLIPCHILDREN 클라이언트 윈도우가 다시 그려질 시 자식 윈도우에 WM_PAINT 메시지를 보내지 못하게 하기 위해 세팅함.
  • 클라이언트 윈도우, MDI 관련 구조체
  • 응용프로그램이 MDI 클라이언트 윈도우를 생성하면 CLIENTCREATESTRUCT 구조체를 지정해줘야 합니다.

  • MDI 클라이언트 윈도우가 MDI 자식 윈도우를 생성하면 MDICREATESTRUCT 구조체를 지정해야 합니다.

  • 차일드(자식) 윈도우

    1. 차일드 윈도우 주의사항

      • 차일드 윈도우는 메뉴를 가질 수 없으므로 lpszMenuName은 NULL이어야 한다.

      • 별도의 아이콘을 지정하는 것이 좋다.(최소화, 시스템 메뉴 구분)

      • 여분의 메모리를 남겨두어야 한다. (차일드 윈도우 파일이름이나 일련번호가 저장됨)

    2. 자식윈도우 생성

    • MDICREATESTRUCT 속성 채우기

      1. mcs.style = MDIS_ALLCHIDSTYLES

        =MDIS_ALLCHILDSTYLES : WS_MINIMIZE | WS_MAXMIZE | WS_HSCROLL | WS_VSCROLL

      2. WM_MDICREATE 를 SendMessage에 보내면 자식 윈도우 생성(lParam에 MDICREATESTRUCT 구조체 포인터전달)

      typedef struct tagMDICREATESTRUCT { LPCTSTR szClass; LPCTSTR szTitle; HANDLE hOwner; int x; int y; int cx; int cy; DWORD style; LPARAM lParam;

    } MDICREATESTRUCT, *LPMDICREATESTRUCT;

     3) HWND CreateMDIWindow(LPTSTR lpClassName, LPTSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth,
    
         int nHeight, HWND hWndParent, HINSTANCE hInstacne, LPARAM lParam);
  1. 자식 윈도우 바둑판식 정렬
  • WM_MDITILE 를 SendMessage에 보내면 자식 윈도우 생성

  • MDITILE_HORIZONTAL 수평정렬, MDITILE_VERTICAL 수직정렬

  1. 자식 윈도우 계단식 정렬
  • WM_MDICASCADE 를 SendMessage에 보내면 자식 윈도우 생성

  • wParam에 MDITILE_SKIPDISABLED 플래그를 주면 사용금지 된 차일드는 정렬대상에서 제외한다.

  1. 자식 윈도우 아이콘 정렬
  • WM_MDIICONARRANGE 를 SendMessage에 보내면 자식 윈도우 생성

  • 최소화된 아이콘을 정렬함.

  1. 마지막은 DefMDIChildProc를 불러서 처리해야함(DefWindowProc에 인수와 동일함.)
  • WndClass에서 cbWndExtra = sizeof(int) -여분의 메모리 지정가능.

  • SetWindowLong(hWnd, 0, ChildNum) - 메모리 블록을 참조하는 포인터를 통해서 값들을 저장한다.

index : 윈도우에 여분 메모리가 있을 경우 여분 메모리의 오프셋을 지정할 수도 있다. 이 값은 반드시 양수여야 하며 cbWndExtra-4보다는 작아야 한다. 예를 들어 여분 메모리가 32바이트 지정되어 있으면 nIndex는 0~28까지 지정할 수 있다.

=GetWindowLong(hWnd, 0)을 통해서 저장된 값을 확인할 수 있다.

멀티태스킹과 멀티스레딩 & 동기화

  • 멀티태스킹 : 하나의 운영체제에 여러 개의 프로세스가 동시에 실행되는 환경

  • 멀티스레드 : 하나의 프로세스에서 여러 개의 스레드가 동시에 실행되는 환경

  • 스레드 : 프로세스 내의 명령어를 실행시켜주는 경로, 일련의 실행코드

    1. 스레드 생성
    • HANDLE CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreateFlags, lpThreadID)

1번째 인수 : 스레드 보안속성 지정(핸들끼리 상관하지 않는 한 NULL로 지정됨)

2번째 인수 : 스레드의 스택의 크기(기본 1M 잡힘)

3번째 인수 : 스레드의 시작주소

4번째 인수 : 스레드로 전달하는 작업 내용

5번째 인수 : 스레드 특성 지정(CREATE_SUSPENDED 플래그 지정시 스레드 만들고 실행X - ResumeThread 함수를 호출해야함)

6번째 인수 : 스레드 ID

2 스레드 특성

- 같은 프로세스 내의 스레드끼리는 주소공간, 전역변수, 코드를 공유함.
  1. 스레드 상태 확인

    • BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)

      1번째 인수 : 대상 스레드 핸들

      2번째 인수 : 스레드의 종료 코드 조사해 리턴

  2. 스레드 종료

    1. Return & ExitThread 차이점과 ExitThread 문제점

      • 차이점 :
  3. 문제점 : A,B 함수에 C++객체가 존재할 경우 C함수에서 ExitThread 함수로 종료시 A,B 함수의 소멸자가 호출되지 않아서 메모리 유출현상이 발생되므로 가급적이면 쓰지 않고 Return 되도록 해야한다.

  4. ExitThread & TerminateThread 차이점

    • VOID ExitThread(DWORD dwExitCode) / BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)

      1. ExitThread : 실행중인 스레드의 특정 위치에서 스레드를 종료

        TerminateThread 는 인수로 전달받은 스레드를 강제로 종료시킬 때 사용된다.

  • 스레드 중지/재실행

    • SuspendThread(HANDLE hThread) : 중지카운트 증가

    • ResumeThread(HANDLE hThread) : 중지카운트 감소(0이 될 경우 재실행됨)

  • UI 스레드

    • 작업스레드 : 사용자 눈에 보이지 않고 내부적인 계산만 하고 사라지는 스레드

    • UI 스레드 : 윈도우를 만들고, 메시지 큐와 메시지 루프를 가지는 스레드

예)

RegisterClass(~)

DWORD WINAPI ThreadFunc(LPVOID temp)

{

  CreateWindow(~);

while(GetMessage(~))

{

TranslateMessage

DispatchMessage

}

}

LRESULT CALLBACK DeCompProc(~)

{

}

  • 스레드 우선순위

    • 스레디의 우선 순위는 우선 순위 클래스, 우선 순위 레벨 두가지 값의 조합으로 결정함.
    1. 우선순위 클래스(프로세스) CreateProcess(6번째 인자 세팅)

      DWORD GetPriorityClass(HANDLE hProcess);

      BOOL SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass);

    2. 우선순위 스레드(스레드)

      int GetThreadPriority(HANDLE hThread);

      BOOL SeThreadPriority(HAND hThread, int nPriority)

  • C런타임 라이브러리

  • C,C++ 코드로 작성하는 경우 WINAPI 제공하는 CreateThread 사용은 문제가 생길 수 있으므로 _beginThreadex, _endthreadex 써야함.
  1. _beginthread, _beginthreadex 차이점

    _beingthread는 새로운 스레드 생성하고 난 후 내부적으로 CloseHandle 함수 호출되서 생성된 스레드 핸들러 제거시킴

    _beingthreadex 핸들을 리턴(형변환 해야함), CloseHandle 함수가 내부호출을 안하므로 명시적으로 함수를 호출해 줘야한다.

예)

unsigned __stdcall SecondThreadFunc(void *pArg)

{

~

_endthreadex(0);

}

void main()

{

HANDLE hThread;

hThread = (HANDLE)_beginthreadex(NULL, 0, SecondThreadFunc, null, 0, &threadID);

CloseHandle(hThread);

}

  • TLS(스레드 지역 저장소)
  1. TLS(Thread Local Storage)
  • 전역변수나 정적변수에 스레드가 공유하는 문제점을 해결하기 위해서 나오게 되었음
  1. TLS 함수
  • 인덱스 값 얻어오기(슬롯 할당) / 슬롯 해제하기

    TlsIndex= TlsAlloc(); TlsFree(TlsIndex);

  • 슬롯에 값 세팅 / 슬롯 값 얻어오기

    TlsSetValue(TlsIndex, (LPVOID)0); tcount=(int)TlsGetValue(TlsIndex)+1;

  • 동기화

    • 복수 개의 스레드가 보조를 맞추어 실행하도록 함으로써 경쟁 상태나 교착상태를 해소하는 것
  1. DeadLock(교착상태) - 대기 상태가 종료되지 않아 무한정 대기만 하는 비정상적인 상태

ThreadFunc1

EnterCriticalSection(&crit1); - 1

EnterCriticalSection(&crit2); - 3

LeaveCriticalSection(&crit2);

LeaveCriticalSection(&crit1);

ThreadFunc2

EnterCriticalSection(&crit2);

EnterCriticalSection(&crit1); - 2

LeaveCriticalSection(&crit1);

LeaveCriticalSection(&crit2);

  1. 크리티컬 섹션/ 뮤텍스/ 세마포어 차이점

    1. 크리티컬 섹션 : 유저모드 객체, 가볍고 빠르다.

                         같은 Process 내의 Thread 동기화 지원
    2. 뮤텍스, 세마포어 : 커널모드 객체, 상대적으로 무겁고 느린편

                             여러 Process의 Thread간의 동기화를 지원
    3. 뮤텍스, 세마포어 차이점 : 뮤텍스는 임계구역 접근 Thread는 한개

                                       세마포어 임계구역 접근 Thread 갯수 조절
  2. CriticalSection(임계영역)

    • 중단해서는 안되는 코드 블록

    • CRITICAL_SECTION 함수

      1. InitializeCriticalSection, DeleteCriticalSection - 초기화 / 파괴

      2. EnterCriticalSection, LeaveCriticalSection - 구간의 시작을 명시 / 섹션을 빠져나올 구간

  3. 뮤텍스

    • WaitForSingleObject, WaitForMultiIObject

    • CreateMutex, OpenMutex, ReleaseMutex

  4. 세마포어

  • CreateSemaphore, OpenSemaphore, ReleaseSemaphore CreateSemaphore 2번째 인자 : 임계영역 갯수, 3번째 인자 : 임계영역 접근 갯수
  1. 이벤트
  • CreateEvent, OpenEvent, SetEvent, ResetEvent
    1. 2번째 인자 TRUE : 수동리셋 이벤트 FALSE 자동리셋 이벤트
    2. 3번째 인자 TRUE : 이벤트를 생성함과 동시에 신호상태를 만든다.

동적링크라이브러리

  • 정적링크 & 동적링크

  • DLL 사용 장점

  1. 여러 프로그램이 동시에 사용하기 때문에 메모리 절약

  2. DLL을 사용하는 프로그램은 크기가 작다.(정정링크 실행파일이 커진다.)

  3. DLL을 교체하여 프로그램의 성능을 향상시키기 쉽다.(교체시 DLL만 바꾸면됨)

  4. 리소스 교체가 가능(다국어버전)

  5. 디버깅 용이(DLL 버그 없다는 것을 가정)

  6. 혼합 프로그래밍 가능(어떤 개발툴과도 호환가능)

  7. 프로그래머끼리 분담 작업이 용이하며 재사용도 뛰어나다

  • DLL 사용단점
  1. DLL 없다거나 손상된 경우 실행이 불가능

  2. DLL 버전 변경 시 프로그램 호환이 안될 경우 발생

  • DLL Export 되는 함수 / DLL Import 하는 함수
  1. extern “C” **declspec(dllexport) 함수 원형 -**declspec : 함수에 대한 정보를 제공

    extern “C” __declspec(dllimport) 함수 원형

  • 임포트 라이브러리 : 실제 코드는 없고 함수에 대한 위치 정보만 저장함.
  • DLL 파일 찾는 순서

    =1. 클라이언트 프로그램이 포함된 디렉토리

     2. 프로그램의 현재 디렉토리
    
     3. 윈도우즈의 시스템 디렉토리
    
     4. 윈도우즈 디렉토리
    
     5. PATH 환경 변수가 지정하는 모든 디렉토리
  • 임포트 라이브러리 지정 : #pragma comment(lib, “MyDll.lib”)

  • 명시적 연결(DLL을 명시적으로 읽고 사용)

    1. HINSTANCE LoadLibrary(LPCTSTR lpLibFileName)

    2. FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName)

    hInst = LoadLibrary(TEXT(“MyDll.dll”));

    pFunc = (int (*)(int, int))GetProcAddress(hInst,“AddInteger”);

  • 명시적 연결 장/단점

    1. 필요할 때만 DLL을 읽어와 사용하기 때문에 메모리와 리소스가 절약된다.

    2. 사용할 DLL을 교체(DLL 이름만 상황에 맞게 교체)

    3. 필요한 DLL이 없는 경우에도 프로그램 실행가능

    4. 클라이언트 프로그램 시작이 빠르다.

    단점 : 함수 호출 속도가 느려진다.

  • DllMain 함수

    BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpRes);

    -DLL이 처음 메모리에 올라오고 제거시에 위 함수가 호출됨.

    fdwReason : 함수가 호출된 이유
    
    1) DLL_PROCESS_ATTACH / DLL_PROCESS_DETACH
    
        DLL_THREAD_ATTACH / DLL_THREAD_DETACH

메모리

  • C 런타임 함수 ( 물리적인 메모리 소비)

    • void *malloc(size_t size);

      void *calloc(size_t num, size_t size); // 필요한 메모리 양을 논리적으로 표현

      void *realloc (void *memblock, size_t size); // 이미 할당한 메모리를 더 크게 할당하고 축소할 때

      void free(void* memblock);

  • 가상메모리 할당

    1. 장점
    • 메모리 예약 할당 가능( 물리메모리 소비하지 않으면서 할당가능)

    • 할당한 메모의 액세스 권한 설정가능

  LPVOID VirtualAlloc(LPVOID lpAdress, DWORD dwSize, DWORD flallocationType, DWORD flProtect);

  BOOL VirtualFree(LPVOID lpAddress, DOWRD dwSize, DWORD dwFreeType);

  ptr = (int*)VirtualAlloc(NULL, sizeof(int)*10, MEM_RESERVE|MEM_COMMT, PAGE_REDWRITE);

  wsprintf(str "%d", ptr[i]*i*2);

  TextOut(hdc, 10, i\*20, str, lstrlen(str));

  VirtualFree(ptr, sizeof(int)\*10, MEM_DECOMMIT);

  VirtualFree(ptr, 0, MEM_RELEASE);

동기화

  1. 동기화 필요성
  • 단일 프로세서를 이용한 선점형 멀티스레딩 시스템은 여러개의 스레드가 마치 동시에 수행되는 것처럼 보이지만 오직 하나의 스레드만 실행됨 그럴때 공유자원에 대한 스레드의 선점에 문제가 발생하는 것을 해결하기 위해서 동기화가 필요해졌다.
  1. 동기화함수
  1. 크리티컬 세션 : 유저레벨 동기화(커널 객체x), 동일한 프로세스내에서만 사용, 속도 높음

  2. 뮤텍스 : 커널객체 사용(CreateMutex, OpenMutex, ReleaseMutex, CloseHandle), 하나의 공유자원 보호

    • 포기된 뮤텍스 : 뮤텍스 점유 중 스레드를 죽이는 Terminatethread, ExitThread 사용할 경우 -waitforsingleobject return 값이 WAIT_ABANDONED 리턴함.
  3. 세마포어 : 사용가능한 자원의 갯수를 카운트 하는 동기화 객체( CreateSemaphore, OpenSemaphore, ReleaseSemaphore)

  1. 이벤트
  1. 스레드간의 작업순서나 시기조정, 신호를 보냄

  2. CreateEvent(. bManualReset,,) bManualReset = True 수동(ResetEvent, SetEvent 사용해야함) False 자동

이전글
C/C++
다음글
MSSQL