我有一些代码可以从特定路径的文件中检索128位NTFS ID。然后,我尝试使用此ID检索文件路径。该代码在检索以admin身份运行的路径时有效。在生产中这是不可能的。不幸的是,我无法调用Marshal.GetLastWin32Error(),因为System.AccessViolationException导致应用程序完全崩溃。下面是检索路径的代码。
public const int NO_PERMISSION = 0;
[DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
[InAttribute()] System.IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
[InAttribute()] System.IntPtr hTemplateFile
);
[DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle OpenFileById(
IntPtr hVolumeHint,
FILE_ID_DESCRIPTOR lpFileId,
uint dwDesiredAccess,
uint dwShareMode,
[InAttribute()] System.IntPtr lpSecurityAttributes,
uint dwFlagsAndAttributes
);
public enum _FILE_ID_TYPE
{
FileIdType = 0,
ObjectIdType,
ExtendedFileIdType,
MaximumFileIdType
}
[StructLayout(LayoutKind.Explicit)]
public struct FILE_ID_128
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
[FieldOffset(0)]
public byte[] Identifier;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FILE_ID_DESCRIPTOR
{
public uint dwSize;
public _FILE_ID_TYPE Type;
public FILE_ID_128 ExtendedFileId;
}
public static string GetObjectPathFromId(string pathToSection, string hexId)
{
// We need a file handle to the drive we are looking in
using (SafeFileHandle handle = Methods.CreateFile(
pathToSection,
Constants.NO_PERMISSION,
Constants.NO_PERMISSION,
IntPtr.Zero,
Constants.OPEN_EXISTING,
0x02000000 | 0x00000080,
IntPtr.Zero))
{
// Build descriptor
FILE_ID_DESCRIPTOR descriptor = new FILE_ID_DESCRIPTOR();
descriptor.dwSize = (uint)Marshal.SizeOf(descriptor);
descriptor.Type = _FILE_ID_TYPE.ExtendedFileIdType;
descriptor.ExtendedFileId.Identifier = StringToByteArrayFastest(hexId);
using (SafeFileHandle actualFile = OpenFileById(handle.DangerousGetHandle(), descriptor,
Constants.NO_PERMISSION, Constants.NO_PERMISSION,
IntPtr.Zero, 0))
{
if (actualFile.IsInvalid)
return "";
// Buffer for the path, this should be way big enough
int sizeOfBuffer = 1024;
// Allocate a buffer
IntPtr pointer = Marshal.AllocHGlobal(sizeOfBuffer);
uint size = (uint)sizeOfBuffer;
uint returnValue = GetFinalPathNameByHandleW(actualFile.DangerousGetHandle(), pointer, size, 0);
// Copy it into a managed array
byte[] outPut = new byte[sizeOfBuffer];
Marshal.Copy(pointer, outPut, 0, (int)returnValue);
// Decode it
var str = Encoding.Unicode.GetString(outPut);
// Will be an empty string if the call fails
return str;
}
}
}
我还是要指定-此代码以admin身份运行时效果很好。这些文件归用户所有,该用户无需任何其他权限即可删除,重命名和移动文件。
任何帮助将不胜感激!
Edit1:
我实现了How to handle AccessViolationException处的答案,以成功捕获异常。但是,即使执行完此Marshal.GetLastWin32Error()也会返回0。如果有人对如何调试此类问题有任何想法,请告诉我。
当我以admin(而不是用户)身份运行时,它仍然可以正常运行。
Edit2:
不确定是否相关-此代码库是否针对.NET Standard 2.0构建-使用此库代码的应用程序针对.NET Framework 4.6.2构建