Получить имя файла из дескриптора файла? - PullRequest
4 голосов
/ 23 июля 2010

У меня функция ntdll.dll NtCreateFile () подключена, чтобы разрешить / запретить доступ к определенным файлам.В отличие от CreateFile () из kernel32.dll, который легко дает вам полный путь к рассматриваемому файлу, функция ntdll.dll (ntdll.dll) дает вам только дескриптор файла.Мне нужно получить полный путь к файлу из дескриптора файла, чтобы впоследствии разрешить / запретить доступ.Я искал вокруг, и, кажется, нет работающего решения C #.

Это решение написано на C ++ и задокументировано Microsoft.Я пытался перенести его на C # с небольшим успехом.Вот моя попытка C # эквивалента C ++ версии «получения имени файла из дескриптора файла»:

    public string GetFileNameFromHandle(IntPtr FileHandle)
    {
        string fileName = String.Empty;
        IntPtr fileMap = IntPtr.Zero, fileSizeHi = IntPtr.Zero;
        UInt32 fileSizeLo = 0;

        fileSizeLo = GetFileSize(FileHandle, fileSizeHi);

        if (fileSizeLo == 0 && fileSizeHi == IntPtr.Zero)
        {
            // cannot map an 0 byte file
            return String.Empty;
        }

        fileMap = CreateFileMapping(FileHandle, IntPtr.Zero, FileMapProtection.PageReadonly, 0, 1, null);

        if (fileMap != IntPtr.Zero)
        {
            IntPtr pMem = MapViewOfFile(fileMap, FileMapAccess.FileMapRead, 0, 0, 1);
            if (pMem != IntPtr.Zero)
            {
                StringBuilder fn = new StringBuilder(250);
                GetMappedFileName(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle, pMem, fn, 250);
                if (fileName.Length > 0)
                {
                    UnmapViewOfFile(pMem);
                    CloseHandle(FileHandle);
                    return fn.ToString();
                }
                else
                {
                    UnmapViewOfFile(pMem);
                    CloseHandle(FileHandle);
                    return String.Empty;
                }
            }
        }

        return String.Empty;
    }

У меня, конечно, есть все необходимые DLLImports и пользовательские типы.Когда я использую эту функцию на дескрипторах, я получаю пустую строку взамен.Это также довольно сложно отладить, так как этот метод находится в DLL, которая вставляется в целевой процесс, а не в то, что вы можете установить точку останова и наслаждаться системой отладки Visual Studio.Думаю, я мог бы написать файл журнала или какую-нибудь систему трассировки, но я еще не настолько отчаялся.Мне просто нужна успешная C # версия "получить имя файла из дескриптора файла".

Есть идеи, исправления кода, ссылки?

Ответы [ 3 ]

3 голосов
/ 23 июля 2010

Решил сам.Вот рабочий код со ссылками и прочее.

[DllImport("kernel32.dll")]
static extern uint GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr CreateFileMapping(
    IntPtr hFile,
    IntPtr lpFileMappingAttributes,
    FileMapProtection flProtect,
    uint dwMaximumSizeHigh,
    uint dwMaximumSizeLow,
    [MarshalAs(UnmanagedType.LPTStr)]string lpName);

[Flags]
public enum FileMapProtection : uint
{
    PageReadonly = 0x02,
    PageReadWrite = 0x04,
    PageWriteCopy = 0x08,
    PageExecuteRead = 0x20,
    PageExecuteReadWrite = 0x40,
    SectionCommit = 0x8000000,
    SectionImage = 0x1000000,
    SectionNoCache = 0x10000000,
    SectionReserve = 0x4000000,
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr MapViewOfFile(
    IntPtr hFileMappingObject,
    FileMapAccess dwDesiredAccess,
    uint dwFileOffsetHigh,
    uint dwFileOffsetLow,
    uint dwNumberOfBytesToMap);

[Flags]
public enum FileMapAccess : uint
{
    FileMapCopy = 0x0001,
    FileMapWrite = 0x0002,
    FileMapRead = 0x0004,
    FileMapAllAccess = 0x001f,
    fileMapExecute = 0x0020,
}

[DllImport("psapi.dll", SetLastError = true)]
public static extern uint GetMappedFileName(IntPtr m_hProcess, IntPtr lpv, StringBuilder 
        lpFilename, uint nSize);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

public static string GetFileNameFromHandle(IntPtr FileHandle)
{
    string fileName = String.Empty;
    IntPtr fileMap = IntPtr.Zero, fileSizeHi = IntPtr.Zero;
    UInt32 fileSizeLo = 0;

    fileSizeLo = GetFileSize(FileHandle, fileSizeHi);

    if (fileSizeLo == 0)
    {
        // cannot map an 0 byte file
        return "Empty file.";
    }

    fileMap = CreateFileMapping(FileHandle, IntPtr.Zero, FileMapProtection.PageReadonly, 0, 1, null);

    if (fileMap != IntPtr.Zero)
    {
        IntPtr pMem = MapViewOfFile(fileMap, FileMapAccess.FileMapRead, 0, 0, 1);
        if (pMem != IntPtr.Zero)
        {
            StringBuilder fn = new StringBuilder(250);
            GetMappedFileName(System.Diagnostics.Process.GetCurrentProcess().Handle, pMem, fn, 250);
            if (fn.Length > 0)
            {
                UnmapViewOfFile(pMem);
                CloseHandle(FileHandle);
                return fn.ToString();
            }
            else
            {
                UnmapViewOfFile(pMem);
                CloseHandle(FileHandle);
                return "Empty filename.";
            }
        }
    }

    return "Empty filemap handle.";
}
0 голосов
/ 25 июля 2013

Код, который вы разместили здесь, скопирован с MSDN.У него есть несколько недостатков: для работы требуется настоящий файл размером более 0 байт.Он не работает для файлов размером 0 байт и не работает для каталогов.(а я даже не говорю о сетевых дисках)

Я разместил здесь совершенно рабочий код: Как получить имя, связанное с open HANDLE

0 голосов
/ 23 июля 2010

С http://msdn.microsoft.com/en-us/library/aa366789.aspx

"Следующий пример получает имя файла из дескриптора объекта файла с помощью объекта сопоставления файлов. Для создания сопоставления он использует функции CreateFileMapping и MapViewOfFile. Затем он используетфункция GetMappedFileName для получения имени файла. "

Код выглядит законным для меня, надеюсь, это поможет.

...