::NPTEAM:: Network Programer Team

검색 :
RSS 구독 : 글 / 댓글 / 트랙백 / 글+트랙백

[C++] ReturnMacro

C++ 코드 작성시 가독성과 흐름처리를 원활하게 하기 위해서 다음과 같이 리턴 처리를 자주하게 된다.

bool LogicProcedure()
{
    if( A_Logic )
    {
        return false;
    }

    if( B_Logic )
    {
        return false;
    }

    return true;
}
위와 같이 중간에 흐름제어를 하기 위해서 try catch를 쓰고 싶어진다.

이를 해결하기 위해서 ReturnMacro를 작성하였다.

프로그래머에게 금기시되는 goto 제어문을 define으로 감싸서
1. 코드 가독성
2. 사용자 편의
3. 성능상의 잇점
3가지를 모두 얻을 수 있도록 헤더 파일을 제작하였다.



#pragma once

#include < strsafe.h >

//////////////////////////////////////////////////////////////////////////
// ReturnMacro For Singleton Class
template < typename T >
class CReturnMacroForSingleton
{
public:
	static T * InstancePtr()
	{
		if( ms_Instance == NULL ) ms_Instance = new T;
		return ms_Instance;
	};
	static T & Instance()
	{
		if( ms_Instance == NULL ) ms_Instance = new T;
		return *ms_Instance;
	};
	static void DestroyInstance()
	{
		delete ms_Instance;
		ms_Instance = NULL;
	};

private:
	static T * ms_Instance;
};

template< typename T > T* CReturnMacroForSingleton::ms_Instance = 0;
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
class CReturnMacro : public CReturnMacroForSingleton< CReturnMacro >
{
public:
	explicit CReturnMacro()
		: m_nGetLastLine(0)
	{
		memset( m_tszFunctionName, 0, sizeof( m_tszFunctionName ) );
	};

	~CReturnMacro() {};

public:
	inline int	GetLastLine()							{ return m_nGetLastLine;		}
	inline void	SetLastLine( int nLine )				{ m_nGetLastLine = nLine;		}

	inline TCHAR* GetFunctionName()						{ return m_tszFunctionName;		}
	inline void	  SetFunctionName( TCHAR* ptszFnName )
	{
		if( FAILED( StringCchCopy( m_tszFunctionName, _countof( m_tszFunctionName ), ptszFnName ) ) )
		{
			memset( m_tszFunctionName, 0, sizeof( m_tszFunctionName ) );
		}
	}

private:
	int		m_nGetLastLine;
	TCHAR	m_tszFunctionName[256];
};

#define RETURNMACRO CReturnMacro::Instance()
//////////////////////////////////////////////////////////////////////////


struct RETURN_RESULT
{
	int		LastLine;
	TCHAR*	LastFnName;
};

#define RETURN_VOID

//////////////////////////////////////////////////////////////////////////
// RETURN FAIL
#define RETURN_FAIL()													\
	RETURNMACRO.SetLastLine( __LINE__ );								\
	RETURNMACRO.SetFunctionName( _T(__FUNCTION__) );					\
	goto RET_FAIL;

#define RETURN_FAIL_BEGIN()												\
	RET_FAIL:															\
	RETURN_RESULT Ret_Fail;												\
	Ret_Fail.LastLine	= RETURNMACRO.GetLastLine();					\
	Ret_Fail.LastFnName = RETURNMACRO.GetFunctionName();

#define RETURN_FAIL_END( ReturnValue )									\
	return ReturnValue;
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// RETURN_SUCCESS
#define RETURN_SUCCESS( )												\
	RETURNMACRO.SetLastLine( __LINE__ );								\
	RETURNMACRO.SetFunctionName( _T(__FUNCTION__) );					\
	goto RET_SUCCESS;

#define RETURN_SUCCESS_BEGIN()											\
	RET_SUCCESS:														\
	RETURN_RESULT Ret_Success;											\
	Ret_Success.LastLine   = RETURNMACRO.GetLastLine();					\
	Ret_Success.LastFnName = RETURNMACRO.GetFunctionName();

#define RETURN_SUCCESS_END( ReturnValue )								\
	return ReturnValue;
//////////////////////////////////////////////////////////////////////////


Visual Assist Snippet code
RETURN_SUCCESS();


#pragma region RETURN_MACRO

	RETURN_FAIL_BEGIN();
	// Fail Code.
	RETURN_FAIL_END( RETURN_VOID );

	RETURN_SUCCESS_BEGIN();
	// Success Code.
	RETURN_SUCCESS_END( RETURN_VOID );

#pragma endregion RETURN_MACRO
2009/11/21 22:22 2009/11/21 22:22

맨 위로

[C/C++] enum, 보다 나은 enum


프로그래머라면 누구나 enum값이 4byte 정수 자료형이라는 사실을 알고 있습니다.

switch( xxx ) : xxx 에는 정수 자료형만 올 수 있다는 것도 알고 있습니다.

switch( string )
{
  case "A_Case": ... break;
  case "B_Case": ... break;
}

이런식으로 switch 문에서도 문자열을 받고 싶을때가 많습니다.
혹은 enum 값을 1:1 매칭되는 문자열 값으로 변환하고 싶을때가 많습니다.

우연히 웹 서핑을 하던 중 http://eslife.tistory.com/entry/CC-enum-보다-나은-enum을 읽게 되었고, 약간의 팁을 보강하여 다음과 같이 정리하였습니다.


test.h 헤더 파일에 다음과 같이 작성한다.
namespace nsETREEITEMTYPE
{
  // enum ETREEITEMTYPE의 enum 값을 나열한다.(eTIY_GROUP...)
#undef ENUM_LIST
#define ENUM_LIST(ENUM_VALUES)  \
  ENUM_VALUES(GROUP)      \
  ENUM_VALUES(CONNECTION)  \
  ENUM_VALUES(COUNT)
 
#undef DO_DESCRIPTION
#undef DO_ENUM
#define DO_DESCRIPTION(enumValue) _T(#enumValue),
#define DO_ENUM(enumValue) eTIY_##enumValue,
 
  // enum Type 이름(ETREEITEMTYPE)을 설정한다.
  enum ETREEITEMTYPE
  {
    ENUM_LIST(DO_ENUM)
  };
 
  // enum 배열 이름(ptszETIYDescription)을 설정한다.
  static TCHAR* ptszETIYDescription[] =
  {
    ENUM_LIST(DO_DESCRIPTION)
  };
};

위 문장이 전처리기 지시어로 도배(?)가 되어 있어서 가독성이 매우 떨어집니다.
잘 이해가 안가시는 분들을 위해서 한가지 팁을 알려 드리겠습니다.(전처리기 지시어를 자동 변환하는 방법 입니다.)
"C:\Program Files\Microsoft Visual Studio 8\VC\bin\cl.exe" 를 사용하시면 됩니다.

1. test.h 헤더파일에서 #include 문을 모두 주석처리 합니다.
  (#include 문을 만나면 파일을 포함하려고 시도하다가 찾지 못하면 에러가 발생하고, 전처리기 지시문 변환을 실패합니다.)
2. cmd(console 입력창)에서 다음과 같이 입력합니다.
cl /EP /C test.h > c:\result.txt & notepad c:\result.txt

결과는 다음과 같습니다. 두둥!!
//////////////////////////////////////////////////////////////////////////
// 결과 확인 (#include 문이 들어 있으면 결과가 출력되지 않는다.)
// cl /EP /C test.h > c:\result.txt & notepad c:\result.txt
 
namespace nsETREEITEMTYPE
{
  // enum Type 이름(ETREEITEMTYPE)을 설정한다.
  enum ETREEITEMTYPE
  {
    eTIY_GROUP, eTIY_CONNECTION, eTIY_COUNT,
  };
 
  // enum 배열 이름(ptszETIYDescription)을 설정한다.
  static TCHAR* ptszETIYDescription[] =
  {
    _T("GROUP"), _T("CONNECTION"), _T("COUNT"),
  };
};

전처리기 지시어가 깔끔하게 해석되어 나오는 것을 볼 수 있습니다.

이렇게 작성하면 enum 값을 문자열로 변환하고 싶을때,
TCHAR* pString = nsETREEITEMTYPE::ptszETIYDescription[nsETREEITEMTYPE::eTIY_GROUP];
이렇게 쓰시면,
TCHAR* pString = _T("GROUP");
와 같은 결과를 얻으실 수 있습니다.

장점 1. namespace를 사용해서 인텔리센스를 적극적으로 활용할 수 있다.
장점 2. enum 자료형을 추가하면 그에 맞는 문자열이 등록된다.
         (enum 값만 추가하고 문자열을 등록하지 않는 실수를 막을 수 있다.)
장점 3. 전처리기 지시어를 두려워하지 않아도 된다.(cl 명령어로 손쉽게 해석해서 보시면 됩니다.)
2009/01/07 21:23 2009/01/07 21:23

맨 위로

[How to get mouse movement history?] 마우스 이동

출처 : http://nibuthomas.wordpress.com/2007/11/30/how-to-get-mouse-movement-history/

The GetMouseMovePointsEx function retrieves a history of up to 64 previous coordinates of the mouse or pen.

Here is a demo that replays our mouse movements…

void ReplayMouseMovements()
{
	// Current cursor position
	POINT ptCurrentPoint = { 0 };
	GetCursorPos( &ptCurrentPoint );

	// Record marker, mouse co-ordinates prior(and including) to this point is returned in
	// the recorded array of points
	MOUSEMOVEPOINT mmpSamplePoint = { 0 };
	mmpSamplePoint.x = ptCurrentPoint.x;
	mmpSamplePoint.y = ptCurrentPoint.y;

	// Count of records expected, MSDN says max points returned will be 64
	// Anything greater than 64 results in error, API returns -1
	const DWORD dwMaxPoints = 64;

	// On return from function will hold last recorded mouse movements
	MOUSEMOVEPOINT mmpRecordedMovements[dwMaxPoints] = { 0 };
	const DWORD dwMode = GMMP_USE_DISPLAY_POINTS;

	// Get all points prior to sample point
	const int nPtCount = GetMouseMovePointsEx( sizeof( mmpSamplePoint ),
			&mmpSamplePoint,
			mmpRecordedMovements,
			dwMaxPoints ,
			dwMode ) ;

	// Loop through and animate
	for (int nIndex = 0; nIndex < nPtCount; nIndex++)
	{
		SetCursorPos( mmpRecordedMovements[nIndex].x, mmpRecordedMovements[nIndex].y );
		Sleep( 80 );
	}
} // End ReplayMouseMovements
2008/02/13 00:57 2008/02/13 00:57

맨 위로

[클립보드 복사] CopyTextToClipboard Helper Function


 
static bool CopyTextToClipboard( HWND hWindow_i,
		LPCTSTR lpctszText_i )
{
	// Open clipboard
	if ( !lpctszText_i !::OpenClipboard( hWindow_i ))
	{
		return false;
	}

	// Clear clipboard
	EmptyClipboard();

	const int nTotalAllocLen = ( _tcslen( lpctszText_i ) + 1 )
			* sizeof( TCHAR ) ;
	HGLOBAL hGlobal = GlobalAlloc( GMEM_MOVEABLE, nTotalAllocLen );
	if ( !hGlobal )
	{
		CloseClipboard();
		return false;
	}

	// Lock allocated buffer for copying
	LPTSTR lptszCopyStr = RCAST( LPTSTR, GlobalLock( hGlobal ));
	memcpy( lptszCopyStr, lpctszText_i, nTotalAllocLen );
	GlobalUnlock( hGlobal );
	ASSERT( GetLastError() == NO_ERROR );

	// Clipboard format
	UINT uClipBoardFormat = 0;
	#ifdef _UNICODE
	uClipBoardFormat = CF_UNICODETEXT;
	#else
	uClipBoardFormat = CF_TEXT;
	#endif

	// Set data to clipboard
	HANDLE hClip = SetClipboardData( uClipBoardFormat, hGlobal );
	CloseClipboard();

	// Return status
	return ( hClip ? true : false );
} // End CopyTextToClipboard
2008/02/12 20:13 2008/02/12 20:13

맨 위로

ifstream 사용시, 한글 파일을 못 읽는 문제


vs2005에서 ifstream으로 파일명이 한글로된 파일을 읽지 못하는 문제가 생긴다.
이 때는 아래의 코드를 main에 추가해서 사용하자
#include <locale>
 
setlocale( LC_ALL, "Korean" )// Console 화면에 한국어 출력
2007/12/30 11:02 2007/12/30 11:02

맨 위로

[DEFINE] BEGINTHREADEX 사용을 위한 디파인

///////////////////////////////////////////////////////////////////////////////
// Helper macros
//
 
// _beginthreadex wrapper macro (source: J.Richter, "Advanced Windows")
// Have to include "process.h"
typedef unsigned (__stdcall *PTHREAD_START) (void*);
 
#define BEGINTHREADEX(lpsa, cbStack, lpStartAddr, lpvThreadParm, fdwCreate, lpIDThread) \
                     (  (HANDLE)_beginthreadex(                                         \
                                                (void*)(lpsa),                          \
                                                (unsigned)(cbStack),                    \
                                                (PTHREAD_START)(lpStartAddr),           \
                                                (void*)(lpvThreadParm),                 \
                                                (unsigned)(fdwCreate),                  \
                                                (unsigned*)(lpIDThread))  )
 
2007/09/24 00:00 2007/09/24 00:00

맨 위로

BeginThreadEx를 쓰기 위한 샘플

 
///////////////////////////////////////////////////////////////////////////////
//
// DeadLockDemo.cpp
//
// Author: Oleg Starodumov (www.debuginfo.com)
//
// This application simulates a deadlock
//
//
 
 
///////////////////////////////////////////////////////////////////////////////
// Include files
//
 
#include <windows.h>
#include <tchar.h>
 
#include <process.h>
#include <stdio.h>
 
 
///////////////////////////////////////////////////////////////////////////////
// Helper macros
//
 
// _beginthreadex wrapper macro (source: J.Richter, "Advanced Windows")
 
typedef unsigned (__stdcall *PTHREAD_START) (void*);
 
#define BEGINTHREADEX(lpsa, cbStack, lpStartAddr,\
  lpvThreadParm, fdwCreate, lpIDThread)          \
  ((HANDLE)_beginthreadex(                     \
  (void*)(lpsa),                           \
  (unsigned)(cbStack),                     \
  (PTHREAD_START)(lpStartAddr),            \
  (void*)(lpvThreadParm),                  \
  (unsigned)(fdwCreate),                   \
  (unsigned*)(lpIDThread)))
 
 
///////////////////////////////////////////////////////////////////////////////
// Critical section wrapper classes
//
 
class CCriticalSection
{
public:
 
  CCriticalSection()
  {
    InitializeCriticalSection( &m_cs );
  }
 
  ~CCriticalSection()
  {
    DeleteCriticalSection( &m_cs );
  }
 
  void Lock()
  {
    EnterCriticalSection( &m_cs );
  }
 
  void Unlock()
  {
    LeaveCriticalSection( &m_cs );
  }
 
private:
 
  // Copy protection
  CCriticalSection( const CCriticalSection& );
  CCriticalSection& operator=( const CCriticalSection& );
 
private:
 
  // Critical section structure
  CRITICAL_SECTION m_cs;
};
 
class CCritSecLock
{
public:
 
  CCritSecLock( CCriticalSection& cs )
    : m_rcs( cs )
  {
    m_rcs.Lock();
  }
 
  ~CCritSecLock()
  {
    m_rcs.Unlock();
  }
 
private:
 
  // CCriticalSection object reference
  CCriticalSection& m_rcs;
};
 
 
///////////////////////////////////////////////////////////////////////////////
// Function declarations
//
 
DWORD WINAPI ThreadOne( LPVOID lpParam );
DWORD WINAPI ThreadTwo( LPVOID lpParam );
 
 
///////////////////////////////////////////////////////////////////////////////
// Global variables
//
 
CCriticalSection CritSecOne;
CCriticalSection CritSecTwo;
 
 
///////////////////////////////////////////////////////////////////////////////
// main()
//
 
int _tmain( int argc, TCHAR* argv[] )
{
  // Start worker threads
 
  _tprintf( _T("Starting worker threads...\n") );
 
  HANDLE  hThread   = NULL;
  DWORD   ThreadId  = 0;
 
  hThread = BEGINTHREADEX(0, 0, ThreadOne, 0, 0, &ThreadId );
 
  if( hThread == NULL )
  {
    _tprintf( _T("Cannot start thread. Error: %u\n"), GetLastError() );
    return 0;
  }
 
  hThread = BEGINTHREADEX(0, 0, ThreadTwo, 0, 0, &ThreadId );
 
  if( hThread == NULL )
  {
    _tprintf( _T("Cannot start thread. Error: %u\n"), GetLastError() );
    return 0;
  }
 
 
  // Worker threads started
 
  _tprintf( _T("Worker threads started.\n") );
 
  Sleep( 60 * 60 * 1000 );
 
 
  // Complete
 
  _tprintf( _T("Test complete.\n") );
 
  return 0;
}
 
 
///////////////////////////////////////////////////////////////////////////////
// Worker threads
//
 
DWORD WINAPI ThreadOne( LPVOID lpParam )
{
  _tprintf( _T("ThreadOne[%u] started.\n"), GetCurrentThreadId() );
 
  while( 1 )
  {
    CCritSecLock LockOne( CritSecOne );
 
    _tprintf( _T("ThreadOne[%u] acquired CritSecOne\n"), GetCurrentThreadId() );
 
    {
      CCritSecLock LockTwo( CritSecTwo );
 
      _tprintf( _T("ThreadOne[%u] acquired CritSecTwo.\n"), GetCurrentThreadId() );
    }
  }
 
  return 0;
}
 
DWORD WINAPI ThreadTwo( LPVOID lpParam )
{
  _tprintf( _T("ThreadTwo[%u] started.\n"), GetCurrentThreadId() );
 
  while( 1 )
  {
    CCritSecLock LockTwo( CritSecTwo );
 
    _tprintf( _T("ThreadTwo[%u] acquired CritSecTwo\n"), GetCurrentThreadId() );
 
    {
      CCritSecLock LockOne( CritSecOne );
 
      _tprintf( _T("ThreadTwo[%u] acquired CritSecOne\n"), GetCurrentThreadId() );
    }
  }
 
  return 0;
}
 
2007/09/23 23:50 2007/09/23 23:50

맨 위로

[알고리즘] 가우시안 랜덤 함수


// main.cpp : 가우시안 랜덤 알고리즘 테스트
//
 
#include "stdafx.h"
#include <windows.h>
#include "math.h"
#include <iostream>
#include <vector>
#include <algorithm>
 
using namespace std;
 
double GaussianRandom(void)
{
  double v1, v2, s;
 
  do
  {
    v1 =  2 * ((double) rand() / RAND_MAX) - 1;      // -1.0 ~ 1.0 까지의 값
    v2 =  2 * ((double) rand() / RAND_MAX) - 1;      // -1.0 ~ 1.0 까지의 값
    s = v1 * v1 + v2 * v2;
  } while (s >= 1 || s == 0);
 
  s = sqrt( (-2 * log(s)) / s );
 
  return v1 * s;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
  srand(GetTickCount());
 
  vector <double> vResult(400);
 
  for (size_t i = 0; i < vResult.size(); i++)
  {
    vResult[i] = GaussianRandom();
  }
 
  sort( vResult.begin(), vResult.end() );
 
  for (size_t i = 0; i < vResult.size(); i++)
  {
    printf("[%d]   %.17f\n", i, vResult[i] );
  }
 
  return 0;
}
 
2007/05/06 05:56 2007/05/06 05:56

맨 위로

ShellExecuteEx() - 파일 실행 - 기다리기~~



BOOL ExecuteProgram( String FileName, String Params, INT Flag )
{
  SHELLEXECUTEINFO execinfo;
 
  // 실행을 위해 구조체 세트
  ZeroMemory( &execinfo, sizeof(execinfo) );
  execinfo.cbSize = sizeof(execinfo);
  execinfo.lpVerb = "open";
  execinfo.lpFile = FileName.c_str();
  execinfo.lpParameters = Params.c_str();
  execinfo.fMask = SEE_MASK_FLAG_NO_UI SEE_MASK_NOCLOSEPROCESS;
  execinfo.nShow = SW_SHOWDEFAULT;
 
  // 프로그램을 실행한다.
  int r = (int)ShellExecuteEx( &execinfo );
  if ( r == 0 ) return ( false );
 
  // 만약 Sync 플랙이 세트되었으면,
  // 실행이 종료될 때까지 기다린다.
  if ( Flag == 1 )
  {
    DWORD ec;
    do
    {
      GetExitCodeProcess( execinfo.hProcess, &ec );
      Application->ProcessMessages();
    }
    while ( ec == STILL_ACTIVE );
  }
 
  return ( true );
}
 
2007/05/01 16:56 2007/05/01 16:56

맨 위로

[ODBC] ODBC로 Excel(엑셀) 파일 읽고 쓰기

출처 : http://www.codeproject.com/database/excel_odbc_write.asp
출처 : http://www.codeproject.com/database/excel_odbc.asp

ODBC를 이용하여 Excel 파일을 읽고 쓰는 프로젝트 예제

2007/03/27 00:47 2007/03/27 00:47

맨 위로

[MFC] OpenUrl로 html 소스 코드 얻어오기

블로그내 관련 링크 : http://www.npteam.net/80

CInternetFile* pFile = NULL;
CInternetSession InetSession;
 
try
{
  pFile = (CInternetFile *)InetSession.OpenURL( "URL 주소 : http://???" )
}
catch(CInternetException *pEx)
{
  pFile = NULL;
  pEx = NULL;
  AfxMessageBox( "OpenURL Excption Error!" );
}
 
CString strData;
 
if( pFile )
{
  CString strTemp;
  pFile->SetReadBufferSize( 4096 );
 
  while( true )
  {
    if( pFile->ReadString( strTemp ) )
    {
      strTemp += "\r\n";
      strData += strTemp;
    }
    else
    {
      break;
    }
  }
}
else
{
  AfxMessageBox( "OpenURL pFile is NULL!!" );
}
 
MessageBox( strData );
 
2007/01/05 21:22 2007/01/05 21:22

맨 위로

[C++]File Memory Mapping - 대용량 파일 입출력 처리

파일내용을 그대로 메모리에 올려서 메모리에 올려진 파일내용을 수정하고 수정된 내용을 디스크 파일에 쓴다. 순서는 다음과 같다.

- 파일 오픈                                                                  hF=CreateFile("test.txt")
- 파일 내용을 메모리에 올린다                                        hMapF=CreateFileMapping(hF)
- 메모리에 올려진 첫번째 주소를 얻는다.                          pF=MapViewOfFile(hMapF)
- 첫번째 주소로 메모리 내용을 조작한다.
- 중간중간에 변경된 내용을 강제로 디스크에 쓰게만든다.    FlushViewOfFile(pF)
- 해제.                                                                        UnmapViewOfFile(pF);
- 해제.                                                                        CloseHandle(hMapF);
- 파일 닫기.                                                                 CloseHandle(hF);

<예제>

#include <windows.h>
#include <stdio.h>
 
int main(int argc, char **argv)
{
  HANDLE hFile, hMapFile;
  DWORD dwFileSize;
  char *pFile, *pFileTemp;
 
  hFile = CreateFile( "test.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  // hFile = CreateFile( "test.txt", GENERIC_READ, FILESHARE_READ, NULL, OPEN_EXISTING, 0, NULL); // 읽기
 
  dwFileSize = GetFileSize( hFile, NULL );
 
  hMapFile = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, NULL );
  // hMapFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );    // 읽기
 
  if( hMapFile == NULL )
  {
    printf( "CreateFileMapping() fail" );
    CloseHandle( hFile );
    return 1;
  }
 
  pFile = (char*)MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
  //pFile = (char*)MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 );
 
 
  // Do SomeThing...
  pFileTemp = pFile;
 
  for(UINT i = 0; i < dwFileSize; i++ )
  {
    *pFileTemp = (*pFileTemp + 1);
    pFileTemp++;
  }
  // SomeThing End..
 
 
  //메모리 내용을 강제로 파일에 쓴다.
  FlushViewOfFile( pFile, 0 );
 
  UnmapViewOfFile( pFile );
  CloseHandle( hMapFile );
  CloseHandle( hFile );
 
  return 0;
}
 
2006/12/07 10:53 2006/12/07 10:53

맨 위로

[MFC] 대용량의 파일 순식간에 읽기

대용량의 파일 순식간에 읽기

1.요약

10M 이상이 되는 파일을 빠르게 읽는 방법을 알아보기로 합니다.

2.본문

<대용량 파일 읽기 (빠르게...)>
v 파일 읽기는 자주 사용하실 것인데.. CFile::Read를 사용하면.. 10MB정도 되는 파일을 읽으면 무진장 오래 걸려서.. 메모리 맵 파일을 이용한 파일 읽기 방법을 올려 들립니다..

많은 예제가 나온것으로 알지만.. 혹시... 도 몰라서..

BOOL OpenFiles(LPCSTR lpszPathName)
{
  DWORD dwFileSize;
  HANDLE hFile, hFileMap;
  LPVOID lpvFile;
 
  hFile = ::CreateFile( lpszPathName, GENERIC_READ , 0, NULL
    OPEN_EXISTING, FILE_ATTRIBUTTE_NORMAL, NULL );
 
  if( hFile == INVALID_HANDLE_VALUE )
  {
    // 여기에서 에러 메세지 처리..
  }
 
  dwFileSize = ::GetFileSize(hFile, NULL);
 
  hFileMap = CreateFileMapping( hFile, NULL, PAGE_WRITECOPY, 0,
    dwFileSize, NULL );
 
  if( hFileMap == NULL )
  {
    CloseHandle(hFile);
    //여기에서 에러 메세지 처리..
  }
 
  lpFile = MapViewOfFile( hFileMap, FILE_MAP_COPY, 0, 0, 0 );
 
  if( lpFile == NULL )
  {
    CloseHandle( hFile );
    CloseHandle( hFileMap );
    //여기에서 에러 처리
  }
}

이렇게 하면.. 대용량의 파일을 빠르게 읽을 수 있습니다..

제가 시간을 한번 제어 봤는데.. 4초 안에 끊나더군요..

흠.. 그리고 여기에 나온 함수는 Help에서 정확한 내용을 보세요.

.
<대용량 파일 빠르게 읽기 2>

메모리 맵파일을 이용한 방법외에 간단한 방법이 있어서 말씀드려볼까 합니다.

어려운 루틴은 아니고요, 그냥 도스용 시절에 사용했던 fread함수를 사용한 것입니다.

물론 fread대신 다른 파일 읽기 함수를 사용해도 됩니다.

다만 사용자 편의를 위해서 추가로 만들어진 파일함수들은(파일함수뿐만 아니라 다른 것들도 마찬가지...) 사용하긴 편하겠지만, 속도가 무척 느린 문제가 있습니다.

char *ReadFile( char *FileName )
{
  FILE *fp;
  int FileSize;
  char *buffer;
 
  try
  {
    fp = fopen( FileName, "rb" );
    if( !fp ) throw "File Not Found!";
   
    FileSize = filelength( fileno(fp) );
    buffer = new char [FileSize+1];
    fread( buffer, FileSize, 1, fp );
    *(buffer + FileSize) = 0;
    fclose( fp );
    return buffer;
  }
  catch( char *msg )
  {
    printf( msg );
    return NULL;
  }
}

위의 try ~ catch구분은 중요한것은 아니고요, 대부분의 프로그래머분들이 예외처리를 함에 있어서 일반적인 C스타일로 일일히 에러메시지를 코딩하더군요.

그래서 혹시나 도움이 될까 해서 try ~ catch구분을 사용해보았습니다. 어려운건 아니니깐 try ~ catch를 사용하면 코딩이 훨씬 간단해질꺼예요. ^^

그리고 위의 파일읽기 함수를 fopen/fread등을 사용했는데, 이건 C를 시작하는 분들 께 조금이나마 이해가 쉽도록 도스에서 사용하던 함수를 사용했습니다. 물론 이 함수들은 윈도우즈에서도 그대로 사용할수 있습니다.

원래 도스에서 fread는 한블럭최대크기가 64k로 제한됩니다.

따라서 64k씩 나누어서 파일을 읽어들여야 하는데, 윈도우즈에서는 그냥 한번에 읽을 수 있더군요. ^^

10메가 정도 읽어들이는데 있어서, 펜133의 컴에서 약 3초미만으로 걸리는 것 같습니다.

 
2006/12/03 06:04 2006/12/03 06:04

맨 위로

[c++] new 메모리 할당 실패시 처리 방법

 
#include <iostream.h>
#include <stdlib.h>
#include <new.h>
void newError();
 
int main()
{
  set_new_handler(newError);
 
  char * c1 = new char[2];
  cout << "First allocation worked properly.\n";
 
  char * c2 = new char[64000]// 잘못된 할당(너무 많은 문자가 할당)
  cout << "Second allocation worked properly.\n";
 
  delete [] c1;
  delete [] c2;
 
  return 0;
}
 
void newError()
{
  // 에러 메시지 출력 후 프로그램 종료
  cerr << "Cannot allocate the requested memory.\n";
  exit(1);
}
 
2006/11/28 20:24 2006/11/28 20:24

맨 위로

[MFC] 풀 스크린으로 윈도우 생성 & 메뉴 제거


BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 
  if( !CFrameWnd::PreCreateWindow(cs) )
  {
    return FALSE;
  }
 
 
  // 윈도우 스타일과 위치를 강제로 조정하라.
  cs.style = WS_OVERLAPPED WS_POPUP WS_VISIBLE WS_MAXIMIZE;
  cs.cx = ::GetSystemMetrics(SM_CXSCREEN);
  cs.cy = ::GetSystemMetrics(SM_CYSCREEN);
 
  // 메뉴를 제거하라
  CMenu* pMenu = new CMenu;
  pMenu->Attach( cs.hMenu );
  pMenu->DestroyMenu();
  cs.hMenu = NULL;
  delete pMenu;
 
  return TRUE;
}


MFC에서는 CFrame를 시작점으로 해서 나머지 윈도우가 나타나게 됩니다. CFrame를 상속받은 CMainFrame의 PreCreateWindow는 가상함수입니다. 또한 해당하는 역할은 윈도우를 보여주기 바로 전 단계에서 윈도우 스타일을 바꿀수 있죠.

위에서 바로 그점을 이용한 예제입니다.

2006/11/15 13:29 2006/11/15 13:29

맨 위로