OpenFileById получает System.AccessViolationException при запуске от имени пользователя (работает от имени администратора) - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть код, который извлекает 128-битные идентификаторы NTFS из файлов по определенным путям.Затем я попытался получить путь к файлу, используя этот идентификатор.Код работает так же долго, как и при поиске путей, которые я запускаю от имени администратора.Это не будет возможно в производстве.К сожалению, я не могу вызвать 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;
            }
        }
    }

Снова хочу указать - этот код отлично работает при запуске от имени администратора.Файлы принадлежат пользователю, пользователь может удалять, переименовывать и перемещать файлы без каких-либо дополнительных разрешений.

Любая помощь будет принята с благодарностью, спасибо!

Edit1:

Я реализовал ответ, найденный здесь Как обрабатывать AccessViolationException , чтобы успешно перехватить исключение.Однако даже после этого Marshal.GetLastWin32Error () возвращает 0. Если у кого-либо есть представление о том, как я могу отладить проблему такого типа, пожалуйста, дайте мне знать.

Кроме того, она все еще работает, когда я работаю от имени администратора, но некак пользователь.

Edit2:

Не уверен, что это актуально - библиотека с этим кодом создается для .NET Standard 2.0 - Приложение, использующее этот код библиотеки, создается для .NET Framework 4.6.2

...