In Win32 APP, how to obtain the full path file name from it's handle

Hello everybody, I hooked some file system APIs, such as WriteFile, ReadFile, etc. I replaced WriteFile API with MyWriteFile, and in MyWriteFile function, I want to get the file name via the inputting file handle, I searched from google and find the code like below from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/obtaining_a_file_name_from_a_file_handle.asp

BOOL GetFilenameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR* pszFilename[MAX_PATH+1];
uint uMaxLenDest = 0;

// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);

// Create a file mapping object.
HANDLE hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
dwFileSizeLo,
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)) {

// Attempt to translate the path with device name into drive
// letters.
TCHAR szTemp[512];
*szTemp = NULL;

if (GetLogicalDriveStrings(MAX_ARRAY_ITEMS(szTemp)-1,
szTemp)) {
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;

do {
// Copy the drive letter into the template string,
// removing the backslash.
*szDrive = *p;

// Look up each device name.
if (QueryDosDevice(szDrive, szName,
MAX_ARRAY_ITEMS(szName))) {
uint uNameLen = _tcslen(szName);

// If greater than file name length, it’s not a match.
if (uNameLen < uMaxLenDest) {
bFound = _tcsnicmp(pszFilename, szName, uNameLen)
== 0;

if (bFound) {
// Reconstruct pszFilename using szTemp as scratch,
// and replace device path with our DOS path.
TCHAR szTempFile[MAX_PATH];
_stprintf(szTempFile,
TEXT(“%s%s”),
szDrive,
pszFilename+uNameLen);
stringCopy(pszFilename, szTempFile, uMaxLenDest);
}
}
}

// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // at the end of the string
}
}
bSuccess = TRUE;
if (!UnmapViewOfFile(pMem)) assert(0);
}

if (!CloseHandle(hFileMap)) assert(0);
}
return(bSuccess);
}

I modified some errors and put the code into my project, it do the work when I try to debug it, however, because MyWriteFile is in DLL, I must inject my dll into the target process to take effect my WriteFile API. when I inject my dll into some specified process, the CreateFileMapping failed, GetLastError() returned 161, I looked it up in MSDN, and find that it indicates that "The specified path is invalid. ", I dont’ understand what happened, so who can help me ?

Thanks a lot.

Can anybody tell me why ? how can I resolve it ?

Tom_lyd

GetModuleFileName()
GetModuleFileNameEx()

Regards,
Yan.

-----Original Message-----
From: lists.osr.com [mailto:Tom_lyd@163.com]
Sent: Tuesday, March 30, 2004 7:42 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] In Win32 APP, how to obtain the full path file name
from it’s handle

Can anybody tell me why ? how can I resolve it ?

Tom_lyd


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@smlink.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

GetModuleFileName(Ex) obtain the module’s file name, I want to get the file name, not module name.
for example, some one called :
HANDLE hFile = ::CreateFile( “C:\temp\test.txt”, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

and then he call WriteFile to write some data to test.txt file, because I hooked the WriteFile API, so MyWriteFile will be called instead of the origional WriteFile API, and in myWirteFile API, I know the handle to the file into which the caller want to write some data, but I donn’t know the file name, so I want to get the specified file fullpath name from the handle, but I haven’t found a good way, what should I do ?

GetModuleFileName(Ex) obtain the module’s file name, I want to get the file
name, not module name.
for example, some one called :
HANDLE hFile = ::CreateFile( “C:\temp\test.txt”, GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

and then he call WriteFile to write some data to test.txt file, because I
hooked the WriteFile API, so MyWriteFile will be called instead of the
origional WriteFile API, and in myWirteFile API, I know the handle to the
file into which the caller want to write some data, but I donn’t know the
file name, so I want to get the specified file fullpath name from the
handle, but I haven’t found a good way, what should I do ?

First of all I want to point out that the standard way of intercepting IO is
file system Filter driver and not hooking API. There are standard ways to
get the file name in a filter driver.
As to your original question I don’t know any Win32 API to achieve this. You
may use native API NtQueryInformationFile with FileInformationClass ==
FileNameInformation or you may hook CreateFile as well as WriteFile and
maintain a lookup table that allows to resolve file name from a handle.

Alexei.

“Tom_lyd” <tom_lyd> wrote in message news:xxxxx@ntdev…
> GetModuleFileName(Ex) obtain the module’s file name, I want to get the
file name, not module name.
> for example, some one called :
> HANDLE hFile = ::CreateFile( “C:\temp\test.txt”, GENERIC_READ |
GENERIC_WRITE,
> FILE_SHARE_READ | FILE_SHARE_WRITE,
> NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
>
> and then he call WriteFile to write some data to test.txt file, because I
hooked the WriteFile API, so MyWriteFile will be called instead of the
origional WriteFile API, and in myWirteFile API, I know the handle to the
file into which the caller want to write some data, but I donn’t know the
file name, so I want to get the specified file fullpath name from the
handle, but I haven’t found a good way, what should I do ?
>
>
></tom_lyd>

Thanks for your answer at first. Just as you say, in fact, I have already
hooked CreateFileA/W and WriteFile as well, but the target process called
CreateFileA/W before I succeeded injecting my hook dll into it’s address
space, so my createfile api can not be called when the target process call
createfile too early.

In the other hand, I know the best way is to implement a fils system filter
driver, but my project must run on both 9x and NT/2k, I don’t want to write
a Vxd as well a WDM driver, by the other way, it’s something difficult to
debug an IFS driver, so I must resolve my problem.

Thank you.

Alexei Jelvis:
I have tried the way you told me like this:

typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;

typedef ULONG ( NTAPI * PFNNTQUERYINFOFILE)( HANDLE, PIO_STATUS_BLOCK,
PVOID, ULONG, FILE_INFORMATION_CLASS );

IO_STATUS_BLOCK io;
FILE_NAME_INFORMATION * pFni = (PFILE_NAME_INFORMATION)new char[MAX_PATH];
HMODULE hNtDll = ::LoadLibrary( “NTDLL.dll” );
if( hNtDll )
{
PFNNTQUERYINFOFILE lpfnQueryInfoFile =
(PFNNTQUERYINFOFILE)::GetProcAddress( hNtDll, “NtQueryInformationFile” );

if( lpfnQueryInfoFile )
(* lpfnQueryInfoFile)( hFile, &io, pFni, 250, FileNameInformation );
}

In this way, I succeeded in calling NtQueryInformationFile, however, the
FilName field in FILE_NAME_INFORMATION, returned by NtQueryInformationFile,
contain only string exclude t he root directory. In fact, I create a file
named “C:\temp\temp\test.txt”, but the returned content is
“\temp\temp\test.txt”, how can I get the logical driver as well ?

Thanks a lot.

Dare I ask what it is that you’re trying accomplish here? There might be
a better solution…

lists.osr.com wrote:

Thanks for your answer at first. Just as you say, in fact, I have already
hooked CreateFileA/W and WriteFile as well, but the target process called
CreateFileA/W before I succeeded injecting my hook dll into it’s address
space, so my createfile api can not be called when the target process call
createfile too early.

In the other hand, I know the best way is to implement a fils system filter
driver, but my project must run on both 9x and NT/2k, I don’t want to write
a Vxd as well a WDM driver, by the other way, it’s something difficult to
debug an IFS driver, so I must resolve my problem.

Thank you.


…/ray..

It’s obvisiously in my title, I want to get full path filename from file
hane in win32 application, not kernel mode.
My program is a hook project, I hooked file associated APIs, such
CcreateFileA, CreateFileW, WriteFile and so on, I create a look up table, in
which the file name and it’s opened handle were stored, however, the targer
process maybe has already called CreateFileA/W to opened the specified file
before my hook process succeeded in injecting into it’s address space, so
MyCreateFileA/W can not be called, and I can not create the map relationship
between file name with the handle in lookup table. Later on, in MyWriteFile,
the input parameter tells me only file handle, in order to check whether the
file handle is associated with the specified file, I must try to get it’s
full path name, I searched from google, and found the code below:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base
/obtaining_a_file_name_from_a_file_handle.asp
BOOL GetFilenameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR* pszFilename[MAX_PATH+1];
uint uMaxLenDest = 0;

// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);

// Create a file mapping object.
HANDLE hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
dwFileSizeLo,
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)) {

// Attempt to translate the path with device name into drive
// letters.
TCHAR szTemp[512];
*szTemp = NULL;

if (GetLogicalDriveStrings(MAX_ARRAY_ITEMS(szTemp)-1,
szTemp)) {
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;

do {
// Copy the drive letter into the template string,
// removing the backslash.
*szDrive = *p;

// Look up each device name.
if (QueryDosDevice(szDrive, szName,
MAX_ARRAY_ITEMS(szName))) {
uint uNameLen = _tcslen(szName);

// If greater than file name length, it’s not a match.
if (uNameLen < uMaxLenDest) {
bFound = _tcsnicmp(pszFilename, szName, uNameLen)
== 0;

if (bFound) {
// Reconstruct pszFilename using szTemp as scratch,
// and replace device path with our DOS path.
TCHAR szTempFile[MAX_PATH];
_stprintf(szTempFile,
TEXT(“%s%s”),
szDrive,
pszFilename+uNameLen);
stringCopy(pszFilename, szTempFile, uMaxLenDest);
}
}
}

// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // at the end of the string
}
}
bSuccess = TRUE;
if (!UnmapViewOfFile(pMem)) assert(0);
}

if (!CloseHandle(hFileMap)) assert(0);
}
return(bSuccess);
}

I modified some errors and put it in my project, however, CreaetFileMapping
failed, GetLastError() returned 161. I looked the error code up in MSDN, and
find it indicates that “The specified path is invalid”. I don’t know why,
but I must solve my problem, the time is limitted, so, if anybody can help
me , I will thank him/her very much.

Yes, this function returns exactly the same information that file system
driver provides - path relative to the volume. You need to figure out the
volume where the file resides using different API - I can suggest
GetFileInformationByHandle. The function returns volume serial number and if
you build a lookup table to resolve from serial number to the drive letter
you can get what you need.

Alexei.

lists.osr.com” <tom_lyd> wrote in message news:xxxxx@ntdev…
> Alexei Jelvis:
> I have tried the way you told me like this:
>
> typedef struct _FILE_NAME_INFORMATION {
> ULONG FileNameLength;
> WCHAR FileName[1];
> } FILE_NAME_INFORMATION, PFILE_NAME_INFORMATION;
>
> typedef ULONG ( NTAPI * PFNNTQUERYINFOFILE)( HANDLE, PIO_STATUS_BLOCK,
> PVOID, ULONG, FILE_INFORMATION_CLASS );
>
> IO_STATUS_BLOCK io;
> FILE_NAME_INFORMATION * pFni = (PFILE_NAME_INFORMATION)new
char[MAX_PATH];
> HMODULE hNtDll = ::LoadLibrary( “NTDLL.dll” );
> if( hNtDll )
> {
> PFNNTQUERYINFOFILE lpfnQueryInfoFile =
> (PFNNTQUERYINFOFILE)::GetProcAddress( hNtDll, “NtQueryInformationFile” );
>
> if( lpfnQueryInfoFile )
> (
lpfnQueryInfoFile)( hFile, &io, pFni, 250, FileNameInformation );
> }
>
> In this way, I succeeded in calling NtQueryInformationFile, however, the
> FilName field in FILE_NAME_INFORMATION, returned by
NtQueryInformationFile,
> contain only string exclude t he root directory. In fact, I create a file
> named “C:\temp\temp\test.txt”, but the returned content is
> “\temp\temp\test.txt”, how can I get the logical driver as well ?
>
> Thanks a lot.
>
>
></tom_lyd>

No, I mean *why* are you trying to do this? What are you doing with this
information?

lists.osr.com wrote:

It’s obvisiously in my title, I want to get full path filename from file
hane in win32 application, not kernel mode.
My program is a hook project, I hooked file associated APIs, such
CcreateFileA, CreateFileW, WriteFile and so on, I create a look up table, in
which the file name and it’s opened handle were stored, however, the targer
process maybe has already called CreateFileA/W to opened the specified file
before my hook process succeeded in injecting into it’s address space, so
MyCreateFileA/W can not be called, and I can not create the map relationship
between file name with the handle in lookup table. Later on, in MyWriteFile,
the input parameter tells me only file handle, in order to check whether the
file handle is associated with the specified file, I must try to get it’s
full path name, I searched from google, and found the code below:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base
/obtaining_a_file_name_from_a_file_handle.asp
BOOL GetFilenameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR* pszFilename[MAX_PATH+1];
uint uMaxLenDest = 0;

// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);

// Create a file mapping object.
HANDLE hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
dwFileSizeLo,
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)) {

// Attempt to translate the path with device name into drive
// letters.
TCHAR szTemp[512];
*szTemp = NULL;

if (GetLogicalDriveStrings(MAX_ARRAY_ITEMS(szTemp)-1,
szTemp)) {
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;

do {
// Copy the drive letter into the template string,
// removing the backslash.
*szDrive = *p;

// Look up each device name.
if (QueryDosDevice(szDrive, szName,
MAX_ARRAY_ITEMS(szName))) {
uint uNameLen = _tcslen(szName);

// If greater than file name length, it’s not a match.
if (uNameLen < uMaxLenDest) {
bFound = _tcsnicmp(pszFilename, szName, uNameLen)
== 0;

if (bFound) {
// Reconstruct pszFilename using szTemp as scratch,
// and replace device path with our DOS path.
TCHAR szTempFile[MAX_PATH];
_stprintf(szTempFile,
TEXT(“%s%s”),
szDrive,
pszFilename+uNameLen);
stringCopy(pszFilename, szTempFile, uMaxLenDest);
}
}
}

// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // at the end of the string
}
}
bSuccess = TRUE;
if (!UnmapViewOfFile(pMem)) assert(0);
}

if (!CloseHandle(hFileMap)) assert(0);
}
return(bSuccess);
}

I modified some errors and put it in my project, however, CreaetFileMapping
failed, GetLastError() returned 161. I looked the error code up in MSDN, and
find it indicates that “The specified path is invalid”. I don’t know why,
but I must solve my problem, the time is limitted, so, if anybody can help
me , I will thank him/her very much.


…/ray..

One other thing… you are aware that file handles are only valid in the
context of the process that created them, right? It’s kind of hard to
tell where you’re trying to do the conversion…

lists.osr.com wrote:

It’s obvisiously in my title, I want to get full path filename from file
hane in win32 application, not kernel mode.
My program is a hook project, I hooked file associated APIs, such
CcreateFileA, CreateFileW, WriteFile and so on, I create a look up table, in
which the file name and it’s opened handle were stored, however, the targer
process maybe has already called CreateFileA/W to opened the specified file
before my hook process succeeded in injecting into it’s address space, so
MyCreateFileA/W can not be called, and I can not create the map relationship
between file name with the handle in lookup table. Later on, in MyWriteFile,
the input parameter tells me only file handle, in order to check whether the
file handle is associated with the specified file, I must try to get it’s
full path name, I searched from google, and found the code below:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base
/obtaining_a_file_name_from_a_file_handle.asp
BOOL GetFilenameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR* pszFilename[MAX_PATH+1];
uint uMaxLenDest = 0;

// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);

// Create a file mapping object.
HANDLE hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
dwFileSizeLo,
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)) {

// Attempt to translate the path with device name into drive
// letters.
TCHAR szTemp[512];
*szTemp = NULL;

if (GetLogicalDriveStrings(MAX_ARRAY_ITEMS(szTemp)-1,
szTemp)) {
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;

do {
// Copy the drive letter into the template string,
// removing the backslash.
*szDrive = *p;

// Look up each device name.
if (QueryDosDevice(szDrive, szName,
MAX_ARRAY_ITEMS(szName))) {
uint uNameLen = _tcslen(szName);

// If greater than file name length, it’s not a match.
if (uNameLen < uMaxLenDest) {
bFound = _tcsnicmp(pszFilename, szName, uNameLen)
== 0;

if (bFound) {
// Reconstruct pszFilename using szTemp as scratch,
// and replace device path with our DOS path.
TCHAR szTempFile[MAX_PATH];
_stprintf(szTempFile,
TEXT(“%s%s”),
szDrive,
pszFilename+uNameLen);
stringCopy(pszFilename, szTempFile, uMaxLenDest);
}
}
}

// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // at the end of the string
}
}
bSuccess = TRUE;
if (!UnmapViewOfFile(pMem)) assert(0);
}

if (!CloseHandle(hFileMap)) assert(0);
}
return(bSuccess);
}

I modified some errors and put it in my project, however, CreaetFileMapping
failed, GetLastError() returned 161. I looked the error code up in MSDN, and
find it indicates that “The specified path is invalid”. I don’t know why,
but I must solve my problem, the time is limitted, so, if anybody can help
me , I will thank him/her very much.


…/ray..

No need to worry about this, because my project is a dll project in which my file apis are stayed. I have another server (.exe) that inject my dll into the target process’s address space, so all APIs exported from my dll are in the same address space as the target process.

No need to worry about this, because my project is a dll project in which my
file apis are stayed. I have another server (.exe) that inject my dll into
the target process’s address space, so all APIs exported from my dll are in
the same address space as the target process.

Thank you very much, I get the volume serial number successfully by invoking
GetFileInformationByHandle, but I don’t know how to map the serial number to
logical driver set, could you please help me ?

Thank you very much, I have succeeded in resolving my problem , thank you a
lot !
I implemented it by a class like below:

.h
#pragma once

//
// Here below typedefs are copied from NTDDK.
typedef LONG NTSTATUS;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};

ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef enum _FILE_INFORMATION_CLASS {
// end_wdm
FileDirectoryInformation = 1,
FileFullDirectoryInformation, // 2
FileBothDirectoryInformation, // 3
FileBasicInformation, // 4 wdm
FileStandardInformation, // 5 wdm
FileInternalInformation, // 6
FileEaInformation, // 7
FileAccessInformation, // 8
FileNameInformation, // 9
FileRenameInformation, // 10
FileLinkInformation, // 11
FileNamesInformation, // 12
FileDispositionInformation, // 13
FilePositionInformation, // 14 wdm
FileFullEaInformation, // 15
FileModeInformation, // 16
FileAlignmentInformation, // 17
FileAllInformation, // 18
FileAllocationInformation, // 19
FileEndOfFileInformation, // 20 wdm
FileAlternateNameInformation, // 21
FileStreamInformation, // 22
FilePipeInformation, // 23
FilePipeLocalInformation, // 24
FilePipeRemoteInformation, // 25
FileMailslotQueryInformation, // 26
FileMailslotSetInformation, // 27
FileCompressionInformation, // 28
FileObjectIdInformation, // 29
FileCompletionInformation, // 30
FileMoveClusterInformation, // 31
FileQuotaInformation, // 32
FileReparsePointInformation, // 33
FileNetworkOpenInformation, // 34
FileAttributeTagInformation, // 35
FileTrackingInformation, // 36
FileMaximumInformation
// begin_wdm
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;

typedef NTSTATUS (NTAPI * PFNNTQUERYINFOFILE)( HANDLE, PIO_STATUS_BLOCK,
PVOID, ULONG, FILE_INFORMATION_CLASS );
class CObtainFileInfo
{
public:
CObtainFileInfo(void);
~CObtainFileInfo(void);

public:
BOOL GetFileNameByHandle( HANDLE hFile, LPSTR lpszNameBuf, DWORD dwSize );

private:
BOOL GetFileVolByHandle( HANDLE hFile, LPSTR lpszVol, DWORD dwSize, bool
bEgnoreFloppy=true );

private:
HMODULE m_hNtDll;
PFNNTQUERYINFOFILE m_lpfnQueryInfoFile;
};

.cpp
#include “StdAfx.h”
#include “.\obtainfileinfo.h”
#include <assert.h>

CObtainFileInfo::CObtainFileInfo(void)
: m_hNtDll( NULL )
, m_lpfnQueryInfoFile( NULL )
{
m_hNtDll = ::LoadLibrary( “NTDLL.dll” );
if( m_hNtDll )
{
m_lpfnQueryInfoFile = (PFNNTQUERYINFOFILE)::GetProcAddress( m_hNtDll,
“NtQueryInformationFile” );
if( !m_lpfnQueryInfoFile)
OutputDebugString( “Get NtQueryInformationFile API pointer failed\n” );
}
else
{
OutputDebugString( “Load NTDLL.dll failed\n” );
}
}

CObtainFileInfo::~CObtainFileInfo(void)
{
if( m_hNtDll )
::FreeLibrary( m_hNtDll );
}

#define FILEINFO_BUF_LEN(len) len-(1/for terminator/+2/for prefix
volume
/)sizeof(WCHAR)
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
BOOL CObtainFileInfo::GetFileNameByHandle( HANDLE hFile, LPSTR lpszNameBuf,
DWORD dwSize )
{
if( hFile == INVALID_HANDLE_VALUE || !lpszNameBuf || dwSize==0 )
return FALSE;

if( !m_lpfnQueryInfoFile )
return FALSE;

IO_STATUS_BLOCK io;
FILE_NAME_INFORMATION * pFni = (PFILE_NAME_INFORMATION)new
TCHAR[MAX_PATH
2];
if( !pFni )
return FALSE;

memset( pFni, 0, 2MAX_PATH );

__try
{
NTSTATUS status = (m_lpfnQueryInfoFile)( hFile, &io, pFni,
FILEINFO_BUF_LEN(2
MAX_PATH), FileNameInformation );
if( !NT_SUCCESS(status) )
{
//delete[] pFni;
OutputDebugString( “NtQueryInformationFile failed\n” );
return FALSE;
}

//
// WCHAR to ANSI string
char ansi[MAX_PATH
2];
memset( ansi, 0, sizeof(ansi) );
BOOL bDef;
int bytes = WideCharToMultiByte( CP_ACP, 0, pFni->FileName, -1, ansi,
sizeof(ansi), NULL, &bDef );//include the terminator.
assert( bytes < sizeof(ansi) );
if( dwSize < strlen(ansi)+2 )
{
OutputDebugString( “Insufficient memory for getting file name from
hanel.\n”);
return FALSE;
}

TCHAR vol[3];
memset( vol, 0, sizeof(vol) );
if( !GetFileVolByHandle(hFile, vol, sizeof(vol) ) )
return FALSE;

lpszNameBuf = ‘\0’;
_tcscpy( lpszNameBuf, vol );
if( ansi[0] != ‘\’ )
_tcscat( lpszNameBuf, “\” );
_tcscat( lpszNameBuf, ansi );
return TRUE;
}
__finally
{
delete[] pFni;
}

return FALSE;
}

BOOL CObtainFileInfo::GetFileVolByHandle( HANDLE hFile, LPSTR lpszVol, DWORD
dwSize,
bool bEgnoreFloppy/
=true /)
{
ASSERT( hFile != INVALID_HANDLE_VALUE && dwSize >= 3 );

HANDLE hVol = INVALID_HANDLE_VALUE;
__try
{
::SetErrorMode( SEM_FAILCRITICALERRORS );

//
// Get file volume
BY_HANDLE_FILE_INFORMATION bhfi;
BOOL bOk = GetFileInformationByHandle( hFile, &bhfi );
if( !bOk )
{
//delete[] pFni;
OutputDebugString( “GetFileInformationByHandle failed\n” );
return FALSE;
}

TCHAR szDriveSet[MAX_PATH
2];
memset( szDriveSet, 0, sizeof(szDriveSet) );
::GetLogicalDriveStrings( sizeof(szDriveSet)-1, szDriveSet );
TCHAR szDrive[4] = _T(" :\"); //such as “C:”
TCHAR * p = szDriveSet;
do
{
szDrive[0] = *p; //copy the drive set.
if( bEgnoreFloppy && (szDrive[0] == ‘A’ || szDrive[0] == ‘a’) )
{
while( *p++ );
continue;
}

DWORD dwVolSn = 0;
::GetVolumeInformation( szDrive, NULL, 0, &dwVolSn, NULL, NULL, NULL,
0 );
if( dwVolSn == bhfi.dwVolumeSerialNumber )
{
_tcsncpy( lpszVol, szDrive, 2 );
return TRUE;
}

//
// Extract the next logical drive set.
while( *p++ );

} while( *p );
}
__finally
{
::SetErrorMode( 0 ); //set error mode to system default.
}
return FALSE;
}</assert.h>