Reputation: 21
I'm trying to retrieve a file name from a given file handle.
I've seen that GetFileInformationByHandle could be useful, but the structure it returns does not contain any file name information (http://msdn.microsoft.com/en-us/library/aa363788%28v=VS.85%29.aspx).
How can I do this?
EDIT:
I've tried installing the Windows FileID APIs to get GetFileInformationByHandleEx working on Windows XP. But when including fileextd.h I get the following errors
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(16) : error C2011: '_FILE_INFO_BY_HANDLE_CLASS' : 'enum' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13900) : see declaration of '_FILE_INFO_BY_HANDLE_CLASS'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(32) : error C2011: '_FILE_BASIC_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13917) : see declaration of '_FILE_BASIC_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(40) : error C2011: '_FILE_STANDARD_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13925) : see declaration of '_FILE_STANDARD_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(48) : error C2011: '_FILE_NAME_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13933) : see declaration of '_FILE_NAME_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(53) : error C2011: '_FILE_RENAME_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13938) : see declaration of '_FILE_RENAME_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(60) : error C2011: '_FILE_ALLOCATION_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13945) : see declaration of '_FILE_ALLOCATION_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(64) : error C2011: '_FILE_END_OF_FILE_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13949) : see declaration of '_FILE_END_OF_FILE_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(68) : error C2011: '_FILE_STREAM_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13953) : see declaration of '_FILE_STREAM_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(76) : error C2011: '_FILE_COMPRESSION_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13961) : see declaration of '_FILE_COMPRESSION_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(85) : error C2011: '_FILE_ATTRIBUTE_TAG_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13970) : see declaration of '_FILE_ATTRIBUTE_TAG_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(90) : error C2011: '_FILE_DISPOSITION_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13975) : see declaration of '_FILE_DISPOSITION_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(94) : error C2011: '_FILE_ID_BOTH_DIR_INFO' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(13979) : see declaration of '_FILE_ID_BOTH_DIR_INFO'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(130) : error C2011: '_FILE_ID_TYPE' : 'enum' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(14026) : see declaration of '_FILE_ID_TYPE'
c:\programmi\microsoft visual studio 9.0\vc\include\fileextd.h(135) : error C2011: 'FILE_ID_DESCRIPTOR' : 'struct' type redefinition
c:\programmi\microsoft sdks\windows\v6.1\include\winbase.h(14032) : see declaration of 'FILE_ID_DESCRIPTOR'
c:\documents and settings\lab\documenti\visual studio 2008\projects\sandbox\sandbox\funcs_files.cpp(26) : error C2079: 'lpFileInformation' uses undefined struct '_FILE_NAME_INFO'
c:\documents and settings\lab\documenti\visual studio 2008\projects\sandbox\sandbox\funcs_files.cpp(35) : error C2228: left of '.FileName' must have class/struct/union
type is 'int'
From the following code:
#include <windows.h>
#include <fileextd.h>
LPVOID GetFileNameFromHandle(HANDLE hFile) {
FILE_NAME_INFO lpFileInformation;
BOOL bWorked;
bWorked = GetFileInformationByHandleEx(
hFile,
FileNameInfo,
&lpFileInformation,
sizeof(FILE_NAME_INFO));
return lpFileInformation.FileName;
}
Upvotes: 2
Views: 6028
Reputation: 31
I like the approach by Sirotnikov. However, we are using UTF-8 exclusively (calling setlocale(LC_CTYPE, ".utf8");
at the beginning of main
). This requires the use of GetFinalPathNameByHandleA
instead, where the initial call does not include the space for the terminating null character. The string then needs to be allocated one larger. Here is the call I do:
DWORD size = GetFinalPathNameByHandleA((HANDLE)_get_osfhandle(_fileno(f)), nullptr, 0, FILE_NAME_OPENED);
if (size > 0)
{
std::string fname(size+1, '\0');
size = GetFinalPathNameByHandleA((HANDLE)_get_osfhandle(_fileno(f)), &fname.front(), size+1, FILE_NAME_OPENED);
return fname;
}
There are some additional tricks as I needed to get the file name from a plain C FILE*
pointer. (See https://stackoverflow.com/a/6064796/6954968 for information.) This needs the header io.h
besides Windows.h
because of _get_osfhandl()
.
Upvotes: 0
Reputation: 81
BOOL GetFileNameFromHandle(HANDLE hFile, TCHAR *pszFileName, const unsigned int uiMaxLen)
{
pszFileName[0]=0;
std::unique_ptr<BYTE[]> ptrcFni(new BYTE[_MAX_PATH * sizeof(TCHAR) + sizeof(FILE_NAME_INFO)]);
FILE_NAME_INFO *pFni = reinterpret_cast<FILE_NAME_INFO *>(ptrcFni.get());
BOOL b = GetFileInformationByHandleEx(hFile,
FileNameInfo,
pFni,
sizeof(FILE_NAME_INFO) + (_MAX_PATH * sizeof(TCHAR)) );
if ( b )
{
#ifdef _UNICODE
wcsncpy_s(pszFileName,
min(uiMaxLen, (pFni->FileNameLength / sizeof(pFni->FileName[0])) + 1 ),
pFni->FileName,
_TRUNCATE);
#else
strncpy_s(pszFileName,
min(uiMaxLen, (pFni->FileNameLength / sizeof(pFni->FileName[0])) + 1),
CW2A(pFni->FileName),
_TRUNCATE);
#endif
}
return b;
}
Upvotes: 3
Reputation: 459
For Vista and later take a look at GetFinalPathNameByHandle (like mehrdad wrote)
It is more convenient IMO and allows more customization than GetFileInformationByHandleEx, and it removes the hassle of allocating a custom size FILE_NAME_INFO
struct.
Example:
DWORD size = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
if (size == 0) return L"(NOT FOUND)";
std::wstring fname(size, L'0');
size = GetFinalPathNameByHandleW(handle, &fname.front(), size, VOLUME_NAME_DOS);
Notice, it will prepend \\?\
to the returning name.
(I used C++ std::wstring to avoid C boilerplate for memory handling. Use malloc for your needs).
Upvotes: 2
Reputation: 210765
There is a correct way to do this that works on Windows XP, on both files and directories; I've explained it in another post here.
Upvotes: 1
Reputation: 8463
Where did you get the file handle from? If you're sure it's not a named pipe handle, you can use NtQueryObject to query the file name.
Upvotes: 0
Reputation: 3505
Hi if you need file name from handle you can read this ms article http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx or use this GetFileInformationByHandleEx
Upvotes: 2