파일 관련 함수를 만들 때 인수로 전달된 핸들로 처리를 하다가 다시 파일 명을 알아내서 처리해야 할 경우가 있습니다.
이럴 경우 다시 인수로 파일 이름을 전달 받아야 하는 난감한 상황에 놓이게 된다.
또한 파일 관련 API Hooking을 할 때도 파일 핸들 만으로 파일 명을 알아내서 처리 할 수 있는 기능이 필요하다.
MSDN을 뒤져보니 좋은 코드가 있어서 수정 해보았습이다.
원리는 주어진 파일 핸들로 파일 맵을 만들어 파일 맵으로 파일 명을 알아내는 것인데요.
간단할 것 같은 소스 코드가 무척 복잡한데요.
GetMappedFileName () 함수를 통해 전달되는 패스 명이 드라이버 절대 경로라서 황당하다는 ^^;
그래서 도스의 드라이버 경로를 구하느라고 코드가 복잡합니다.
드라이버 경로명과 도스의 경로명을 변환하는 부분도 유용하게 쓰일 것 같습니다.
#include <Psapi.h>
#pragma comment(lib, "psapi.lib")
#define BUFSIZE 512
BOOL GetFileNameFromHandle(HANDLE hFile, TCHAR *pszFilename)
{
BOOL bSuccess = FALSE;
HANDLE hFileMap;
// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
if( dwFileSizeLo == 0 && dwFileSizeHi == 0 )
{
//OutputDebugString(L"Cannot map a file with a length of zero.\n");
return FALSE;
}
// Create a file mapping object.
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
if (hFileMap)
{
// Create a file mapping to get the file name.
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (pMem)
{
if (GetMappedFileName (GetCurrentProcess(), pMem, pszFilename, MAX_PATH))
{
// Translate path with device name to drive letters.
TCHAR szTemp[BUFSIZE];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(BUFSIZE-1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
// Look up each device name
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
UINT uNameLen = _tcslen(szName);
if (uNameLen < MAX_PATH)
{
bFound = _tcsnicmp(pszFilename, szName, uNameLen) == 0;
if (bFound)
{
// Reconstruct pszFilename using szTempFile
// Replace device path with DOS path
TCHAR szTempFile[MAX_PATH];
swprintf(szTempFile, L"%s%s", szDrive, pszFilename+uNameLen);
_tcscpy(pszFilename, szTempFile);
}
}
}
// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // end of string
}
}
bSuccess = TRUE;
UnmapViewOfFile(pMem);
}
CloseHandle(hFileMap);
}
return(bSuccess);
}
사용 예제)
void GetFileName()
{
DWORD dwWritten;
HANDLE hFile;
hFile=CreateFile(L"C:\\test.doc",GENERIC_READ,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
TCHAR szMapFileName[MAX_PATH+1] = {L"\0"};
GetFileNameFromHandle(hFile, szMapFileName);
::MessageBox(g_hWnd, szMapFileName, L"TEST", MB_OK);
}
CloseHandle(hFile);
}