커널 오브젝트 : Windows 운영체제에서 리소스(Resource : 프로세스, 쓰레드, 파일)들을
                      관리하기 위한 데이터를 저장하는 메모리 블록



Windows에서 관리하는 리소스 특성을 변경하기 위해서는 해당 리소스의 커널 오브젝트를 조작해야한다.

해당 리소스의 정보를 저장하고 있는 커널 오브젝트에 접근하기 위해서는

커널 오브젝트들을 구별하는 커널 오브젝트 핸들(Object Handle)을 얻어야 한다.



커널 오브젝트와 핸들 :

커널 오브젝트는 Windows 운영체제에 종속적이다.

사용자가 리소스 생성을 요청하면 운영체제에서 사용자가 요청한 대로 리소스를 생성하게 되고

이를 관리하기 위해 커널 오브젝트를 생성한다.

즉, 커널 오브젝트는 Windows 운영체제에 의해 생성 및 소멸이 결정된다.


리소스가 생성되어 커널 오브젝트가 생성되면 커널 오브젝트에 핸들이 부여되고

부모 리소스도 구조체 변수를 통해 자식의 커널 오브젝트 핸들을 획득할 수 있다.

즉, 부모와 자식이 자식의 커널 오브젝트를 공유한다.


예)

부모 프로세스가 자식 프로세스의 커널 오브젝트 핸들 획득.

typedef struct _PROCESS_INFORMATION
{
      HANDLE hProcess;            // 커널 오브젝트 구분 위한 핸들
      HANDLE hThread;
      DWORD dwProcessId;        // 프로세스 구분 위한 ID
      DWORD dwThreadId;         
} PROCESS_INFORMAION;

위 구조체는 CreateProcess 호출할때 인자로 전달되는 구조체이다.(&pi)
호출이 완료되면 이 구조체에 자식 프로세스의 커널 오브젝트 핸들값이 hProcess 에 저장된다.

자신의 커널 오브젝트 핸들 획득.

GetCurrentProcess()

위함수를 사용하면 자신의 커널 오브젝트 핸들값을 리턴한다.



커널 오브젝트와 Usage Count :

운영체제는 해당 커널 오브젝트를 참조하는 대상이 하나도 없을때 커널 오브젝트를 소멸시킨다.

참조하는 대상은 Usage Count(참조 횟수)로 관리한다.

즉, Usage Count = 0 일 때 커널 오브젝트를 소멸한다.

리소스의 생성과 동시에 해당 커널 오브젝트의 Usage Count = 1 이된다.
생성이 완료되면 부모가 자식 리소스 커널 오브젝트의 핸들을 획득하기에 Usage Count = 2 가 된다.

만약 자식 리소스를 소멸하면 Usage Count 가 하나 줄어든다.

여기서 문제가 발생한다. 리소스가 소멸됬음에도 그 리소스를 관리하는 커널 오브젝트는 소멸되지 않는다.
(Usage Count 가 1이므로)

Usage Count = 0 을 만들기 위해선

부모의 자식의 커널 오브젝트 참조를 해제해야 한다.

CloseHandle() 함수를 사용하면 자식의 커널 오브젝트 핸들을 반환하여 참조를 해제한다.

즉, Usage Count 가 하나 줄어든다.

따라서 커널 오브젝트를 소멸하기 위해서는

부모가 소유한 자식의 커널 오브젝트 핸들을 반환해야 한다.


예)

부모 프로세스가 자식의 커널 오브젝트 핸들을 반환하지 않아 커널 오브젝트가 소멸되지 않았다고 가정할때

계산기 프로세스를 생성하면 그에 따른 커널 오브젝트가 생성된다.

계산기 프로세스를 종료시켜도 커널 오브젝트는 소멸되지 않는다(Usage Count =  1이므로 )
 
실행-> 종료, 실행 -> 종료 를 반복한다고 할때

커널 오브젝트는 실행의 수만큼 존재한다.

따라서 이 문제를 해결하기 위해 CloseHandle 을 통해 부모의 자식의 커널 오브젝트 참조를 해제함으로써

자식 프로세스가 종료될때 Usage Count = 0 이 되어 커널 오브젝트가 소멸된다)


(참고 :

바탕화면에서 아이콘을 통해 프로세스를 생성할 경우에도 Usage Count = 2 다.

바탕화면 자체도 프로세스이기 때문이다. 이 때는 바탕화면이 부모 프로세스가 된다.
(Cmd 에서 실행하면 Cmd 가 부모 프로세스)

즉, 프로세스는 생성과 동시에 Usage Count = 2 가 된다)

Posted by Dakuo

시스템 프로그램(System Program)

: 컴퓨터 시스템을 동작시키거나 하드웨어를 사용할 수 있도록 도와주는 프로그램



1. 컴퓨터 시스템의 주요 구성요소(Main Components)

컴퓨터 구조(Computer Architecture) : CPU <-> 캐쉬(Cache)
                                     
                                           ↕

운영체제(Operating System) : 메인 메모리(Main Memory) <-> 하드디스크(Hard Disk)



2. 컴퓨터 구조 :


1) CPU : 중앙처리장치(Central Processing Unit)

ALU(Arithmetic Logic Unit) : CPU 내부에 실제 연산을 담당하는 부분. 산술연산(+, -)과 논리연산(AND, OR)을 수행

컨트롤 유닛(Control Unit) : CPU 내부로 들어온 명령어를 해석해서 ALU 에게 전달한다.

레지스터(Register Set) : CPU 내부에 임시적으로 데이터(2진 데이터 : Binary Data, CPU에 따라 16, 32, 64 비트
저장가능)를 저장하기 위한 메모리 공간

버스 인터페이스(Bus Interface) : CPU 내에 I/O 버스의 통신 프로토콜(Protocol)을 이해하고 있는 장치

클럭 신호(Clock Pulse) : 클럭발생기에 의해 발생되며 이 신호에 맞춰 CPU를 구성하는 요소들이 일을 한다. 

(추가  : 클럭신호의 필요성(동기화)


위와 같은 그림에서 만약 클럭 신호가 없다고 가정하고 각각의 작동의 속도가 다르다고 가정하자.

예상 작동 : input 1에서 1, input 2에서 2의 숫자가 입력됬다. +연산장치가 연산을 해서 버퍼에 넘기고 출력장치가 버퍼에 있는 값을 읽어 3이라는 값을 출력했다

실제 작동 : input 1에서 1, input 2에서 2의 숫자가 입력됬다. 하지만 +연산을 하기도 전에 출력장치가 버퍼(Buffer)에 있는 쓰레기 값을 읽어 출력해버렸다.

여기서 + 연산의 속도와 출력장치가 버퍼를 읽는 속도의 차이 때문에 정상적으로 작동을 하지 못했다.
즉 장치마다의 속도차이가 존재하기에 동기화가 필요한것이다.
따라서 속도가 느린 장치에 맞춰 일을 시키면 정상적으로 작동을 할것이다.

동기화 작동 : input 1에서 1, input 2에서 숫자가 입력됬다. 클럭신호를 + 연산장치에 맞춰놓아서 +연산이 될때 출력장치가 버퍼의 3을 읽어와 출력을 한다)


2) 메인 메모리(Main Memory)

컴파일이 완료된 프로그램 코드가 올라가서 실행되는 영역


3) 입 · 출력 버스(Input / Output Bus)

컴퓨터를 구성하는 요소 사이에서 데이터를 주고 받기 위해 사용되는 경로이다.

버스 시스템(Bus System)은 데이터 종류에 따라

1. 데이터 버스(Data Bus) : 데이터를 이동하기 위한 버스(명령어, 피연산자 등)

2. 어드레스 버스(Address Bus) : 주소값을 이동하기 위한 버스

3. 컨트롤 버스(Control Bus) : 명령을 주고 받는 버스

예)

CPU : "데이터 보내"                              // 컨트롤 버스
Memory : "몇번지에 있는 데이터?"          // 컨트롤 버스
CPU : "0x000012"번지                            // 어드레스 버스
Memory : "20"                                      // 데이터 버스



3. 프로그램 실행 과정

1단계 : 전처리기 -> 컴파일러 -> 어셈블러 -> 링커 -> 실행파일

2단계 : 실행파일 -> 로드 -> 메모리

3단계 : 메모리 -> Fetch -> Decode -> Execution


1단계(실행파일 작성) :

1. 전처리기 : '#'으로 시작하는 지시자의 지시에 따라서 소스코드를 변경한다.
                   (참고 : #pragma지시자 는 - #이 붙어있어서 전처리 명령처럼 보이지만 컴파일러 지시자이다)

2. 컴파일러 : C 언어 등으로 구성된 전처리기를 거친 소스코드를 어셈블리 코드로 번역한다

3. 어셈블러 : 어셈블리 코드를 CPU가 이해할수 있는 바이너리 코드로 바꾸어 준다.

(참고 : 바이너리 코드(Binary)와 어셈블리 코드(Assembly)

CPU를 디자인하는 개발자가 만약 덧셈 명령어를 1111 이라고 정했다고 치자. 만약 1+2를 시킨다면
0001 1111 0010  이런 코드(바이너리 코드)를 구성해야 하는데 이것은 매우 알아보기 힘들다.

따라서 이걸 사람이 좀더 보기 쉽게

1111 를 ADD 로 하기로 하고 표를 만들어 둔다. 이제 소스를 작성할때 1+2를 시킨다면
0001 ADD 0010 이런식으로 작성하면 된다.(한결 보기 쉬울것이다) 이것이 어셈코드이다.

어셈블러는 이런 표를 참조해 ADD -> 0011 로 바꾸는 작업을 하는 프로그램이다)


4. 링커 : 프로그램 내에서 참조하는 함수나 라이브러리들을 하나로 묶고 연결시켜주는 작업을 한다.
(1단계를 마치면 실행파일이 생성된다. (바이너리 코드로 구성되있다))


2단계(실행파일 실행) :

실행파일을 실행시키면 메모리에서 로드(Load)를 해서 이 실행파일의 코드(바이너리 코드)들이 메모리에 저장된다.


3단계(실제 작동) :

1. Fetch : 메모리상에 존재하는 명령어를 CPU로 가져 오는 작업이다.(레지스터에 일단 저장한다)

2. Decode : 가져다 놓은 명령어를 CPU가 해석하는 단계이다.(컨트롤 유닛에서 수행한다)

3. Execution : 해석된 명령어대로 CPU가 실행한다.(ALU에서 수행한다)

Posted by Dakuo

파일시스템(File System) : 운영체제(OS)가 하드디스크에 데이터를 읽고, 쓰고 찾는, 파일을 관리하기 위한 규칙



FAT32 : File Allocation Table 32 (파일 할당 테이블)

Sector(섹터)를 몇개의 최소 단위로 묶어서 각각의 묶음(클러스터 : Cluster)을 기본단위로 파일을 저장한다.


예를 들어

1MB의 디스크가 있다고 하면

1 Sector = 4096 byte (4kb)

1MB = 1024KB = 4KB*256

즉 섹터수는 256개이다.

FAT32 시스템은 이 256섹터를(2섹터 = 1클러스터로 가정) 클러스터로 묶어서 128 클러스터로 나타낸다.

이 클러스터들에 번호를 붙여서 파일을 저장하고 검색하는 기준으로 삼는다.
(색인이라고 보시면 됩니다)


클러스터 수의 효율 :

클러스터 수 ↑(섹터를 더 많은 클러스터로 나눔)

: HDD의 공간 낭비는 줄어들지만 검사해야할 클러스터(색인)의 수가 많아지므로 그만큼 파일을 읽고 쓰는데 오래걸린다.

클러스터 수 ↓(섹터를 더 적은 클러스터로 나눔)

: HDD의 공간 낭비가 늘어나지만 검사해야할 클러스터(색인)의 수가 적어지므로 파일을 읽고 쓰는데 속도가 향상된다.


(참고 : 클러스터로 대용량을 표현하는데 한계가 있기 때문에 대용량 하드에서는 FAT32 시스템을 사용할 수 없다.
(FAT32 시스템은 1TB(2000GB)까지 지원합니다. (XP는 32GB까지만 지원) 최대 단일 파일의 크기는 4GB)
클러스터는 원래 플로피 디스크를 위해서 만들어진 것이었다

또 클러스터 수가 줄어들면 HDD의 공간 낭비가 심해지는 이유는 

클러수터 수 ↓ -> 클러스터 용량 ↑ 이므로

클러스터 용량이 4KB라고 할때 2KB 파일을 저장하면 이 파일 하나가 4KB의 클러스터를 독점하게 된다.

따라서 저장하고 남은 2KB는 낭비가 되는 것이다)



NTFS : NT File System

윈도우 NT에 기반을 둔 파일 시스템으로 FAT32 시스템에 보안기능, 압축기능, 원격 저장소 기능 등
성능을 업그레이드 시켰다.

FAT32 와 다르게 클러스터를 쓰고 남은자리에 이어서 파일을 저장할 수 있다.

클러스터 크기도 FAT32보다 작을수 있어(HDD공간 낭비↓  , 속도↓) 보다 HDD를 효율적으로 사용할수 있다.
(클러스터 수와 속도의 관계는 여전합니다)

160억GB의 용량을 지원한다(이론상). 파일크기는 제한이 없다.
(클러스터의 용량이 부족하면 다음 클러스터에 이어서 저장할 수 있으므로)

Window XP 부터 사용 가능하다.

Posted by Dakuo
이런 생각을 많이 해보셨을 것이다.

하나의 하드에 여러개의 운영체제(OS)를 설치해서 그중에 하나를 골라서 부팅하고 싶다.

가장 간단한 방법은 Vmware를 설치해서 그안에 여러개의 운영체제를 설치하여 실행하는 방법일 것이다.

하지만 그방법말고 하드에 여러개의 운영체제를 설치해서 멀티부팅(Multi booting)해보자.

기본개념은 http://dakuo.tistory.com/entry/파티션Partition의-개념 이다.
(최대 4개의 주파티션을 설정할수 있다. 따라서 운영체제도 4개까지 설치가능하다)

기본적으로 MBR에는 하나의 부트레코더만 기록할수 있으므로 여러개의 운영체제를 설치하여 멀티부팅한다는 것은 불가능하다. 하지만 하나의 더미 부트레코더를 MBR에 설치해서 그것을 부팅시킨 후에 거기서 여러개의 주파티션 부트섹터에 접근한다면 여러개의 운영체제중에 골라서 부팅하는것이 가능하지 않을까?

이러한 기능을 수행하는것이 GRUB이다. (제가 아는건 이거 하나..)
이것은 대부분 리눅스에서 사용하는 부팅방식인데 리눅스 부트레코더를 주파티션의 부트섹터에 설치하고 GRUB 라는 부트 레코더를 MBR에 설치한 후에 MBR에서 GRUB를 부팅시키고 그 GRUB에서 주파티션 부트섹터에 있는 리눅스 부트레코더를 실행시키는 방법이다.

즉, MBR(GRLDR(GRUB)) -> Primary(Linux) 이런식의 부팅방법이다.(어느 주파티션의 부트섹터를 읽은것인지 선택가능하다)
(참고 : 윈도우의 경우에는 MBR(NTLDR)) ->  Activate Primary(window))


전 개념을 설명드린거고

실제 구현하실분들은

http://cafe.naver.com/gigicom.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=18835

여기를 참조하세요 설명이 잘되있네요
Posted by Dakuo
파티션(Partition)이란 쉽게 말하면 방입니다.

하나의 집에(물리적인 하드디스크) 여러개의 방(partition 파티션)을 만드는 것이죠.

방에는 2 종류가 있습니다.

1. 살림을 차릴수 있는 원룸(Primary 주파티션)

2. 잠만 잘수 있는 방(Logical 논리드라이브)



하드디스크(Hard Disk)의 구조를 대략적으로 표현한 그림입니다.


1. MBR : Master Boot Recoder

하드에서 가장 먼저 읽히는 부분이다. 하드디스크의 전체적인 관리를 한다고 볼수 있다.
4개의 파티션을 관리할수 있다.
(참고 : 최대 나눌수 있는 파티션은 주파티션 3 + 확장파티션(논리 4개) = 7개입니다)
 
또 주파티션마다 각각의 부트섹터(BootSector)가 할당되는데 이럴 경우 컴퓨터가 어느곳의 부트섹터를 읽어서 부팅을 해야하는지 모른다. 따라서 운영체제를 설치하게 되면 하드에서 가장 먼저 읽히는 MBR에 자신의 부트레코더(BootRecoder)를 기록하여 자기가 실행되게 된다.


2. 주파티션 : Primary

파티션 앞에 부트섹터가 할당되어서 운영체제를 설치 할 수 있다. 주파티션에 운영체제(OS)를 설치하게 되면 부트 섹터에 부트레코더를 기록하게 되고 MBR에도 기록한다.

2-1 활성 주파티션 : Activate Primary

활성주파티션이란 MBR에 부트 레코더가 기록된 파티션을 말한다.

예를 들어 하나의 하드디스크에 주파티션을 2개 설정한 후 첫 파티션에 XP를 2번째에 Vista를 설치하였다. 이때 각각의 주파티션 부트섹터에는 이 운영체제들의 부트레코더가 기록된다.
이중에 하나는 MBR에 적재되는데 만약 XP 부트레코더가 적재됬으면 이 첫번째 파티션이 활성 주파티션이 된다.(MBR에는 하나의 부트레코더만 기록되므로 활성주파티션은 하나다)


3. 확장파티션 : Extended

논리드라이브(Logical)들을 감싸는 벽이라고 생각하면 된다.
확장파티션은 하나의 물리디스크에 하나만 설정할 수 있으며 4개의 논리드라이브를 가질수 있다.


4. 논리드라이브 : Logical

데이터를 저장할수 있는 드라이브다. 부트섹터가 없으므로 운영체제는 설치할 수 없다.
Posted by Dakuo
타이머 :

한 번 지정해 놓기만 하면 일정한 시간 간격을 두고 연속적으로 게속 발생한다. 주기적으로 같은 동작을 반복해야 한다거나 여러 번 나누어 해야 할 일이 있을 때 이 메시지를 이용한다.

타이머 메시지를 사용한 예제이다.
(윈도우 프로그램 기본틀에 수정을 하면 된다 http://dakuo.tistory.com/entry/1)

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,
                                              WPARAM wParam, LPARAM lParam)
{
      HDC hdc;
      PAINTSTRUCT ps;
      static HANDLE hTimer;
      SYSTEMTIME st;
      static char sTime[128];

      switch(iMessage)
      {
             case WM_CREATE:
                     hTimer = (HANDLE)SetTimer(hWnd, 1, 1000, NULL);
                     return 0;
             case WM_TIMER:
                     GetLocalTime(&st);
                     wsprintf(sTime, "지금 시간은 %d:%d:%d 입니다",
                                               st.wHour, st.wMinute, st.wSecond);
                     InvalidateRect(hWnd, NULL, TRUE);
                     return 0;
             case WM_PAINT:
                     hdc = BeginPaint(hWnd, &ps);
                     TextOut(hdc, 100, 100, sTime, strlen(sTime));
                     EndPaint(hWnd, &ps);
                     return 0;
             case WM_DESTROY:
                     KillTimer(hwnd, 1);
                     PostQuitMessage(0);
                     return 0;
        }
        return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

(참고 : 현재 시간을 구할 때는 GetLocalTime 함수에 SYSTEMTIME 구조체를 넘겨준다)

WndProc 선두에

static HANDLE hTimer;              // 타이머 핸들 hTimer 선언
SYSTEMTIME st;                      // SYSTEMTIME 구조체 st 선언 
static char sTime[128];             // 시간값을 문자열로 변경하여 저장할 sTime 문자열 선언

WndProc 에서 첫 번째로 처리하는 메시지는 WM_CREATE 메시지다. 윈도우가 처음 생성될 때 발생하는데 이 메시지에서 프로그램 시작시 꼭 한 번만 초기화되어야 할 처리를 해 준다.
(예 : 프로그램 실행에 필요한 메모리 할당, 전역변수에 초기값을 대입하는 등의 초기화처리)
이 예제에서 WM_CREATE 메시지에서 SetTimer 함수를 사용하여 타이머를 생성시켰다.

UINT SetTimer(HWND hWnd, UINT nlDEvent UINT uElapse, TIMERPROC lpTimerFunc)

hWnd 인수는 타이머 메시지를 받을 윈도우인데 통상 WndProc의 파라미터로 전달되는 hWnd를 써준다.

두 번째 파라미터 nlDEvent는 타이머의 번호를 지정한다. 하나의 타이머만 사용할 경우 1을
여러 개의 타이머를 사용할 경우 nlDEvent 에 겹치지 않도록 번호를 부여한다.
(예 : 세 개의 타이머를 사용하면 1, 2, 3 의 타이머 번호를 부여)타이머 번호는 WM_TIMER
메시지에서 타이머를 구분하기 위한 표식으로 사용한다.
(참고 : 두 개의 타이머를 사용할 경우에도 발생하는 메시지는 WM_TIMER 로 동일하다.
다만 wParam 으로 전달되는 타이머의 ID 를 통해 이 메시지가 어느 타이머에서 발생했는지를 체크하여 두개의 타이머를 효율적으로 조절할수 있다)

세 번째 파라미터 uElapse 는 1/1000 초 단위(ms, 기본단위)로 타이머의 주기를 설정한다.
(참고 : 타이머의 최대 해상도는 Windows NT/2000 에서 0.01초에 불과하기 때문에 주기를 아무리 짧게 해도 타이머 메시지는 1초에 100회 이상 발생하지 않는다 또 ms가 기본단위인 이유는 cpu clock time이 ms단위이기 때문이다)

네 번째 파라미터는 타이머 메시지가 발생할 때마다 호출할 함수를 지정한다. 사용하지 않을 경우 NULL로 설정한다.
(참고 : SetTimer의 리턴값은 첫 번째 파라미터가 NULL 일 경우에 한해 특별하게 사용하는 것이며 거의 사용되지 않는다)

이제 ID 1번으로 1초 간격으로 WndProc에 WM_TIMER 메시지가 전달된다.
(참고 : WM_TIMER 메시지는 wParam 으로 타이머 ID를 전달하며 lParam 으로 타이머
메시지 발생시 호출될 함수의 번지가 전달된다)

case WM_TIMER:
         GetLocalTime(&st);
         wsprintf(sTime, "지금 시간은 %d:%d:%d 입니다",
                                               st.wHour, st.wMinute, st.wSecond);
         InvalidateRect(hWnd, NULL, TRUE);
         return 0;

WM_TIMER 메시지가 발생하면 GetLocalTime 함수로 시간을 조사한 후 출력을 위해 wsprintf로 sTime 문자열로 변환해 둔다. 또 시간이 WM_TIMER 메시지가 올 때마다 값을
갱신시키기 위해 InvaildateRect 함수를 호출한다.

WM_PAINT 에서는 sTime 문자열을 TextOut 으로 출력한다.

BOOL KillTimer(HWND hWnd, UINT ulDEvent);

타이머는 시스템 전역 자원이므로 필요가 없어지면 제거해 주는 것이 좋다. KillTimer 의
첫 번째 파라미터로 이 타이머를 소유한 윈도우 핸들을 넘겨 주며 두 번째 파라미터로 타이머 ID를 넘겨 준다.

이렇게 하면 여러 문제가 생긴다.
첫 번째 문제는 프로그램이 실행 된 후 1초 뒤에 시간이 보인다는 것이다.
SetTimer에서 1초 간격으로 WM_TIMER 메시지를 발생시키므로 프로그램 실행 후 1초 뒤에 시간이 보이는 것이다. 따라서 프로그램이 실행 직후에 강제로 WM_TIMER 메시지를 발생시켜야 한다.

LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

(참고 : 메시지는 사용자의 동작에 의해서나 시스템의 상황 변화에 따라 발생하는 것이 원칙이지만 강제로 메시지가 발생한 것처럼 만들어야 할 때도 있다. 이때 SendMessage를 사용하여 hWnd 윈도우로 Msg 메시지를 보낸다
메시지 기반의 운영체제인 윈도우즈에서 SendMessage 는 빈번히 사용되는 중요한 함수다.
어떤 종류의 메시지도 누구에게나 보낼 수 있으며 차일드 컨트롤을 프로그래밍하는 중요한 수단이다)

WM_CREATE 메시지 처리에 SendMessage(hWnd, WM_TIMER, 1, 0); 을 추가한다.

두 번째 문제는 비효율적이라는 것이다.
단 한줄의 텍스트를 갱신하기 위해서 우리는 지금 화면 전체를 갱신하고 있다.

InvalidateRect(hWnd, NULL, TRUE);

hWnd 윈도우를 무효화 시키되 두 번째 파라미터가 NULL 이므로 화면 전체가 무효화 되며
세 번째 파라미터가 TRUE 이므로 화면을 지운후 다시 그리게 된다.

따라서 무효화 영역을 최소화 하여 꼭 필요한 부분만 무효화하도록 해야 한다.

static RECT rt = {100, 100, 400, 120}; 사각형을 만든 뒤
InvalidateRect(hWnd, &rt,TRUE); 에 NULL 대신 만든 사각형 rt 을 넣어준다.

이제 rt 영역 외에는 지우지도 그리지도 않게 되므로 프로그램의 속도가 향상된다.
이런 처리들을 깔끔하게 해줄수록 프로그램의 질이 향상된다.


콜백함수(Callback Function) :

일반적으로 API 함수들은 운영체제가 제공하며 프로그램에서는 이 함수들을 호출해서 운영체제의 서비스를 받는다. 하지만 콜백함수는 응용 프로그램이 제공하며 운영체제가 필요할 때 호출하는 함수이다. 호출되는 방향이 거꾸로 되었기 때문에 콜백이라 부른다.
즉, 운영체제에 의해 호출되는 프로그램 내부의 함수이다.


콜백함수는 조건이 될 때 시스템이 불러주는 함수이므로 그 원형이 미리 정해져 있다. 운영체제가 어떤 특정한 때에 특정한 파라미터와 함께 호출하기로 약속이 되어 있으므로 원형은 반드시 지켜야 한다.
(참고 : 이름은 마음대로 붙여도 상관없다)


만약 프로그램이 실행되는 동안 지속적으로 수행해야 할 작업이 있다면 DOS의 경우에는

while(1)
{
      작업;
}

위와 같이 코드를 작성할 것이다.

하지만 윈도우즈와 같은 멀티 태스킹에서는 이런 방식으로 해서는 안된다. 한 프로그램이 제어권을 독점하여 다른 프로그램에 실행시간을 주지 못하기 때문이다.

또한 같은 프로그램으로 전달 되는 다른 메시지도 처리해야 하는데 무한 루프에서 CPU를
독점하면 다른 작업은 전혀 할수가 없다. 따라서 메시지가 전달 되었을 때에 한해 필요한 작업을 하도록 해야 한다. 이때 타이머 메시지를 사용하여 구현할 수 있다.

SetTimer 의 네 번째 파라미터는 TIMERPROC lpTimerFunc 인데 타이머 프로시저 함수의 포인터를 가리킨다. 매 시간마다 이 포인터가 가리키는 함수가 대신 호출된다.
즉, 지정한 시간 간격으로 WM_TIMER 메시지 대신 네 번째 파라미터의 함수가 호출된다.
(참고 : NULL 일 경우 첫 번째 파라미터로 넣어준 hWnd로 WM_TIMER 메시지가 전달된다)
타이머 함수는 다음과 같은 원형으로 작성된다.

VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);

4개의 파라미터를 가지는데 hwnd는 타이머를 소유한 윈도우의 핸들, uMsg 는 WM_TIMER, idEvent 는 타이머 ID, dwTime 은 윈도우즈가 실행된 후의 경과시간이다.
(참고 : 콜백함수를 사용하여 이 문제를 해결할 수 있지만 WM_TIEMR 메시지를 받아 처리를 할 수도 있다(네 번째 파라미터에 NULL) 하지만 WM_TIMER 메시지는 다른 메시지가 있을 경우 실행 순서에 밀려 늦게 호출되는 경우가 있지만 콜백함수는 정확한 시간에 호출된다. 따라서 정확도를 위해 콜백함수를 사용한다)

'Windows > _Windows Programming' 카테고리의 다른 글

윈도우 프로그램 기본 틀  (0) 2009.12.23
윈도우 관리 메시지  (0) 2009.12.23
타이머(Timer)  (0) 2009.12.23
입력하기  (0) 2009.12.01
출력하기  (2) 2009.11.28
윈도우 기초 프로그래밍  (0) 2009.11.27
Posted by Dakuo
윈도우즈(Windows)의 장점 :

1. 그래픽 기반의 운영체제이다.

2. 멀티 태스킹이 가능하다.

3. 장치에 영향을 받지 않는다.

4. 일관성



개발툴의 선택 :

1. API :

API(Application Programming Interface) : 운영체제가 응용 프로그램을 위해 제공하는 함수의 집합

2. SDK :

SDK(Software Development Kit) : 윈도우즈를 만든 Microsoft에서 제공하는 윈도우즈용 프로그램 개발 킷이다. API 함수들을 사용하여 프로그램을 작성하며 가장 원론적이고 먼저 발표된 개발방법이다. 섬세하고 막강하며 속도가 빠르고 크기에 유리하나 방대한 API 함수를 알아야 하며 코드가 길어지고 생산성도 낮다.

3. 클래스 라이브러리

API 함수들을 좀 더 쉽고 빠르게 사용하기위해 클래스로 잘 포장하여 클래스 위주로 프로그램을 작성하는 방법이다. 클래스가 잘 설계되어 있어 사용하기도 쉬우며 기능 또한 막강하다.
MFC(Microsoft사)가 대표적이다. 다만 클래스 라이브러리의 문법적 기반인 OOP에 대해 상세히 알아야 하며 API 함수를 기반으로 하기 때문에 API 함수에 대한 기본 개념이 있어야 한다.

4. 비주얼 툴

API는 어렵고 생산성이 너무 떨어지고 클래스 라이브러리도 배우기가 쉽지 않다.
API나 OOP를 몰라도 프로그램을 작성할 수 있는 비주얼 툴이 있다.
그림을 그리듯 화면을 디자인 하며 필요한 곳에만 간단한 코드를 작성하는 개발툴이다.



API 를 알아야 하는 이유 :

1. 운영체제를 이해하기 위해

2. 어차피 알아야 하므로

3. 개발툴이 제공하지 않는 것을 구현하기 위해



API 공부하기 전에 :

1. API 를 사용하기 위해서는 윈도우즈의 표준 언어인 C를 컴파일 하는 컴파일러가 있어야 한다.
또한 API는 C언어로 형식으로 되어 있기에 C 프로그래밍에 대해 어느정도 알고 있어야 한다.



2. 사전 지식 :

2-1. 변수 명명법 :

 접두어  원래말   의미
 cb  Count of Bytes  바이트 수
 dw  double word  부호없는 long형 정수
 h  handle  윈도우, 파일 등의 핸들
 sz  Null Terminated   NULL 종료 문자열
 ch  Character  문자형
 a  Array  배열
 w  Word  부호없는 정수형
 i  Integer  정수형
 b  Bool  논리형

변수명을 나타내는 이런 약속 외에도 윈도우즈는 새로운 데이터형을 만들어서 사용한다.
이 데이터 형은 windows.h 라는 헤더파일에 typedef 로 선언되어 있으며 모든 프로그램에서 표준 데이터형처럼 사용한다.

 데이터형  의미 
 BYTE  unsigned char 형
 WORD  unsigned short 형
 DWORD  unsigned long 형
 LONG  long형과 동일
 LPSTR  char* 와 동일
 BOOL  정수형이며 TRUE, FALSE 중 한값을 가진다


2-2. 핸들에 대한 이해 :

핸들(Handle) : 어떤 대상에 붙여진 번호이며 문법적으로는 32비트 정수값이다.
만들어진 윈도우에는 윈도우 핸들(hWnd)를 붙여 윈도우를 번호로 관리하며 거의 모든 것에 다 핸들을 붙여 구분하는데 그 이유는 문자열 보다 정수를 사용하는 것이 훨씬 더 속도가 빠르고 간편하기 때문이다.

핸들의 특징 :

1. 32비트 정수값이다.

2. 운영체제가 발급해 주며 사용자는 쓰기만 하면 된다. 사용자가 직접 핸들을 만들 경우는 없다.

3. 같은 종류의 핸들끼리는 중복될 수 없다.(단 다른 종류의 핸들은 중복된 값을 가질수도 있다)

4. 핸들의 실제 값을 몰라도 상관없다. 구분을 위한 표식일 뿐이므로 값에 의미를 부여하지 않는다.

핸들은 접두어 h로 시작되며 핸들을 저장하기 위한 별도의 데이터형이 정의되있다.
(HWND, HPEN, HBRUSH, HDC 등이 있다 - 부호없는 정수형)


2-3. 비트 OR 연산자 :

API 함수들은 작업에 대한 세부 정보(옵션)를 파리미터로 전달받는다. 전달 가능한 옵션이 여러 개가 있을 경우 하나의 파라미터에 복수 개의 옵션을 묶어 전달하는데 이때 비트 OR 연산자(|)를 사용한다.


비트 OR 연산자를 사용하면 여러개의 옵션을 묶어서 하나의 정수값만 전달하더라도 함수는 개별 비트를 테스트한 후 어떤 옵션이 선택되었는지 알 수 있다. 각 옵션의 실제값이 어떻게 정의되어 있는가는 알 필요가 없으며 매크로 상수만 알면 된다.
API 함수는 이런식의 파라미터 전달법을 흔히 사용하며 상관없는 옵션들이 하나의 파라미터에 전달되는 경우도 있고 옵션끼리 배타적인 경우도 있다.

'Windows > _Windows Programming' 카테고리의 다른 글

타이머(Timer)  (0) 2009.12.23
입력하기  (0) 2009.12.01
출력하기  (2) 2009.11.28
윈도우 기초 프로그래밍  (0) 2009.11.27
윈도우즈(Windows) 프로그래밍의 기초  (0) 2009.11.27
.xxx 파일 만들기  (2) 2009.11.24
Posted by Dakuo