【经验】C++|利用 Windows API,通过文件句柄获取文件路径的两种方式

方法一

主要参考博客:根据文件句柄获得文件名(这篇超级清晰,就是有一点点小问题)
通过文件句柄获得文件路径(这篇不是很好用,但是思路大体是一致的)

主要思路:

  1. 根据HANDLE 创建映射文件,调用GetMappedFileName获得一个DosDevice路径。
  2. 然后GetLogicaDriveStrings获得盘符字串,依次读取盘符字串获得对应的DosDevice路径,看之前的DosDevice路径中是否有现在的DosDevice路径(strstr)。
  3. 有的话,就拿到盘符字串,把盘字符串和去掉DosDevice盘符的DosDevice路径拼接;没有的话,就再读取下一个盘符的DosDevice路径,依次这样,直到找到为止。

缺点:

  1. 只能获得自己进程打开的文件,其它进程打开的文件貌似不行。
  2. MapViewOfFile在多线程中会产生冲突,返回错误码6,暂待解决。
#include <windows.h>
#include <psapi.h>

typedef DWORD (WINAPI *MyGetMappedFileName)(HANDLE,LPVOID,LPTSTR,DWORD);
int GetFileNameByHandle(HANDLE hFile,LPSTR buff,DWORD bufSize)
{
    HANDLE hfilemap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,NULL,NULL,NULL);      // 获取文件映射句柄
    if(INVALID_HANDLE_VALUE==hfilemap)
    {
        printf("CreateFileMapping error: %d\n",GetLastError());
        return 0;
    }

    LPVOID lpmap = MapViewOfFile(hfilemap,FILE_MAP_READ|FILE_MAP_WRITE,NULL,NULL,0);    // 获取文件映射对象
    if(NULL==lpmap)
    {
        printf("MapViewOfFile error: %d\n",GetLastError());
        return 0;
    }

    // GetMappedFileName未定义
    MyGetMappedFileName GetMappedFileName =(MyGetMappedFileName)GetProcAddress(LoadLibrary("psapi.dll"),"GetMappedFileNameA");
    if(GetMappedFileName==NULL)
    {
        printf("Get 'GetMappedFileName' FuncAddress error.\n");
        return 0;
    }
    char DosStr[MAX_PATH]= {0};
    DWORD length = GetMappedFileName(GetCurrentProcess(),lpmap,DosStr,bufSize);         // 获取Dos设备名
    if(0==length)
    {
        printf("GetMappedFileName error: %d\n", GetLastError());
        return 0;
    }

    char DosPath[MAX_PATH]= {0};
    char DriverString[MAX_PATH]= {0};
    if (0 == GetLogicalDriveStrings(MAX_PATH, DriverString))                            // 获取电脑的盘符列表
    {
        printf("GetLogicalDriveStrings error: %d", GetLastError());
        return 0;
    }

    char * p = (char *)DriverString;                                                    //p用来指向盘符
    do
    {
        *(p+2)='\0';                            //QuerDosDevice第一个参数必须是c:这种类型的,不能有\,所以把\抹掉
        if (!QueryDosDevice((LPCTSTR)p, DosPath, MAX_PATH))                             // 将盘符映射成DOS设备名
        {
            printf("QueryDosDrive error: %d\n", GetLastError());
            return FALSE;
        }

        char * q = strstr(DosStr,DosPath);      //检测buff中是否有DosDevice中的DosPath,有的话,p指向的那个字串就是要的盘符
        if(q!=0)
        {
            sprintf(buff, "%s%s", p, DosStr+strlen(DosPath));                           //找到之后应该把DosPath替换成盘符
            return 1;
        }
        p=p+4;                                                                          //指针移动到DriverString的下一个盘符处
    }
    while(*p!=0);
    return 0;
}

调用测试:

int main()
{
    HANDLE p=CreateFileA("a.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
    char m[100000];
    GetFileNameByHandle(p, m, sizeof(m));
    printf("%s",m);
    return 0;
}

结果截图:

在这里插入图片描述

方法二

char m[1000];	// 存储路径
int fileNameResult = GetFinalPathNameByHandleA(hFile, m, MAX_PATH, 0);	// fileNameResult是路径长度

缺点:不能跨进程获取路径。
可能问题:fileapi.h不存在。(codeblocks中显示不存在,vs2019没有问题)

posted @ 2021-09-16 09:12  shandianchengzi  阅读(8)  评论(0编辑  收藏  举报  来源