여러 개의 프로세스들을 동시에 실행하는 컴퓨터에서는 파일 같은 공유 자원에 대한 접근 중재와 동기화가 중요한 문제가 된다.

Windows 는 파일 전체 또는 일부를 잠글 수 있다. 일단 파일 또는 파일의 일부분을 잠그면 다른 프로세스 또는 같은 프로세스의 다른 스레드는 그 파일 또는 파일의 일부분에 접근 할 수 없다. 잠금은 프로세스 수준에서 강제되는 것이기 때문에 어떠한 프로세스가 기존의 잠금을 위반하면서 파일의 일부에 대해 접근하려 하면 그 접근은 실패한다.

 파일 잠금에서 가장 일반적인 함수는 LockFileEx이다. 확장 I/O 함수군에 속하는 것으로 잠글 64비트 파일 위치와 파일 영역의 범위를 지정하기 위해 중첩 구조체가 필요하다.


 LockFileEx 함수의 원형은 다음과 같다.

 

  BOOL LockFileEx(

HANDLE hFile, // 열린 파일 핸들

DWORD dwFlags, // 잠금 모드와 자물쇠가 풀릴 때까지 기다릴지의 여부를 결정

// LOCKFILE_EXCLUSIVE_LOCK => 읽기/ 쓰기 자물쇠가 된다.

// LOCKFILE_FAIL_IMMEDIATELY => 자물쇠를 얻을 수 없는 경우 즉시 FALSE를 반환한다.

DWORD dwReserved, // 반드시 0으로 설정

DWORD nNumberOfBytesToLockLow, // 잠글 바이트 구간의 길이

DWORD nNumberOfBytesToLockHigh, // 잠글 바이트 구간의 길이

LPOVERLAPPED lpOverlapped);


 UnlockFileEx 함수의 원형은 다음과 같다. dwFlags를 제외한 매개변수는 LockFileEx와 동일하다.


 BOOL UnlockFileEx(

HANDLE hFile, // 열린 파일 핸들

DWORD dwReserved, // 반드시 0으로 설정

DWORD nNumberOfBytesToLockLow, // 잠글 바이트 구간의 길이

DWORD nNumberOfBytesToLockHigh, // 잠글 바이트 구간의 길이

LPOVERLAPPED lpOverlapped);



 파일 잠금을 사용할 때 주의사항이 몇가지 있다.


 1) 자물쇠를 해제할 때에는 파일을 잠갔을 때와 정확히 동일한 구간을 지정해야 한다. 이전의 두 잠금 구간들을 결합해서 한번에 해제한다거나 잠긴 구간의 일부만을 해제하는 것은 불가능 하다.

 2) 새 자물쇠가 기존의 잠긴 영역과 겹쳐서 충돌이 생기면 잠금이 실패한다.

 3) 파일의 끝을 넘는 영역을 잠그는 것이 가능하다.

 4) 자물쇠들이 새로 생성된 프로세스로 상속되지 않는다.


출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

특정 디렉터리 내에 있는 내용을 출력하는 프로그램입니다.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>

#define TYPE_FILE 1  
#define TYPE_DIR 2
#define TYPE_DOT 3

#define MAX_OPTIONS 20 
#define MAX_ARG 1000 
#define MAX_COMMAND_LINE MAX_PATH+50 
#define MAX_PATH_LONG 32767 
#define MAX_NAME 256    

#ifdef _UNICODE 
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

#ifdef _UNICODE 
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

#ifdef _UNICODE 
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif

BOOL TraverseDirectory(LPCTSTR, DWORD, LPBOOL);
DWORD FileType( LPWIN32_FIND_DATA);
BOOL ProcessItem( LPWIN32_FIND_DATA, DWORD, LPBOOL);
DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...);

int _tmain(int argc, LPTSTR argv[])
{
 BOOL flags[MAX_OPTIONS], ok = TRUE;
 TCHAR pathName[MAX_PATH + 1] , currPath[MAX_PATH + 1], tempPath[MAX_PATH + 1];
 LPTSTR pSlash, pFileName;
 int i, fileIndex;

 fileIndex = Options(argc, argv, _T("Rl"), &flags[0], &flags[1], NULL);

 GetCurrentDirectory(MAX_PATH, currPath);

 if( argc < fileIndex + 1)
 {
  ok = TraverseDirectory(_T("*"), MAX_OPTIONS, flags);
 }
 else 
 {
  for( i = fileIndex; i < argc; i++)
  {
   _tcscpy(pathName, argv[i]);
   _tcscpy(tempPath, argv[i]);
  
   pSlash = _tstrrchr(tempPath, '\\');

   if( pSlash != NULL )
   {
    *pSlash = '\0';
    _tcscat(tempPath, _T("\\"));
    SetCurrentDirectory(tempPath);
    pSlash = _tstrrchr(pathName, '\\');
    pFileName = pSlash + 1;
   }
   else 
   {
    pFileName = pathName;
   }

   ok = TraverseDirectory(pFileName, MAX_OPTIONS, flags) && ok;

   SetCurrentDirectory(currPath);
  }
 }
}

static BOOL TraverseDirectory(LPCTSTR pathName, DWORD numFlags, LPBOOL flags)
{
 HANDLE searchHandle;
 WIN32_FIND_DATA findData;
 BOOL recursive = flags[0];
 DWORD fType, iPass;
 TCHAR currPath[MAX_PATH + 1];

 GetCurrentDirectory(MAX_PATH, currPath);

 for( iPass = 1; iPass <= 2; iPass++)
 {
  searchHandle = FindFirstFile(pathName, &findData);

  do
  {
   fType = FileType(&findData);
   if( iPass == 1 )
   {
    ProcessItem(&findData, MAX_OPTIONS, flags);
   }

   if( fType == TYPE_DIR && iPass == 2 && recursive)
   {
    _tprintf(_T("\n%s\\%s:"), currPath, findData.cFileName);

    SetCurrentDirectory(findData.cFileName);
    TraverseDirectory(_T("*"), numFlags, flags);
    SetCurrentDirectory(_T(".."));
   }
  
  }while( FindNextFile(searchHandle, &findData));

  FindClose(searchHandle);
 }

 return TRUE;

}

static DWORD FileType(LPWIN32_FIND_DATA pFileData)
{
 BOOL isDir;
 DWORD fType;
 fType = TYPE_FILE;
 isDir =(pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 if (isDir)
  if (lstrcmp(pFileData->cFileName, _T(".")) == 0
    || lstrcmp(pFileData->cFileName, _T("..")) == 0)
   fType = TYPE_DOT;
  else fType = TYPE_DIR;
 return fType;
}

static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD numFlags, LPBOOL flags)
{
 const TCHAR fileTypeChar[] = {_T(' '), _T('d')};
 DWORD fType = FileType(pFileData);
 BOOL longList = flags[1];
 SYSTEMTIME lastWrite;

 if (fType != TYPE_FILE && fType != TYPE_DIR) return FALSE;

 _tprintf(_T("\n"));
 if (longList) {
  _tprintf(_T("%c"), fileTypeChar[fType - 1]);
  _tprintf(_T("%10d"), pFileData->nFileSizeLow);
  FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &lastWrite);
  _tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d"),
    lastWrite.wMonth, lastWrite.wDay,
    lastWrite.wYear, lastWrite.wHour,
    lastWrite.wMinute, lastWrite.wSecond);
 }
 _tprintf(_T(" %s"), pFileData->cFileName);
 return TRUE;
}

DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
{
 va_list pFlagList;
 LPBOOL pFlag;
 int iFlag = 0, iArg;

 va_start (pFlagList, OptStr);

 while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL
    && iFlag < (int)_tcslen (OptStr)) {
  *pFlag = FALSE;
  for (iArg = 1; !(*pFlag) && iArg < argc && argv [iArg] [0] == _T('-'); iArg++)
   *pFlag = _memtchr (argv [iArg], OptStr [iFlag],
     _tcslen (argv [iArg])) != NULL;
  iFlag++;
 }

 va_end (pFlagList);

 for (iArg = 1; iArg < argc && argv [iArg] [0] == _T('-'); iArg++);

 return iArg;
}
출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블​

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Tip] 문자열 처리 관련  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

1. Windows 환경에서 문자열 처리 방법


  Windows 는 표준 8비트 문자(char / CHAR)와 16비트 문자( C 의 wchar_t )를 지원한다. 8비트 문자는 ASCII 라고 부르며 16비트 문자는 유니코드(Unicode) UTF-16 인코딩을 통해 지원한다.


  UTF-8 : 유니코드를 위한 가변길이 문자 인코딩 방식. 유니코드 한 문자를 표현하기 위해 1바이트에서 4바이트 까지 사용한다.

  UTF-16 : 기본 다국어 평면에 속하는 문자들은 그대로 16비트 값으로 인코딩이 되고 그 이상의 문자는 특별히 정해진 방식으로 32비트 크기로 인코딩 된다.


2. 유니코드와 ASCII 문자열 모드를 선택하여 빌드하기 위한 프로그래밍 방법


 1) 모든 문자와 문자열을 일반적 형식 TCHAR, LPTSTR, LPCTSTR을 이용해서 정의한다.

 2) 유니코드를 사용하고자 하는 경우 모든 소스 모듈에 #define UNICODE와 #define _UNICODE 를 포함시킨다. UNICODE와 _UNICODE 정의에 따라 유니코드와 ASCII 문자열이 결정된다. 이 정의는 반드시 #include <windows.h> 전에 와야 한다.

 3) 바이트 버퍼 길이 들은 sizeof(TCHAR) 를 이용해서 계산한다.

 4) <tchar.h> 에 정의된 범용 C 라이브러리 문자열 및 I/O 함수를 사용한다. _fgettc, _itot 등

 5) 상수 문자열은 다음 세가지 형태 중 하나이어야 한다.

   5.1) "이 문자열은 8비트 문자들을 사용함"

   5.2) L"이 문자열은 16비트 문자들을 사용함"

   5.3) _T("이 문자열은 전처리 구문에 따라 달라짐")

 6) 텍스트 매크로들과 범용 C 라이브러리 함수들의 정의를 위해 windows.h 다음에 tchar.h를 포함한다.


출처 : 위키백과 / Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블

'0x001 Programming > 01. C | C++' 카테고리의 다른 글

[Example] 예외 처리  (0) 2017.12.29
[Tip] 예외 처리  (0) 2017.12.29
[Tip] 파일 잠금  (0) 2017.12.29
[Example] 디렉터리 내용 출력  (0) 2017.12.29
[Example] 파일 복사  (0) 2017.12.29

+ Recent posts