根据句柄获得文件名
发布于 2021-09-09
我们可以通过GetFinalPathNameByHandle
这个 api 直接从一个句柄中获得文件的路径。使用代码如下:
WCHAR path_name[MAX_PATH] = {0};
BOOL result =
GetFinalPathNameByHandle(test_file_handle, path_name, MAX_PATH,
FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
if (result) {
std::cout << "FILE_NAME_NORMALIZED | VOLUME_NAME_DOS" << std::endl;
std::wcout << path_name << std::endl << std::endl;
}
result = GetFinalPathNameByHandle(test_file_handle, path_name, MAX_PATH,
FILE_NAME_NORMALIZED | VOLUME_NAME_NT);
if (result) {
std::cout << "FILE_NAME_NORMALIZED | VOLUME_NAME_NT" << std::endl;
std::wcout << path_name << std::endl << std::endl;
}
result = GetFinalPathNameByHandle(test_file_handle, path_name, MAX_PATH,
FILE_NAME_NORMALIZED | VOLUME_NAME_NONE);
if (result) {
std::cout << "FILE_NAME_NORMALIZED | VOLUME_NAME_NONE" << std::endl;
std::wcout << path_name << std::endl << std::endl;
}
输出结果为:
FILE_NAME_NORMALIZED | VOLUME_NAME_DOS
\\?\C:\Users\xxx\source\repos\ConsoleApplication10\ConsoleApplication10\test.txt
FILE_NAME_NORMALIZED | VOLUME_NAME_NT
\Device\HarddiskVolume5\Users\xxx\source\repos\ConsoleApplication10\ConsoleApplication10\test.txt
FILE_NAME_NORMALIZED | VOLUME_NAME_NONE
\Users\xxx\source\repos\ConsoleApplication10\ConsoleApplication10\test.txt
获得的路径前面添加了一些前缀,这跟我们正常的路径还是有一些差别。
但是这个 api 最低只支持vista系统。如果要在 XP 等低版本 Windows 系统上获得文件名,可以使用其他办法。
BOOL GetFileNameFromHandle(HANDLE hFile) {
BOOL bSuccess = FALSE;
TCHAR pszFilename[MAX_PATH + 1] = {0};
HANDLE hFileMap;
// Create a file mapping object.
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 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)) {
size_t uNameLen = wcslen(szName);
if (uNameLen < MAX_PATH) {
bFound = _wcsnicmp(pszFilename, szName, uNameLen) == 0 &&
*(pszFilename + uNameLen) == L'\\';
if (bFound) {
// Reconstruct pszFilename using szTempFile
// Replace device path with DOS path
TCHAR szTempFile[MAX_PATH];
StringCchPrintf(szTempFile, MAX_PATH, TEXT("%s%s"), szDrive,
pszFilename + uNameLen);
StringCchCopyN(pszFilename, MAX_PATH + 1, szTempFile,
wcslen(szTempFile));
}
}
}
// Go to the next NULL character.
while (*p++)
;
} while (!bFound && *p); // end of string
}
}
bSuccess = TRUE;
UnmapViewOfFile(pMem);
}
CloseHandle(hFileMap);
}
std::wcout << L"File name is " << pszFilename << std::endl;
return (bSuccess);
}
输出结果:
C:\Users\xxx\source\repos\ConsoleApplication10\ConsoleApplication10\test.txt
明显繁琐很多。
如果是dll或者模块的句柄,使用GetModuleFileName
很简单
参考
Obtaining a File Name From a File Handle GetFinalPathNameByHandle