从文件句柄中获取文件名?

我将ntdll.dll的NtCreateFile()函数挂钩以允许/拒绝某些文件的访问。 与kernel32.dll的CreateFile()不同,它很容易为您提供相关文件的完整路径,ntdll.dll的NtCreateFile()函数只为您提供文件的句柄。 我需要从文件句柄获取文件的完整路径,从而允许/拒绝访问。 我一直在搜索,似乎没有一个有效的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#版本的“从文件句柄获取文件名”。

任何见解,代码修复,链接?

自己解决了。 这是带有引用和东西的工作代码。

 [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."; } 

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

“以下示例使用文件映射对象从句柄到文件对象获取文件名。它使用CreateFileMapping和MapViewOfFile函数创建映射。接下来,它使用GetMappedFileName函数来获取文件名。”

代码对我来说是合法的,希望有所帮助。

您在此处发布的代码已从MSDN中复制。 它有几个缺点:它需要一个大于0字节的实际文件才能工作。 它不适用于0字节的文件,也不适用于目录。 (我甚至不谈网络驱动器)

我在这里发布了一个完美的代码: 如何获得与打开HANDLE相关联的名称