Путь от тома жесткого диска до полного пути к файлу

У меня есть приложение MSVC++, которое выдает пути к дескрипторам файлов на жестком диске, открытые другими приложениями, в следующем строковом формате:

\Device\HarddiskVolume4\Users\User\Documents\Visual Studio 2013\Projects\FileLocker\FileLocker\bin\Debug\Test.txt

Я хотел бы преобразовать эти пути в полные пути к этим файлам в Windows. Например, я хотел бы преобразовать указанный выше путь к тому жесткого диска в полный путь к файлу Windows с соответствующей буквой диска:

C:\Users\User\Documents\Visual Studio 2013\Projects\FileLocker\FileLocker\bin\Debug\Test.txt

Я искал в Интернете, но я не нашел никакого четкого ресурса для того, чтобы сделать это программно. Как это сделать?


person Alexandru    schedule 26.10.2014    source источник


Ответы (1)


Вам следует найти одну из функций Windows API для управления томами:

Функции управления томами

Вот пример из MSDN:

Отображение путей к томам

#include <windows.h>
#include <stdio.h>

void DisplayVolumePaths(
        __in PWCHAR VolumeName
        )
{
    DWORD  CharCount = MAX_PATH + 1;
    PWCHAR Names     = NULL;
    PWCHAR NameIdx   = NULL;
    BOOL   Success   = FALSE;

    for (;;) 
    {
        //
        //  Allocate a buffer to hold the paths.
        Names = (PWCHAR) new BYTE [CharCount * sizeof(WCHAR)];

        if ( !Names ) 
        {
            //
            //  If memory can't be allocated, return.
            return;
        }

        //
        //  Obtain all of the paths
        //  for this volume.
        Success = GetVolumePathNamesForVolumeNameW(
            VolumeName, Names, CharCount, &CharCount
            );

        if ( Success ) 
        {
            break;
        }

        if ( GetLastError() != ERROR_MORE_DATA ) 
        {
            break;
        }

        //
        //  Try again with the
        //  new suggested size.
        delete [] Names;
        Names = NULL;
    }

    if ( Success )
    {
        //
        //  Display the various paths.
        for ( NameIdx = Names; 
              NameIdx[0] != L'\0'; 
              NameIdx += wcslen(NameIdx) + 1 ) 
        {
            wprintf(L"  %s", NameIdx);
        }
        wprintf(L"\n");
    }

    if ( Names != NULL ) 
    {
        delete [] Names;
        Names = NULL;
    }

    return;
}

void __cdecl wmain(void)
{
    DWORD  CharCount            = 0;
    WCHAR  DeviceName[MAX_PATH] = L"";
    DWORD  Error                = ERROR_SUCCESS;
    HANDLE FindHandle           = INVALID_HANDLE_VALUE;
    BOOL   Found                = FALSE;
    size_t Index                = 0;
    BOOL   Success              = FALSE;
    WCHAR  VolumeName[MAX_PATH] = L"";

    //
    //  Enumerate all volumes in the system.
    FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));

    if (FindHandle == INVALID_HANDLE_VALUE)
    {
        Error = GetLastError();
        wprintf(L"FindFirstVolumeW failed with error code %d\n", Error);
        return;
    }

    for (;;)
    {
        //
        //  Skip the \\?\ prefix and remove the trailing backslash.
        Index = wcslen(VolumeName) - 1;

        if (VolumeName[0]     != L'\\' ||
            VolumeName[1]     != L'\\' ||
            VolumeName[2]     != L'?'  ||
            VolumeName[3]     != L'\\' ||
            VolumeName[Index] != L'\\') 
        {
            Error = ERROR_BAD_PATHNAME;
            wprintf(L"FindFirstVolumeW/FindNextVolumeW returned a bad path: %s\n", VolumeName);
            break;
        }

        //
        //  QueryDosDeviceW does not allow a trailing backslash,
        //  so temporarily remove it.
        VolumeName[Index] = L'\0';

        CharCount = QueryDosDeviceW(&VolumeName[4], DeviceName, ARRAYSIZE(DeviceName)); 

        VolumeName[Index] = L'\\';

        if ( CharCount == 0 ) 
        {
            Error = GetLastError();
            wprintf(L"QueryDosDeviceW failed with error code %d\n", Error);
            break;
        }

        wprintf(L"\nFound a device:\n %s", DeviceName);
        wprintf(L"\nVolume name: %s", VolumeName);
        wprintf(L"\nPaths:");
        DisplayVolumePaths(VolumeName);

        //
        //  Move on to the next volume.
        Success = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));

        if ( !Success ) 
        {
            Error = GetLastError();

            if (Error != ERROR_NO_MORE_FILES) 
            {
                wprintf(L"FindNextVolumeW failed with error code %d\n", Error);
                break;
            }

            //
            //  Finished iterating
            //  through all the volumes.
            Error = ERROR_SUCCESS;
            break;
        }
    }

    FindVolumeClose(FindHandle);
    FindHandle = INVALID_HANDLE_VALUE;

    return;
}

Чтобы уточнить:

Имя тома (или GUID) что-то вроде \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}

Имя устройства что-то вроде \Device\HarddiskVolume1

Буква диска что-то вроде C:

FindFirst/NextVolume дает вам список имен томов.

QueryDosDevice дает вам имя устройства из имени тома.

GetVolumePathNamesForVolumeName дает вам букву диска из имени тома.

person kyflare    schedule 26.10.2014
comment
Я знаю, что должен быть какой-то API, который это делает, но мне нужно точно знать, какой метод поможет, и в идеале я ищу программное решение. - person Alexandru; 26.10.2014
comment
Этот пример из MSDN, кажется, делает именно то, что вы хотите: msdn.microsoft.com/en-us/library/cc542456%28v=vs.85%29.aspx Он отображает имя и путь каждого диска в вашей системе, просто выберите тот, который вы ищете . - person kyflare; 26.10.2014
comment
Это действительно работает? В документации говорится, что для этого требуется путь GUID тома, а не путь \Device\HarddiskVolume. - person Harry Johnston; 25.06.2015
comment
Чтобы уточнить: FindFirst/NextVolume дает вам имена томов (GUID \?\\etc), QueryDosDevice дает вам имя устройства (\Device\HarddiskVolume) из GUID, а GetVolumePathNamesForVolumeName дает вам букву диска (C:) из GUID. - person kyflare; 25.06.2015
comment
Да, пример кода работает, потому что он получает путь GUID тома и передает его в GetVolumePathNamesForVolumeName. Но ОП начинался с имени устройства. Я не уверен, работает ли GetVolumePathNamesForVolumeName с именем устройства или вам придется перечислять тома в поисках того, чье имя устройства совпадает. - person Harry Johnston; 26.06.2015