정리

Delay Load 관련 내용

저장소/VC++
Delay Load 처리 방법은 다음과 같이 소스코드에 추가해주면 된다.

#pragma comment(linker, "/DELAYLOAD:파일이름.dll")

근데 Visual Studio 2008에서 빌드해보면

warning LNK4229: invalid directive '/DELAYLOAD:파일이름.dll' encountered; ignored

이와 같은 경고를 표시한다.
제대로 처리되지도 않는다.

MSDN에 다음과 같이 기술되어있다.
(http://msdn.microsoft.com/en-us/library/7f0aews7%28v=VS.90%29.aspx)

Only the following (comment-type) linker options are available to be passed to the linker identifier:

결국은 Property 설정에서 지정하라는 말인 것 같은데
Property->Linker->Input->Delay Loaded DLLs 에 필요한 모듈을 기술하고 빌드하면 경고 없이 잘 된다.
Delay Load의 Unload는 다음과 같이 설정할 수 있다.
Property->Linker->Advanced->Delay Loaded DLL을 Support Unload(/DELAY:UNLOAD)로 설정해주면 된다.

Delay Load에 대한 보다 자세한 사항은 책과 검색을 통해서 익히도록... 후후후...

[Win32 API] File Version 확인

저장소/VC++
파일 버전만 필요로 할 때가 있으려나...
간단한 파일 버전 확인 방법을 정리한다.

#include 
#pragma comment(lib, "version.lib")

int GetFileVersion(LPCTSTR _lpszFilePath, LPTSTR _lpszBuf, DWORD _cchBuf)
{
	if( NULL == _lpszFilePath	||
		NULL == _lpszBuf		)
	{
		return -1;
	}

	DWORD dwHandle = 0;
	DWORD dwSize = 0;

	dwSize = ::GetFileVersionInfoSize(_lpszFilePath, &dwHandle);
	if(0 == dwSize)
		return -1;

	BYTE* pBlockData = new BYTE[dwSize];
	ZeroMemory(pBlockData, dwSize);

	if(FALSE == ::GetFileVersionInfo(_lpszFilePath, dwHandle, dwSize, pBlockData))
	{
		delete [] pBlockData;

		return -1;
	}

	// File Version
	VS_FIXEDFILEINFO* pVerInfo = NULL;
	UINT uLen = 0;

	if(FALSE == ::VerQueryValue(pBlockData, _T("\\"), (LPVOID*)&pVerInfo, &uLen))
	{
		delete [] pBlockData;

		return -1;
	}

	StringCchPrintf(_lpszBuf, _cchBuf,
					_T("%d.%d.%d.%d"),
					HIWORD(pVerInfo->dwFileVersionMS),	// Major
					LOWORD(pVerInfo->dwFileVersionMS),	// Minor
					HIWORD(pVerInfo->dwFileVersionLS),	// Release
					LOWORD(pVerInfo->dwFileVersionLS));	// Test

	delete [] pBlockData;

	return 0;
}
VerQueryValue의 두 번째 인자인 lpSubBlock의 다른 사용 예로 VS_FIXEDFILEINFO 를 얻어 버전 정보를 확인할 수 있다.
버전 확인 외에 다른 용도는 없는 것 같기도 하고...
버전만 확인할 때 쓰면 되겠다.

[Win32 API] File Information 확인 (1)

저장소/VC++
파일 정보를 확인해야 할 일이 얼마나 있을까?
그나마 많이 확인하는 것이 Attribute나 Size, Version 이정도?
혹시나 필요할 일이 생길까 싶어서 정리한다.

#include 
#pragma comment(lib, "version.lib")

#include 


typedef struct _Lang_And_Code_Page
{
	WORD	wLanguage;
	WORD	wCodePage;
}
LANGANDCODEPAGE, *LPLANGANDCODEPAGE;


int GetFileInformation(LPCTSTR _lpszFilePath, LPCTSTR _lpszInfoString, LPTSTR _lpszBuf, DWORD _cchBuf)
{
	if( NULL == _lpszFilePath	||
		NULL == _lpszInfoString	||
		NULL == _lpszBuf		)
	{
		return -1;
	}

	DWORD dwHandle = 0;
	DWORD dwSize = 0;

	dwSize = ::GetFileVersionInfoSize(_lpszFilePath, &dwHandle);
	if(0 == dwSize)
		return -1;

	BYTE* pBlockData = new BYTE[dwSize];
	ZeroMemory(pBlockData, dwSize);

	if(FALSE == ::GetFileVersionInfo(_lpszFilePath, dwHandle, dwSize, pBlockData))
	{
		delete [] pBlockData;

		return -1;
	}

	UINT uLangCodePage = 0;
	LPLANGANDCODEPAGE pLangCodePage = NULL;

	if(FALSE == ::VerQueryValue(pBlockData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&pLangCodePage, &uLangCodePage))
	{
		delete [] pBlockData;

		return -1;
	}

	//
	int nRet = 0;
	TCHAR szResource[50] = {0,};
	TCHAR* pszBuffer = NULL;
	UINT uBufSize = 0;

	for(UINT i = 0 ; i < (uLangCodePage / sizeof(LANGANDCODEPAGE)) ; i++ )
	{
		StringCchPrintf(szResource, 50, _T("\\StringFileInfo\\%04x%04x\\%s"), pLangCodePage[i].wLanguage, pLangCodePage[i].wCodePage, _lpszInfoString);

		if(::VerQueryValue(pBlockData, szResource, (LPVOID*)&pszBuffer, &uBufSize))
			StringCchCopy(_lpszBuf, _cchBuf, pszBuffer);
		else
			nRet = -1;
	}

	delete [] pBlockData;

	return nRet;
}
이렇게 하면 몇몇 정보는 얻어올 수 있지만 파일 등록정보에서 확인할 수 있는 모든 정보를 확인하지는 못한다.
for문과 같은 처리는 파일 정보가 여러 언어로 되어있을 때 확인하기 위해 사용되는건가?
GetFileVersionInfoSizeEx와 GetFileVersionInfoEx에 첫 번째 인자로 Flag를 받게끔 되어있는데 이와 연관되어있을듯 하다.
MSDN을 대충 해석하고 참고해서 만든 것인데 아무래도 설명이 필요할 것 같다.
GetFileVersionInfoSizeEx와 GetFileVersionInfoEx에 대한 내용을 포함해서 나머지 부분은 다음에 다시...

[Win32 API] 가변인자 처리 방식, 그리고 오류

저장소/VC++
최근 가변인자 처리 과정에서 생각치 못했던 오류가 발생했다.(원인은 내 실수 ㅡㅜ)
그리 어려웠던 것도 아니었는데 시간은 시간대로 소비하고 간신히 원인을 찾았는데 정말 생각하지도 못했던 문제였기에 적어본다.

우선 가변인자 처리에는 _vstprintf_s의 사용보다는 Strsafe.h에 있는 StringCchVPrintf 함수를 주로 사용한다.
익숙해져서이기도 하지만 안전한 문자열 처리를 위해 Strsafe.h에 있는 함수들을 사용하기 때문이다.
내가 보편적으로 쓰는 처리방식은 아래와 같다.
void OuputFunction(LPCTSTR lpszFormat, ...)
{
	TCHAR szContent[1024] = {0,};

	va_list vlist;
	va_start(vlist, lpszFormat);
	StringCchVPrintf(szContent, 1024, lpszFormat, vlist);
	va_end(vlist);

	...
}
로그 기록 처리에 주로 위와 같이 구현해서 사용하는데 쓰다보니 가변인자 처리를 2번에 걸쳐서 쓰게되는 상황이 생겼는데
문제는 여기서 발생했다.
처리 상황을 똑같이 구현해놓기는 뭐하고 다음과 같이 처리해놓으니 문제 증상이 재현된다.
void OuputFunction(LPTSTR _lpszRet, size_t _cchLen, LPCTSTR _lpszFormat, ...)
{
	TCHAR szContent[1024] = {0,};

	if(NULL != _lpszFormat)
	{
		va_list vl;
		va_start(vl, _lpszFormat);
		StringCchVPrintf(szContent, sizeof(szContent) / sizeof(TCHAR), _lpszFormat, vl);
		va_end(vl);
	}

	if(NULL != _lpszRet)
		StringCchCopy(_lpszRet, _cchLen, szContent);
}

void SomeFunction()
{
	TCHAR* pszSampleString = _T("C:\\Users\\Administrator\\Desktop\\style-12px%20Helvetica%2C%20Arial%2C%20Sans-serif;606060_FFFFFF_3399CC_99FF33_006600_666666_FFFFFF;0px%20solid;_blank[1].htm");
	TCHAR szContent[1024] = {0,};

	OuputFunction(szContent, _countof(szContent), _T("[test] %s"), pszSampleString);
	OuputFunction(NULL, 0, szContent);

	_tprintf_s(_T("%s\n"), szContent);
}
증상 재현을 위해 대충 만들었기 때문에 그냥 이러한 상황이 있다 가정한다.
주목해야 할 부분은 바로 pszSampleString의 파일 경로다.
첫 번째, OuputFunction을 거치고나면 szContent에 "[test] C:\Users..." 요로코롬 값이 들어간다.
두 번째, szContent가 다시 OutputFunction의 Format으로 전달되는데 이 때 문자열에 포함된 %로 인하여 문제 발생.
(디버깅으로 하나하나 찾아보니 %s를 두 번째 처리할 때 Access Violation이 발생했다.)

보통 가변인자 처리를 많이 하는 것도 아니고 2번에 걸쳐 처리되게 만들지도 않는다.
좀 편하게 만들자고 여기저기 만들어뒀는데 그것땜에 이런 문제를 발견했다.
생각치도 못했던 파일명으로 인하여 예상하지 못했던 증상을 발견했네. ㅡㅜ
이번 가변인자 처리과정의 문제로 인해 좀 더 생각하고 만들어야겠단 반성을 하게됐다.
끝!

[MFC] Modaless Dailog - Itself destroy

저장소/VC++
Dialog를 띄우다보면 종종 Modaless로 띄워야 할 경우가 많다.
Modaless로 Dialog를 띄우는 방법은 다음과 같다.
CTestDlg*	m_pDlgTest;

void OpenDlg()
{
	m_pDlgTest = new CTestDlg;
	m_pDlgTest->Create(IDD_TEST_DIALOG, this);
	m_pDlgTest->ShowWindow(SW_SHOWNORMAL);
}
객체를 생성했기 때문에 Dialog가 닫히고나면 반드시 지워줘야 메모리 누수를 방지할 수 있다.
그런데... 종종 잊어버린다. ㅡㅡ; 문제다.

이런 문제를 사전에 방지하기 좋은 방법이 요기있넹~
기완형이 알려주셨던, 창훈형이 다시 알려준 좋은 방법 정리!!!
class CTestDlg : public CDialog
{
	DECLARE_DYNAMICCTestDlg 

public:
	CTestDlg(CTestDlg*& pOwnObjPtr);
	virtual ~CTestDlg();

	BOOL	Create(CWnd* pParentWnd = NULL);

Protected:
	...
	virtual void PostNcDestroy();
	afx_msg void OnClose();
	

private:
	CTestDlg*&	m_pOwnObjPtr;


};

CTestDlg::CTestDlg(CTestDlg*& pOwnObjPtr)
	: CDialog(CTestDlg::IDD, NULL)
	, m_pOwnObjPtr(pOwnObjPtr)
{
}

BOOL CTestDlg::Create(CWnd* pParentWnd)
{
	return CDialog::Create(IDD, pParentWnd);
}

void CTestDlg::PostNcDestroy()
{
	m_pOwnObPtr = NULL;
	delete this;
}

void CTestDlg::Close()
{
	DestoryWindow();
}

////////////////////////////////////////////////////////

CTestDlg*	m_pDlgTest;

void OpenDlg()
{
	m_pDlgTest = new CTestDlg(m_pDlgTest);
	m_pDlgTest->Create(this);
	m_pDlgTest->ShowWindow(SW_SHOWNORMAL);
}
수정이 필요한 부분만 정리했다.
중요 부분은 Constructor 수정, Create 함수 Overload, PostNcDestroy, OnClose 함수를 Override 해줘야 한다.
그리고 자신의 객체를 저장할 변수(CTestDlg*&)를 잡아주면 된다.
Dialog가 종료될 때 반드시 OnClose를 거치지는 않는다. 필요에 따라 손을 좀 봐줘야 한다.

주요 내용은 위와 같으며 요로코롬 해두면 Dialog가 닫힐 때 스스로 자신의 객체를 지우기 때문에 편리하다.
하지만 주의해야 할 것은 Modaless에만 해당된다는 것이다.
이렇게 처리한 Dialog는 Modal로 띄우면 스스로 객체를 지우는 과정 때문에 문제가 발생한다. 아마 그랬던 것 같다.
요령껏 쓰도록 합시다.

[MFC] Esc Key 또는 Return Key에 의해 Dialog가 닫힐 때 처리 방법

저장소/VC++
Dialog를 만들고 아무런 처리도 안하면 Esc Key 또는 Return Key를 누를 경우 Dialog가 종료된다.
이런게 편하다면 그냥 쓰면 되겠지만 불편할 때가 오히려 더 많다.
이 문제를 처리하기 위해서는 PreTranslateMessage를 Override해야한다.
아래와 같이 처리해주면 Esc Key나 Return Key를 눌러도 Dialog가 종료되지 않는다.

BOOL CXXXDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class

	if(NULL != pMsg)
	{
		if(WM_KEYDOWN == pMsg->message)
		{
			if( VK_RETURN == pMsg->wParam ||
			    VK_ESCAPE == pMsg->wParam )
			{
				return FALSE;
			}
		}
	}

	return CDialog::PreTranslateMessage(pMsg);
}

Syntax Highlighter Test

저장소/잡다한거
 function foo()
{
	if(counter <= 10)
		return;
	// it works!
}
 


된다~ ㅋㅋㅋㅋ


적용 방법은 다음 글 참고

http://mindgear.tistory.com/164

2011 엔딩 보고싶은 & 해보고 싶은 게임

기타등등
[PS3]
Assassin's Creed 2
Little BIG Planet 2
BIOSHOCK 1, 2
Dead Space 1, 2
Call of Duty : Black Ops
Red Dead Redemption
Red Dead Redemption : Undead Nightmare
Castlevania : Loads of Shadow
Dead Rising 2
Ninja Gaiden :Sigma 2

Portal 2
BATMAN : Arkham City
Ico & Shadow of the Colossus HD collection
The Last Guardian
Uncharted 3
Final Fantasy Versus 13


[XBOX 360]
Halo : Reach
Bayoneta


[PSP]
Prinny 2
용사주제에 건방지다 or 2
용사 30
Persona 3 Portable
God Eater Bust
God of War - Chain of Olympus
God of War - Ghost of Sparta
Diamond and The Sound of a Gun Shot
Patapon 1, 2, 3

'기타등등' 카테고리의 다른 글

2010 해봤던 게임들  (0) 2011.01.19

2010 해봤던 게임들

기타등등
[Play Station 3]
HEAVY RAIN
God of War 3
Final Fantasy 13
Uncharted 1, 2
Gran Turismo 5
Assassin's Creed 2
Lost Planet 2
World Soccer winning eleven 2010
Biohazard 5
BATMAN : Arkham Asylum

[XBOX 360]
Gears of War 1, 2
Fable 3

[PSP]
Tekken 6
Monster Hunter Portable 3rd
Prinny 2
용사주제에 건방지다 or 2
용사 30


'기타등등' 카테고리의 다른 글

2011 엔딩 보고싶은 & 해보고 싶은 게임  (0) 2011.01.19

[MFC] OnCancel(), OnClose(), OnDestroy(), OnOK() 그리고 Dialog 소멸자

저장소/VC++

예전 스프링노트에 정리했던 내용



Dialog가 종료되는 상황

  1. IDOK 버튼을 눌렀을 때
    • OnOK() 호출 뒤 OnDestroy() 호출됨
  2. IDCANCEL 버튼을 눌렀을 때
    • OnCancel() 호출 뒤 OnDestroy() 호출됨
  3. Dialog의 우측 상단 종료 버튼(x)를 눌렀을 때
    • OnClose() 호출 뒤 OnCancel() 마지막으로 OnDestroy() 호출됨
  4. Esc 버튼을 눌러 종료할 때 - 결과만 놓고 봤을 때 'Esc = IDCANCEL' 이 된다는 말인가?? 아무튼 결과는 동일
    • OnCancel() 호출 뒤 OnDestroy() 호출됨
  5. Alt + F4 로 종료할 때
    • OnClose() 호출 뒤 OnCancel() 마지막으로 OnDestroy() 호출됨