2010년 7월 8일 목요일

시스템 프로그램 #1

프로세스 : 수행 중인 프로그램의 인스턴스(instance)로서 커널오브젝트와 주소 공간으로 구성
 프로세스의 상위 2GB는 커널 영역, 하위 2GB는 유저 영역

HMODULE과 HINSTANCE는 혼용 가능
GetModuleFileName()
GetModuleHandle()

GetCommandLine()
CommandLineToArgvW()

프로세스의 환경 변수
GetEnvironmentStrings()
FreeEnvironmentStrings()

GetEnvironmentVariable() : 환경 변수의 존재 여부와 값 확인
ExpandEnvironmentStrings()
SetEnvironmentVariable()

프로세스의 선호도
 : 프로세스의 스레드가 가용 CPU들중 일부 CPU에서만 수행되도록 할 수 있다.

프로세스의 에러 모드
 : 프로세스들은 심각한 에러를 어떻게 처리할지를 시스템에게 알려주기 위한 일련의 플래그 값을 가지고 있다
SetErrorMode()

프로세스의 현재 디렉토리와 드라이브
GetCurrentDirectory() : API
SetCurrentDirectory() : API
_chdir() : C RTL
GetFullPathName()

시스템 버전
GetVersion()
GetVersionEx()

그림1, 버전 자료형의 구조


프로세스의 생성
CreateProcess()
새로 생성된 프로세스가 완전히 초기화되기 전에 반환

그림2 프로세스의 생성

그림2는 CreateProcess()의 호출에서 반환까지의 과정이다. CreateProcess()는 새로 생성된 프로세스가 완전히 초기화되기 전에 반환한다.

ProcessID, ThreadID
 : 시스템 전체에 걸쳐 고유한 ID. 단순히 시스템 내에서 프로세스들과 스레드들을 쉽게 구분하기 위해 사용.
GetCurrentProcessId()
GetCurrentThreadId()
GetProcessId()
GetThreadId()

프로세스의 종료
방법.1 주 스레드의 진입점 함수 반환(추천)

그림3 진입점 함수 반환에 의한 프로세스 종료

방법.2 프로세스 내의 어떤 스레드가 ExitProcess() 함수를 호출
 - 사용자가 ExitProcess() 호출시 C 런타임 리소스 해제가 적절하게 이루어지지 않는다. 따라서 메모리나 다른 리소스의 누수가 발생할 수 있다.
 - ExitProcess()의 매개변수로 종료 코드를 설정한다.
방법.3 다른 프로세스의 스레드가 TerminateProcess() 함수를 호출
 - 자신의 프로세스 뿐만 아니라 다른 프로세스까지도 종료시킬 수 있다.
 - 비동기 함수이므로 프로세스의 정확한 종료 시점을 알기 위해서는 추가적인 작업이 필요하다.
 - 프로세스가 사용하던 리소스는 완벽하게 정리된다.
방법.4 프로세스 내의 모든 스레드가 각각 종료

프로세스의 종료시
1) 프로세스 내에 남아 있는 스레드 종료
2) 프로세스에 할당되었던 모든 사용자 오브젝트와 GDI 오브젝트 삭제 및 모든 커널 오브젝트 파괴 (커널 오브젝트의 usage count가 0이 되는 경우에만)
3) 프로세스의 종료 코드는 STILL_ACTIVE에서 ExitProcess나 TerminateProcess 호출 시 설정한 종료 코드로 변경
4) 프로세스 커널 오브젝트의 상태가 시그널 상태로 변경
5) 프로세스 커널 오브젝트의 usage count 1 감소

프로세스 간의 자료 전송 기법
 : DDE(Dynamic Data Exchange), OLE, 파이프(PIPE), 메일슬롯(mailslot), 메모리 맵 파일(MMF) 등

Child process의 독립적인 수행
Child process 생성 후 CloseHandle()을 이용하여 child process의 핸들 및 child process의 주 스레드 핸들을 해제한다.
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);

상승된 권한으로 프로세스를 수행시
CreateProcess() 대신 ShellExecuteEx를 사용

프로세스를 나열할 수 있는 프로세스 상태 관련 함수
EnumProcess()

동기화 기법

쓰레드 동기화 기법

 

 같은시간, 오직 하나의 쓰레드 또는 제한된 쓰레드만이 공유영역(Data 영역, 힙 영역) 에 접근하기 위한 방법

 

Critical Section 는 단일 프로세스의 스레드에 대해서만 동작합니다.반면에, 뮤텍스는 여러 프로세스의 스레드에 대해서도 동작합니다.세마포어는 CS, 뮤텍스가 가지는 특징에 하나를 더 가집니다. 세마포어는 특정 영역의 코드를 실행하는 스레드의 최대 개수를 설정할 수 있습니다.

 

  • 커널 오브젝트의 두가지 상태

프로세스 생성시 : Non-Signaled 상태로 생성

프로세스 종료시 : Signaled 상태로 변경됨

 

  •  커널 오브젝트의 상태를 확인하는 용도의 함수

DWORD  WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds)

hHandle : 상태 확인을 원하는 커널 오브젝트의 핸들

dwMilliseconds: 커널 오브젝트가 Signaled 상태가 될때까지 기다릴 수 있는 최대 시간, INFINITE 로 설정시 프로세스 종료시까지 무한정 기다림

 

 

메모리 접근 동기화#

 

유저모드 동기화#

 

크리티컬 섹션(Critical Section) 기반의 동기화#

 

  1. // 크리티컬 섹션 오브젝트 선언
  2. CRITICAL_SECTION   hCriticalSection;
  3. // 초기화
  4. InitializeCriticalSection(&hCriticalSection);
  5. EnterCriticalSection (&hCriticalSection); // 임계영역 진입을 위해 크리티컬 섹션 오브젝트 획득
  6. // Code..
    LeaveCriticalSection (&hCriticalSection); // 크리티컬 섹션 오브젝트 반환
  7. // 리소스 반환
  8. DeleteCriticalSection(&hCriticalSection);

 

예제)

  1. #include <stdio.h>
    #include <windows.h>
    #include <process.h>
    #include <tchar.h>
  2. #define NUM_OF_GATE  6
  3. LONG gTotalCount = 0;
  4. CRITICAL_SECTION   hCriticalSection;

  5. void IncreaseCount()
    {
     EnterCriticalSection (&hCriticalSection);
     gTotalCount++;
     LeaveCriticalSection (&hCriticalSection);
    }

  6. unsigned int WINAPI ThreadProc( LPVOID lpParam )
    {
     for(DWORD i=0; i<1000; i++)
     {
      IncreaseCount();
     }
  7.  return 0;
    }

  8. int _tmain(int argc, TCHAR* argv[])
    {
     DWORD dwThreadId[NUM_OF_GATE];
     HANDLE hThread[NUM_OF_GATE];
  9.  InitializeCriticalSection(&hCriticalSection);
  10.  for(DWORD i=0; i<NUM_OF_GATE; i++)
     {
      hThread[i] = (HANDLE)
       _beginthreadex (
       NULL,
       0,          
       ThreadProc,    
       NULL,                  
       CREATE_SUSPENDED,    
       (unsigned *)&dwThreadId[i]  
       );
  11.    if(hThread[i] == NULL)
       {
        _tprintf(_T("Thread creation fault! \n"));
        return -1;
       }
     }
  12.  for(DWORD i=0; i<NUM_OF_GATE; i++)
     {
      ResumeThread(hThread[i]);
     }

  13.  WaitForMultipleObjects(NUM_OF_GATE, hThread, TRUE, INFINITE);
  14.  _tprintf(_T("total count: %d \n"), gTotalCount);
  15.  for(DWORD i=0; i<NUM_OF_GATE; i++)
     {
      CloseHandle(hThread[i]);
     }
  16.  DeleteCriticalSection(&hCriticalSection);
  17.  return 0;
    }

 

인터락 함수(Interlocked Family Of Function) 기반의 동기화#
  1. // 전역으로 선언된 하나의 변수를 증가 또는 감소 시키기위해 사용되는 특화된 함수
  2. LONG  InterlockedIncrement(LONG volatile* Addend);
  3. LONG  InterlockedDecrement(LONG volatile* Addend);

 

 

 

커널모드 동기화#

 

뮤텍스(Mutex) 기반의 동기화#

 

  1. HANDLE hMutex;
  2. // Mutex 생성
  3.  hMutex = CreateMutex( NULL, FALSE, _T("NamedMutex"));
  4. // Mutex 획득
  5. WaitForSingleObject(hMutex, INFINITE);
  6. //  Mutex 반환
  7. ReleaseMutex(hMutex);

 

 

  1. #include <stdio.h>
    #include <windows.h>
    #include <process.h>
    #include <tchar.h>
  2. #define NUM_OF_GATE  6
  3. LONG gTotalCount = 0;
    HANDLE hMutex;
  4. void IncreaseCount()
    {
     AcquireMutex(hMutex);
  5.  gTotalCount++;
  6.  ReleaseMutex(hMutex);
    }

  7. unsigned int WINAPI ThreadProc( LPVOID lpParam )
    {
     for(DWORD i=0; i<1000; i++)
     {
      IncreaseCount();
     }
  8.  return 0;
    }
  9. DWORD AcquireMutex(HANDLE mutex)
  10. {
  11. return WaitForSingleObject(mutex, INFINITE);
  12. }
    int _tmain(int argc, TCHAR* argv[])
    {
        DWORD dwThreadIDs[NUM_OF_GATE];
        HANDLE hThreads[NUM_OF_GATE];

  13.     hMutex = CreateMutex (
                 NULL,     // 디폴트 보안관리자.
                       FALSE,    // 누구나 소유 할 수 있는 상태로 생성.
                       NULL      // numaned mutex
           );
  14.     if (hMutex == NULL)
        {
            _tprintf(_T("CreateMutex error: %d\n"), GetLastError());
        }
  15.  for(DWORD i=0; i<NUM_OF_GATE; i++)
     {
           hThreads[i] = (HANDLE)
          _beginthreadex (
           NULL,
           0,          
           ThreadProc,    
           NULL,                  
           CREATE_SUSPENDED,    
           (unsigned *)&dwThreadIDs[i]  
             );
  16.      if(hThreads[i] == NULL)
         {
             _tprintf(_T("Thread creation fault! \n"));
             return -1;
         }
     }
  17.  for(DWORD i=0; i<NUM_OF_GATE; i++)
     {
      ResumeThread(hThreads[i]);
     }
     WaitForMultipleObjects(NUM_OF_GATE, hThreads, TRUE, INFINITE);
  18.  _tprintf(_T("total count: %d \n"), gTotalCount);
  19.  for(DWORD i=0; i<NUM_OF_GATE; i++)
     {
      CloseHandle(hThreads[i]);
     }

     CloseHandle(hMutex);
  20.  return 0;
    }

 

세마포어(Semaphore) 기반의 동기화#

뮤텍스와 비슷하나 세미포어는 카운트 기능을 가지고 있음

임계영역에 접근 가능한 쓰레드의 개수를 조절하는 기능 내포

- 임계 영역의 접근 허용 쓰레드 개수를 하나로 제한하기 위해 사용되는 세마포어를 바이너리 세마포어라 하고, 이는 즉 뮤텍스와 동일한 기능

 

  1. // 세마포어 변수 설정
  2. HANDLE hSemaphore;
  3. // 세마포어 생성
  4.     hSemaphore = CreateSemaphore (
                       NULL,    // 디폴트 보안관리자.
                       TABLE_CNT,      // 세마포어 초기 값.
                       TABLE_CNT,      // 세마포어 최대 값.
                       NULL     // unnamed 세마포어 구성.
                        );
  5. // WaitForSingleObject(hSemaphore, INFINITE); // 세마포어 획득
  6. // code...
  7. // ReleaseSemaphore(hSemaphore,1,NULL); // 세마포어 반환

 

  1.  /*
     MyongDongKyoJa.cpp
     프로그램 설명: 카운트 세마포어에 대한 이해
     시뮬레이션 제한 요소:
      1. 테이블이 총 10개이고, 동시에 총 10분의 손님만 받을 수 있다고 가정한다.
      2. 오늘 점심시간에 식사하러 오실 예상되는 손님의 수는 총 50분이다.
      3. 각 손님들께서 식사 하시는 시간은 대략 10분에서 30분 사이이다.
    */

  2. #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <windows.h>
    #include <process.h>
    #include <tchar.h>
  3. #define NUM_OF_CUSTOMER 50
    #define RANGE_MIN 10
    #define RANGE_MAX (30 - RANGE_MIN)
    #define TABLE_CNT 10

  4. HANDLE hSemaphore;
    DWORD randTimeArr[50];
  5. void TakeMeal(DWORD time)
    {
     WaitForSingleObject(hSemaphore, INFINITE);
     _tprintf( _T("Enter Customer %d~ \n"), GetCurrentThreadId());
  6.  _tprintf(_T("Customer %d having launch~ \n"), GetCurrentThreadId());
     Sleep(1000 * time); // 식사중인 상태를 시뮬레이션 하는 함수.
  7.  ReleaseSemaphore(hSemaphore, 1, NULL);
     _tprintf( _T("Out Customer %d~ \n\n"), GetCurrentThreadId());
    }

  8. unsigned int WINAPI ThreadProc( LPVOID lpParam )
    {
     TakeMeal((DWORD)lpParam);
     return 0;
    }

  9. int _tmain(int argc, TCHAR* argv[])
    {
        DWORD dwThreadIDs[NUM_OF_CUSTOMER];
        HANDLE hThreads[NUM_OF_CUSTOMER];
     
     srand( (unsigned)time( NULL ) );   // random function seed 설정

  10.  // 쓰레드에게 전달할 random 값 총 50개 생성.
     for(int i=0; i<NUM_OF_CUSTOMER ;i++)
     {
            randTimeArr[i] = (DWORD) (
        ((double)rand() / (double)RAND_MAX) * RANGE_MAX + RANGE_MIN
       );
       }
  11.  // 세마포어 생성.
        hSemaphore = CreateSemaphore (
                 NULL,    // 디폴트 보안관리자.
                       TABLE_CNT,      // 세마포어 초기 값.
                       TABLE_CNT,      // 세마포어 최대 값.
           NULL     // unnamed 세마포어 구성.
               );
        if (hSemaphore == NULL)
        {
            _tprintf(_T("CreateSemaphore error: %d\n"), GetLastError());
        }

  12.  // Customer를 의미하는 쓰레드 생성.
     for(int i=0; i<NUM_OF_CUSTOMER; i++)
     {
            hThreads[i] = (HANDLE)
          _beginthreadex (
           NULL,
           0,          
           ThreadProc,    
           (void*)randTimeArr[i],                  
           CREATE_SUSPENDED,    
           (unsigned *)&dwThreadIDs[i]  
             );
  13.      if(hThreads[i] == NULL)
         {
             _tprintf(_T("Thread creation fault! \n"));
             return -1;
         }
     }
  14.  for(int i=0; i<NUM_OF_CUSTOMER; i++)
     {
      ResumeThread(hThreads[i]);
     }
  15.  WaitForMultipleObjects(NUM_OF_CUSTOMER, hThreads, TRUE, INFINITE);
  16.     _tprintf(_T("----END-----------\n"));
  17.  for(int i=0; i<NUM_OF_CUSTOMER; i++)
     {
      CloseHandle(hThreads[i]);
     }
     
     CloseHandle(hSemaphore);
  18.  return 0;
    }

 

 

이름있는 뮤텍스(Named Mutex) 기반의 프로세스 동기화#

뮤텍스는 커널 오브젝트이므로 프로세스에 소속되는것이 아니라 운영체제가 관리한다. 따라서 뮤텍스에 유일한 이름을 지어주고 이것을 다른 프로세스에서 획득하여 사용하는것이 가능하다. 아래는 서로다른 프로세스에 속해있는 두개의 쓰레드를 동기화 하는 예제 코드이다.

 

  1. HANDLE OopenMutex(
  2. DWORD dwDesiredAccess, // 접근권한
  3. BOOL bInheritHandle, // 핸들 상속여부
  4. LPCSTR lpName // 뮤텍스 오브젝트 이름
  5. );

 

 

  1. #include <stdio.h>
    #include <windows.h>
    #include <process.h>
    #include <tchar.h>

  2. HANDLE hMutex;
    DWORD dwWaitResult;
  3. void ProcessBaseCriticalSection()
    {
     dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
  4.  switch (dwWaitResult)
     {
      // 쓰레드가 뮤텍스를 소유하였다.
     case WAIT_OBJECT_0:
      _tprintf(_T ("thread got mutex ! \n") );
      break;
  5.   // time-out 발생하였다.
     case WAIT_TIMEOUT:
      _tprintf(_T ("timer expired ! \n") );
      return;
  6.   // 뮤텍스 반환이 적절이 이뤄지지 않았다.
     case WAIT_ABANDONED:
      return;
     }
  7.  for(DWORD i=0; i<5; i++)
     {
      _tprintf( _T("Thread Running ! \n") );
      Sleep(2000);
     }
  8.  ReleaseMutex(hMutex);
    }

  9. int _tmain(int argc, TCHAR* argv[])
    {
  10. #if 0
     hMutex = CreateMutex(
      NULL,                      
      FALSE,                    
      _T("NamedMutex")  
      );        
    #else
  11.  hMutex = OpenMutex(
      MUTEX_ALL_ACCESS,    
      FALSE,                
      _T("NamedMutex")  
      );
  12. #endif
  13.  if (hMutex == NULL)
     {
      _tprintf(_T("CreateMutex error: %d\n"), GetLastError());
      return -1;
     }
  14.  ProcessBaseCriticalSection();
  15.  CloseHandle(hMutex);
  16.  return 0;
    }

 

 

 

실행순서 동기화#

 

이벤트(Event) 기반의 동기화#

쓰레드나 커널 오브젝트의 경우 초기에는 Non-Signaled 상태로 생성되고, 종료시 Signaled 상태로 자동변경 된다. 그러나 이벤트 오브젝트는 자동으로 Signaled 상태로 변경되는것이 아니라 함수호출을 통해서 Signaled 상태로 변경을 해야한다. 따라서 프로그래머는 이벤트 커널 오브젝트의 상태를 직접 조작함으로써 실행 순서를 동기화 할 수 있다. 실행순서 동기화를 위한 내용을 정리하자면 아래와 같다.

 

  • A 쓰레드의 특정 시점까지 완료후 B 쓰레드가 시작되도록 하는 프로그램을 작성 하고자 한다.
  • A, B 쓰레드를 차례대로 생성하고, A 쓰레드는 Non-Signaled 상태로 이벤트 커널 오브젝트를 생성한다.
  • B 쓰레드 쓰레드 시작 부분에 WaitForSingleObject(hEvent,INFINITE) 함수를 호출하여 event 가 Signaled 상태가 되기를 기다린다.
  • 이벤트 오브젝트는 A 쓰레드에의해 Non-Signaled 상태이므로 B 쓰레드가 블로킹된다.
  • A 쓰레드는 SetEvent() 함수를 통해 이벤트 오브젝트의 상태를 Signaled 상태로 바꾸면 이때 블로킹되어있던 B 쓰레드가 블로킹 상태를 빠져나와 쓰레드가 실행된다.

 

  1.  // 이벤트 오브젝트 생성
  2. HANDLE CreateEvent(
  3. LPSECURITY_ATTRIBUTES lpEnventAttrivutes, // 보안속성 지정

  4. BOOL bManualReset, // 리셋모드 결정

    BOOL bInitialState, // 이벤트 오브젝트의 초기 상태결정 TRUE:Signaled, FALSE:Non-Signaled)

  5. LPCTSTR lpName // 오브젝트 이름

  6. );

  7. // Non-Signaled 상태로 변경
  8. BOOL ResetEvent(HANDLE hEvent);
  9. // Signaled 상태로 변경
  10. BOOL SetEvent(HANDLE hEvent);

 

  • 참고 : BOOL bManualReset

TRUE:수동리셋모드 - 블로킹된 쓰레드가 WiatForSingleObject 함수를 빠져나온후에도 이벤트의 상태가 변하지 않고 Signaled 상태로 남음

FALSE:자동리셋모드 - 블로킹된 쓰레드가 WiatForSingleObject 함수를 빠져나옴과 동시에 이벤트의 상태가 Non-Signaled 상태로 변함

 

 

예제)

  1. /*
    StringEvent.cpp
    프로그램 설명: 1. 생산자/소비자 모델의 이해
    2. 동기화 event에 대한 이해.
    */
  2. #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <process.h>    /* _beginthreadex, _endthreadex */

  3. unsigned int WINAPI OutputThreadFunction(LPVOID lpParam);
  4. TCHAR string[100];
    HANDLE hEvent;
  5. int _tmain(int argc, TCHAR* argv[])
    {
     HANDLE  hThread;
     DWORD dwThreadID;
  6.  hEvent = CreateEvent( // event object 생성.
      NULL,  // 상속 불가.
      TRUE,  // manual-reset mode로 생성.
      FALSE,  // non-signaled 상태로 생성.
      NULL  // 이름 없는 event.
      );
     if(hEvent==NULL){
      _fputts(_T("Event object creation error \n"), stdout);
      return -1;
     }
  7.  hThread = (HANDLE)_beginthreadex (
      NULL, 0,
      OutputThreadFunction,
      NULL, 0,
      (unsigned *)&dwThreadID
      );
  8.  if(hThread==0) {
      _fputts(_T("Thread creation error \n"), stdout);
      return -1;
     }
  9.  _fputts(_T("Insert string: "), stdout);
     _fgetts(string, 30, stdin);
  10.  SetEvent(hEvent); // event의 state를 signaled 상태로 변경.
  11.  WaitForSingleObject(hThread, INFINITE);
  12.  CloseHandle(hEvent); // event 오브젝트 소멸
     CloseHandle(hThread);
  13.  return 0;
    }
  14. unsigned int WINAPI OutputThreadFunction(LPVOID lpParam)
    {
  15.  WaitForSingleObject(hEvent, INFINITE); // event가 signaled 상태가 되기를 기다린다.
  16.  _fputts(_T("output string: "), stdout);
     _fputts(string, stdout);
  17.  return 0;
  18. }

 

수동리셋(Muanual-Reset) 모드 이벤트 활용 예#

문자열입력, 문자열 출력, 문자열 길이를 출력하는 3개의 쓰레드가 있다.

  문자열 출력과 문자열 길이를 출력하는 쓰레드는 문자열이 입력되기를 기다리고 있다가 문자열의 입력이 완료되면  동시에 블로킹을 풀고 쓰레드가 실행되도록한다.

블로킹된 두개의 쓰레드를 동시에 풀기위해 Event 가 사용되고, 쓰레드가 동시에 실행되더라도 문자열 출력이 섞이지 않도록 하기위해 Mutex 가 사용된다.

 

  1.  /*
     StringEvent2.cpp
     프로그램 설명: manual-reset mode 동기화 적용 사례.
    */
  2. #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <process.h>    /* _beginthreadex, _endthreadex */

  3. unsigned int WINAPI OutputThreadFunction(LPVOID lpParam);
    unsigned int WINAPI CountThreadFunction(LPVOID lpParam);
  4. TCHAR string[100];
    HANDLE hEvent;
  5. int _tmain(int argc, TCHAR* argv[])
    {
     HANDLE  hThread[2];
     DWORD dwThreadID[2];
  6.  hEvent = CreateEvent( // event object 생성.
        NULL,  // 상속 불가.
        TRUE,  // manual-reset mode로 생성.
        FALSE,  // non-signaled 상태로 생성.
        NULL  // 이름 없는 event.
        );
     if(hEvent==NULL){
      _fputts(_T("Event object creation error \n"), stdout);
      return -1;
     }
     
     hThread[0] = (HANDLE)_beginthreadex (
          NULL, 0,
          OutputThreadFunction,
          NULL, 0,
          (unsigned *)&dwThreadID[0]
         );
  7.  hThread[1] = (HANDLE)_beginthreadex (
          NULL, 0,
          CountThreadFunction,
          NULL, 0,
          (unsigned *)&dwThreadID[1]
         );

  8.  if(hThread[0]==0 ||hThread[1]==0)
     {
      _fputts(_T("Thread creation error \n"), stdout);
      return -1;
     }
  9.  _fputts(_T("Insert string: "), stdout);
     _fgetts(string, 30, stdin);
  10.  SetEvent(hEvent); // event의 state를 signaled 상태로 변경.
  11.  WaitForMultipleObjects (
        2,           // 배열의 길이.
        hThread,     // 핸들의 배열.
        TRUE,        // 모든 핸들이 신호받은 상태로 될 때 리턴.
        INFINITE  // 무한 대기.
     );
     
     CloseHandle(hEvent); // event 오브젝트 소멸
     CloseHandle(hThread[0]);
     CloseHandle(hThread[1]);
  12.     return 0;
    }
  13. unsigned int WINAPI OutputThreadFunction(LPVOID lpParam)
    {
  14.   WaitForSingleObject(hEvent, INFINITE); // event가 signaled 상태가 되기를 기다린다.
  15.   _fputts(_T("Output string: "), stdout);
      _fputts(string, stdout);
  16.   return 0;
    }
  17. unsigned int WINAPI CountThreadFunction(LPVOID lpParam)
    {
  18.   WaitForSingleObject(hEvent, INFINITE); // event가 signaled 상태가 되기를 기다린다.
  19.   _tprintf(_T("Output string length: %d \n"), _tcslen(string)-1);
  20.   return 0;
    }

 

위 코드의 문제점 : WaitForMultipleObjects() 함수를 통해 블로킹된 두개의 쓰레드가 동시에 풀리면서 출력순서를 보장하지 못한다.

따라서 위 코드를  Mutex 를 사용한 코드로 수정해야 한다.

 


  1. #include "stdafx.h"
  2. #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <process.h>    /* _beginthreadex, _endthreadex */

  3. unsigned int WINAPI OutputThreadFunction(LPVOID lpParam);
    unsigned int WINAPI CountThreadFunction(LPVOID lpParam);
    DWORD AcquireMutex(HANDLE mutex);

  4. TCHAR string[100];
    HANDLE hEvent;
    HANDLE hMutex;

  5. int _tmain(int argc, TCHAR* argv[])
    {
     HANDLE  hThread[2];
     DWORD dwThreadID[2];
  6.  hMutex = CreateMutex( NULL, FALSE, _T("NamedMutex"));
     if(hMutex==NULL)
     {
      _fputts(_T("Mutex object creation error \n"), stdout);
      return -1;
     }
  7.  hEvent = CreateEvent( // event object 생성.
      NULL,  // 상속 불가.
      TRUE,  // manual-reset mode로 생성.
      FALSE,  // non-signaled 상태로 생성.
      NULL  // 이름 없는 event.
      );
  8.  if(hEvent==NULL)
     {
      _fputts(_T("Event object creation error \n"), stdout);
      return -1;
     }
  9.  hThread[0] = (HANDLE)_beginthreadex (
      NULL, 0,
      OutputThreadFunction,
      NULL, 0,
      (unsigned *)&dwThreadID[0]
      );
  10.  hThread[1] = (HANDLE)_beginthreadex (
      NULL, 0,
      CountThreadFunction,
      NULL, 0,
      (unsigned *)&dwThreadID[1]
      );
  11.  if(hThread[0]==0 ||hThread[1]==0)
     {
      _fputts(_T("Thread creation error \n"), stdout);
      return -1;
     }
  12.  _fputts(_T("Insert string: "), stdout);
     _fgetts(string, 30, stdin);
  13.  SetEvent(hEvent); // event의 state를 signaled 상태로 변경.
  14.  WaitForMultipleObjects (
      2,           // 배열의 길이.
      hThread,     // 핸들의 배열.
      TRUE,        // 모든 핸들이 신호받은 상태로 될 때 리턴.
      INFINITE  // 무한 대기.
      );
  15.  CloseHandle(hEvent); // event 오브젝트 소멸
     CloseHandle(hThread[0]);
     CloseHandle(hThread[1]);
  16.  return 0;
    }
  17. unsigned int WINAPI OutputThreadFunction(LPVOID lpParam)
    {
  18.  WaitForSingleObject(hEvent, INFINITE); // event가 signaled 상태가 되기를 기다린다.
  19.  AcquireMutex(hMutex);
  20.  _fputts(_T("Output string: "), stdout);
     _fputts(string, stdout);
  21.  ReleaseMutex(hMutex);
  22.  return 0;
    }
  23. unsigned int WINAPI CountThreadFunction(LPVOID lpParam)
    {
  24.  WaitForSingleObject(hEvent, INFINITE); // event가 signaled 상태가 되기를 기다린다.
  25.  AcquireMutex(hMutex);
  26.  _tprintf(_T("Output string length: %d \n"), _tcslen(string)-1);
  27.  ReleaseMutex(hMutex);
  28.  return 0;
    }
  29. DWORD AcquireMutex(HANDLE mutex)
    {
     return WaitForSingleObject(mutex, INFINITE);
    }

 

 

타이머 기반 동기화#

Windows 에서는 Signaled/Non-Signaled 상태 개념이 중요하다. 어떤 커널 오브젝트는 특정 상황이 도래하면 Signaled 상태가 되고, 또 어떤 커널 오브젝트는 명시적인 함수 호출을 통해서 Signaled 상태가 되기도 한다.

타이머는 생성시 Non-Signaled 상태로 생성되고 정해진 시간이 지나면 자동으로 Signaled 상태가되는 특성이 있다.

 

  • 타이머 오브젝트 생성

HANDLE CreateWaitableTimer(

LPSECURITY_ATTRIBUTES lpTimerAttributes, //  보안속성 지정

BOOL bManualReset, // 수동리셋/자동리셋 모드 설정

LPCTSTR lpTimerName // 타이머 오브텍트 이름 설정

);

 

  •  알람 시간 설정

BOOL SetWaitableTimer(

HANDLE hTimer, // 알람을 설정할 타이머 오브젝트 핸들

const LARGE_INTEGER* pDueTime, // 알람이 울리는 시간 지정, 단위는 NanoSeconds (+값일경우 절대시간, -값일경우 상대시간을 의미)

LONG lPeriod, // 타이머의 주기, 단위는 Milliseconds

PTIMERAPCROUTINE pfnCompletetionRoutine, // 완료루틴 타이머 생성 용도로 사용

LPVOID lpArgToCompletionRoutine, // 완료루틴 타이머 생성 용도로 사용

BOOL fResume // 전원관리와 관련된 매개변수, 기본적으로 FALSE 로 세팅함

);

 

  •  타이머 해제

BOOL CancelWaitableTimer(

HANDLE hTimer // 알람을 해제할 타이머 오브젝트의 핸들

);

 

수동리셋 타이머(Manual-Reset Timer)#

 

예제)

  1.  /*
     ManualResetTimer.cpp
     프로그램 설명: 수동 리셋 타이머 오브젝트에 대한 이해.
    */
  2. #define _WIN32_WINNT 0x0400
  3. #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>

  4. int _tmain(int argc, TCHAR* argv[])
    {
        HANDLE hTimer = NULL;
        LARGE_INTEGER liDueTime;
  5.     liDueTime.QuadPart=-100000000;
  6.     hTimer = CreateWaitableTimer(NULL, TRUE, _T("WaitableTimer")); // 수동리셋 타이머 생성
        if (!hTimer)
        {
            _tprintf( _T("CreateWaitableTimer failed (%d)\n"), GetLastError());
            return 1;
        }
  7.     _tprintf( _T("Waiting for 10 seconds...\n"));
  8.     SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE); // 타이머 시간 설정
  9.     WaitForSingleObject(hTimer, INFINITE); // 수동리셋 타이머 이므로 타이머가 특정시간이 지난후 Signaled 상태로 변경되면 쓰레드가 블로킹에서 풀려나지만 타이머의 상태는 계속 Signaled 상태로 유지된다.

  10.     _tprintf( _T("Timer was signaled.\n") );
        MessageBeep(MB_ICONEXCLAMATION);
  11.     return 0;
    }

 

#define _WIN32_WINNT   0x0400

CreateWaitableTimer, SetWaitableTimer 은 Windows NT 4.0 이후부터 제공되기 시작한 함수이기때문에 매크로 선언을 미리 해 줘야 사용 가능함.

만약 Widows XP 이후 버전부터 제공하기 시작한 함수가 있다면 _WINNT_WIN32 를 0x0501 로 정의해야한다.

 

 

 

주기적 타이머(Periodic-Timer)#

일정 시간 간격으로 알람이 울리는 타이머.

 

  1.  /*
     PeriodicTimer.cpp
     프로그램 설명: 주기적 타이머에 대한 이해.
    */
  2. #define _WIN32_WINNT 0x0400
  3. #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>

  4. int _tmain(int argc, TCHAR* argv[])
    {
        HANDLE hTimer = NULL;
        LARGE_INTEGER liDueTime;
  5.     liDueTime.QuadPart=-100000000;
  6.     hTimer = CreateWaitableTimer(NULL, FALSE, _T("WaitableTimer")); // 자동리셋 타이머 생성
        if (!hTimer)
        {
            _tprintf( _T("CreateWaitableTimer failed (%d)\n"), GetLastError());
            return 1;
        }
  7.     _tprintf( _T("Waiting for 10 seconds...\n"));
  8.     SetWaitableTimer(hTimer, &liDueTime, 5000, NULL, NULL, FALSE); // 타이머 주기 설정
  9.     while(1)
       {
          WaitForSingleObject(hTimer, INFINITE); // 자동리셋 타이머 이므로 타이머가 Signaled 상태로 변경됨과 동시에 쓰레드가 블로킹 상태에서 빠져나오고 타이머의 상태는 Non-Signaled 상태로 바뀐다.
          _tprintf( _T("Timer was signaled.\n") );
          MessageBeep(MB_ICONEXCLAMATION);
       }
        return 0;
    }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2010년 6월 9일 수요일

apache 설치하기 (CentOS)

운영체제를 깔때 서버 버전으로 깔아서 기본적으로 Httpd 가 설치되어 있었다.

하지만 내가 복사해야될 폴더며 내가 필요한 것들은 당췌 어디 있는지... 알 수가 없었다 ;;;

그래서 과감히 소프트웨어 추가 삭제에서 삭제를 하고, 다운 받아서 다시 깔았다.

http://www.apache.org  에서 Linux 용 최신 버전 다운


1. tar 파일의 압축을 푼다.

# tar xvf httpd-2.2.13.tar


2. 컴파일 스크립트 수행

# ./configure --with-layout=apache --prefix-/usr/local/web/apache --enable-module=so --enable-mods-shared=all --enable-so -enable-rewrite

prefix = 설치 경로
--enable-module=so 는 tomcat 연동이나 다른 연동시 필요하므로 꼭 추가.
여기서
configure: error: no acceptable C compiler found in $PATH
이런 에러가 뜬다면 gcc 가 깔려 있는지 확인하자.
# rpm -qa | grep gcc

없다면.
# yum install gcc

mod_deflate has been requested but can not be built due to prerequisite failures
에러가 난다면.

# yum -y install zlib-devel

뭐 대략적으로 설치가 안되서 나는 에러다.

3. 컴파일

# make


4. install

# make install


에러 없이 설치가 되었다면 성공.


부팅시 자동으로 띄우고 싶다면.


#cp /usr/local/web/apachectl /etc/init.d/httpd

#vi /etc/init.d/httpd


#!bin/sh 밑에 아래 내용을 넣는다.
#chkconfig: 2345 90 90
#processname: /usr/local/web/apache/bin/apachectl
#config: /usr/local/web/apache/conf/httpd.conf
#pidfile: /usr/local/web/apache/logs/httpd.conf


저장.

#chkconfig --add httpd
#chkconfig --list httpd


하면 httpd 가 있는지 확인.

# ntsysv

하면 파란 화면이 뜬다.
여기서 httpd 에 * 가 쳐져 있다면 자동 실행된다.

#service httpd start


하고

http://localhost

들어가면

It works!

라고 뜬다.

2010년 5월 15일 토요일

iphone sdk 언인스톨

sudo /Developer/Library/uninstall-devtools --mode=all

2010년 5월 14일 금요일

디스크 초기화

clearhdd 1 타이핑후 y를 선택한다음 재부팅 하면 된다.

 

mbr(master boot record) 을삭제해야한다.

MBR은 파티션 위치정보를 가지고 있다.그리고 운영체제가 저장되어있는 파티션의 부트섹터를

읽어올수있는 프로그램을 포함하고 있다.

부트섹터에는 OS를 메모리에 올릴수있는 프로그램이 내장되어 있다

 

FDISK 는 파티션을 나누는 즉 디스크영역을 만드는 것이고

FDISK /mbr 은 mbr영역까지 삭제하는 명령이다.

 

실제로 Fdisk/mbr은 mbr영역중 파티션테이블 64byte를 제외한 나머지 mbr영역을 fdisk가 다시

기록해주는 것이다.

파티션테이블을 제외한 mbr영역이 손상되었을때 복구하는 도구로 사용된다.

파티션테이블 손상시에는 다른 복구유틸이나 백업본을 이용해야한다.

 

 

2010년 5월 13일 목요일

해킨토시 설치하기

The first time I installed OSX on my P1610 I used Kalyway 10.5.2, it was pretty successful,
but there were a few remaining issues and it was a lot of hard work.
Quite a few months down the line and much has improved in the world of hackintosh,
My latest install is with iAtkos v7, which can be found at any good torrent search.

I do suggest burning the disc at the slowest speed possible to minimise errors on the DVDR.
Here is how I installed iAtkos v7 OS X 10.5.7 on my Fujitsu P1610.
I'm not guaranteeing it will work for you, it's just how I did it.

MANY MANY THANKS to all that put the work in to make this possible.


<Preparation>
-------------
The very first thing I did was replace the standard Atheros WiFi card in my P1610,
with a Airport compatible 802.11N Broadcom based WiFi card, that I picked up off eBay.
No idea if iAtkos v7 supports the original Atheros card as I got rid of ages ago.

Downloaded and burned the iAtkos v7 disc image at x2 speed.

Plug in my external USB DVD rom and put the iAtkos v7 disc in.
Turn on your Fujitsu Lifebook P1610 and at the POST screen hit F2 to enter the BIOS.
In the BIOS go over to Boot and down to Boot Device Priority.
in the list of Boot priority order, I removed everything except CD/DVD drive,
hit x to remove or add a device to the list.
Hit F10 to save and exit, then enter to confirm.


<Installation>
--------------
Boot from CD/DVD drive and at the Darwin loader
press F8 for options and type -v to boot in verbose mode.
Once the installer loads up
click the button to continue

under utilities menu
click on Disk Utility

Select the drive in your P1610, then choose the Partition tab.
You could create just one partition if you want just Mac OS X, format it in Mac OS Extended (Journaled) format.

----
I have mine setup as a dualboot, Mac OS X and Windows XP Tablet.
So created two equal sized paritions the first being a Mac OS Extended (Journaled)
the second being (MS-DOS) FAT so I can install Windows XP Tablet to it.
Once the partitions are created,
I then install Windows XP Tablet as I normally would, during the XP installation I reformat the FAT partition to NTFS.
Since it doesn't see the Mac OS Extended (Journaled) partition there is no issues here.
After installing Windows XP, boot from the iAtkos disc again with F8 and typing -v.
----

Agree to the edited iAtkos license agreement,
Select a Destination - click on the Mac OS partiton, then continue
Install Summary - Customize
(the following are the options I used, they may not be the best, but they work for me.)

-iATKOS v7 Main System

-Bootloader
--Chameleon v2

-X86 Patches
--/Extra directory
--DSDT
--Decrypters
---AppleDecrypt
--SMBIOS drivers
---SMBIOS Enablers
----SMBIOS Resolver
---SMBIOS' for X86
----AppleSMBIOS-28
--Kernel
---9.7.0 Kernel voodoo
--Disabler

-Drivers
--VGA
---Intel
----GMA 950
-----GMA 950 Laptop
--System
---SATA/IDE
----Generic IDE
---CardBus Driver
---USB
---Sound
----Voodoo HDA driver
---PS/2 mouse/keyboard
----Apple PS/2 driver
---Laptop Battery
---NTFS-3G
---Network
----Wireless
-----Broadcom BCM43xx

-Post-Install Actions


Click Done, then Install


<Setup>
-------
Once the Install has succeeded, click restart,
and when you get the Fujitsu POST screen hit F2 to go into the BIOS
Unplug the USB DVD drive
Remove the CD/DVD drive from the Boot priority order,
and re-add the hard drive Drive0:
Press F10 to save and exit, then enter to confirm.
When you get the Chameleon boot screen, push down three times to select Boot Verbose and hit enter.

OSX will start up and you should hear some funky music playing out the speakers,

Select Country
Keyboard
Dou you already own a mac? - Continue
Select a wireless Service
Enter your Apple ID - you can leave it blank and hit Continue
Registration Information - Alt+Q to skip
Create Your Account Name and a password
Select Time Zone
Set the Date and Time
Don't Forget to Register - Done


<Display> 반드시 설정해야한다 .
---------
First things first, set the correct screen resolution.
Click on System preferences, the metallic looking Cogs icon at the bottom
then under the Hardware heading, Displays.
select 1280x768 to get the correct resolution.

/Library/Preferences/SystemConfiguration/com.apple.Boot.plist 에서

<key>Graphic Mode</key>

<string>1280*768*32</string>

를 입력후 저장 한다 맨 아래쪽에

만약 하지 않게 되면 재부팅 했을경우 gui를 볼수 없게 된다.



<Ethernet Networking>
---------------------
1. 터미널 실행
2. sudo -s 실행(관리자 권한 획득)
3. 관리자 암호 입력
4. vi /System/Library/Extensions/IONetworkingFamily.kext/Contents/Plugins/AppleYukon2.kext/Contents

/Info.plist

아래 색칠된 부분 수정

<key>Yukon-88E8055</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.iokit.AppleYukon2</string>
            <key>EnableLowPwr</key>
            <integer>1</integer>
            <key>IOClass</key>
            <string>yukon2osx</string>
            <key>IOPCIPrimaryMatch</key>
            <string>0x436311ab</string>
            <key>IOPCISecondaryMatch</key>
            <string>0x139a10cf</string>
            <key>IOProviderClass</key>
            <string>IOPCIDevice</string>
            <key>InitialWaitForLinkUp</key>
            <string></string>
            <key>MACNumber</key>
            <integer>1</integer>
            <key>Model</key>
            <string>Yukon Gigabit Adapter 88E8055 Singleport Copper SA</string>
            <key>NetworkNumber</key>
            <integer>6000</integer>
            <key>Vendor</key>
            <string>marvell</string>
        </dict>


5. rm /System/Library/Extensions.mkext
6. diskutil repairPermissions /
7. reboot


<Keyboard layout>
-----------------
http://www.insanelymac.com/forum/index.php...st&p=767201
download and install the Microsoft Keyboard layouts,
once that's done, restart the computer and go into System Preferences and select International.
Select Input Menu.
scroll through and check the box for the keyboard you have.
mine is British - Microsoft.
Then up in the top right you'll see a little Flag where you can click on to change the keyboard layout.


<Upgrade to 10.5.8>
-------------------
Click on the Apple icon, top right, and select Software update,
uncheck the 10.5.8 update for now, and update everything else.
once it's all updated and restarted, check for updates again,
hopefully there is now only the 10.5.8 update left.
Check that and apply that update, it takes a while,
but it should restart a couple of times and you'll now have 10.5.8 running on your P1610.


<Things that are not working>
-----------------------------
Touchscreen, Buttons on the screen bezel, SD card reader.
I don't think I'm going to be able to get the Touchscreen to work,
as the P1610 uses a serial touchscreen controller, which there doesn't seem to be any support for.
Again the same for the buttons on the screen bezel, no support.
But I reckon with a bit more hunting around I should be able to get the SD card reader working. Hopefully.

2010년 5월 7일 금요일

파일을 DB처럼 사용하는법

class CInfo
{
public:
char szName[40];
char szPhone[40];
char szMobile[40];
char szAddress[40];
char szEmail[40];
char szEtc[1024-40*5-7];
char szn[3];


CInfo(){
  memset(szName, 0 ,sizeof(char)*40);
  memset(szPhone, 0 ,sizeof(char)*40);
  memset(szMobile, 0 ,sizeof(char)*40);
  memset(szAddress, 0 ,sizeof(char)*40);
  memset(szEmail, 0 ,sizeof(char)*40);
  memset(szEtc, 0 ,sizeof(char)*1024-40*5-7);
  memset(szn,0,sizeof(szn));
  strncpy(szn,_T("\r\n"),sizeof("\r\n"));
}
};

1.데이터 삽입(Insert)



void CFileDB::InsertInFile(CInfo &Info)
{


m_hFile = CreateFile(_T("c:\\test001.dat"), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

DWORD nWrite = 0;

SetFilePointer(m_hFile,0,NULL,FILE_END);

//WriteFile(m_hFile,_T("\n"),sizeof("\n"),&nWrite,NULL);




if(m_hFile != INVALID_HANDLE_VALUE)
{
  WriteFile(m_hFile,&Info,sizeof(Info),&nWrite,NULL);
}

CloseHandle(m_hFile);


}



2.데이터 조회(Select)



void CFileDB::SelectInFile(void)
{

UpdateData(TRUE);


DWORD dwStartTime, dwFinishTime;
CInfo Info;
memset(&Info,0,sizeof(Info));



m_hFile = CreateFile(_T("c:\\test001.dat"), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

SetFilePointer(m_hFile,0,NULL,FILE_BEGIN);

int nNumOfData = GetFileSize(m_hFile,NULL)/sizeof(CInfo);

DWORD nRead = 0;

if(m_hFile != INVALID_HANDLE_VALUE)
{
  for(int i = 0 ; i< nNumOfData ; ++i)
  {
   SetFilePointer(m_hFile,sizeof(Info)*i,NULL,FILE_BEGIN);
   ReadFile(m_hFile,&Info,sizeof(Info),&nRead,NULL);

   if(m_strNameSearch.Compare(Info.szName) == 0 )
   {
    // 데이타를 표시한다.
    m_uIndex = i;
    m_strName = Info.szName;
    m_strPhone = Info.szPhone;
    m_strMobile = Info.szMobile;
    m_strAddress = Info.szAddress;
    m_strEmail = Info.szEmail;
    dwFinishTime = GetTickCount();
    m_uTime = 0;

   }
  }
 
}

CloseHandle(m_hFile);

UpdateData(FALSE);

}



3.데이터 수정(Update)



void CFileDB::UpdateInFile(void)
{

UpdateData(TRUE);


DWORD dwStartTime, dwFinishTime;
CInfo Info;
memset(&Info,0,sizeof(Info));

m_hFile = CreateFile(_T("c:\\test001.dat"), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

SetFilePointer(m_hFile,0,NULL,FILE_BEGIN);

int nNumOfData = GetFileSize(m_hFile,NULL)/sizeof(CInfo);

DWORD nRead = 0;
DWORD nWrite = 0;

if(m_hFile != INVALID_HANDLE_VALUE)
{
  for(int i = 0 ; i< nNumOfData ; ++i)
  {
   SetFilePointer(m_hFile,sizeof(Info)*i,NULL,FILE_BEGIN);
   ReadFile(m_hFile,&Info,sizeof(Info),&nRead,NULL);

   if(m_strNameSearch.Compare(Info.szName) == 0 )
   {
    // 데이타를 표시한다.
    m_uIndex = i;
    strncpy(Info.szName,m_strName,strlen(m_strName));
    strncpy(Info.szPhone, m_strPhone,strlen(m_strPhone));
    strncpy(Info.szMobile, m_strMobile,strlen(m_strMobile));
    strncpy(Info.szAddress, m_strAddress,strlen(m_strAddress));
    strncpy(Info.szEmail, m_strEmail,strlen(m_strEmail));
    dwFinishTime = GetTickCount();
    m_uTime = 0;

    SetFilePointer(m_hFile,sizeof(Info)*i,NULL,FILE_BEGIN);
    WriteFile(m_hFile,&Info,sizeof(Info),&nWrite,NULL);

    MessageBox(_T("수정이 완료되었습니다."));

   }
  }

}

CloseHandle(m_hFile);

UpdateData(FALSE);

}



4.데이터 삭제(Delete)

void CFileDB::DeleteInFile(void)
{
CInfo Info;
DWORD nRead = 0;
DWORD nWrite = 0;

BOOL bCompare = FALSE;


m_hFile = CreateFile(_T("c:\\test001.dat"), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
SetFilePointer(m_hFile,0,NULL,FILE_BEGIN);

int nNumOfData = GetFileSize(m_hFile,NULL)/sizeof(CInfo);

if(m_hFile != INVALID_HANDLE_VALUE)
{
  for(int i = 0 ; i< nNumOfData ; ++i)
  {
   SetFilePointer(m_hFile,sizeof(Info)*i,NULL,FILE_BEGIN);
   ReadFile(m_hFile,&Info,sizeof(Info),&nRead,NULL);

   if(m_strName.Compare(Info.szName) == 0 )
   {
    bCompare = TRUE;
   
   }

   if(bCompare)
   {
    //바로 뒤에 있는 데이터를 읽어서
    SetFilePointer(m_hFile,sizeof(Info)*(i+1),NULL,FILE_BEGIN);
    ReadFile(m_hFile,&Info,sizeof(Info),&nRead,NULL);
    //데이터를 삭제한 곳에 덮어쓴다.
    SetFilePointer(m_hFile,sizeof(Info)*i,NULL,FILE_BEGIN);
    WriteFile(m_hFile,&Info,sizeof(Info),&nWrite,NULL);  

   }


  }
}

if(bCompare)
{
  CInfo blank;
  memset(&blank,0,sizeof(CInfo));
  SetFilePointer(m_hFile,sizeof(CInfo)*(nNumOfData -1),NULL,FILE_BEGIN);
  WriteFile(m_hFile,&blank,sizeof(blank),&nWrite,NULL);

  MessageBox(_T("삭제가 완료되었습니다."));

}

CloseHandle(m_hFile);

}