Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 ntdll NtQueryInformationFile x64  [new]
S_Gur
Member

Откуда: Беэр-Шева, Израиль
Сообщений: 353
Добрый день. Долгое время пользовался самописной 32-хбитной программой, которая вытаскивает параметры файлов с помощью функции NtQueryInformationFile. Решил переписать программу и в процессе модификации собрать ее как 64-хбитную. Обнаружилось, что в 64-хбитном режиме функция не работает - возвращает код 0x80000002. С 32-хбитным режимом никаких проблем - все прекрасно живет. Перерыл полгугла - нигде не описано каких-то различий между вызовами функции под x86 и x64. Все параметры и их типы теоретически должны быть идентичны. Что я упускаю? Никто не сталкивался с подобной ситуацией?

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    OD: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

Uses
  UITypes;

{$R *.dfm}

Type
  IO_STATUS_BLOCK = Packed Record
                      NTSTATUS    : Pointer;
                      Information : DWord;
                    End;
  PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;

  FILE_BASIC_INFORMATION = Packed Record
                             CreationTime, LastAccessTime, LastWriteTime, ChangeTime : FileTime;
                             FileAttributes, Reserve                                 : ULong
                           End;
  PFILE_BASIC_INFORMATION = ^FILE_BASIC_INFORMATION;

Const
  FileBasicInformation = 4;
  STATUS_SUCCESS       = 0;

function NtQueryInformationFile(hFile : THandle; IoStatusBlock : PIO_STATUS_BLOCK; FileInformation : PFILE_BASIC_INFORMATION; Length : ULong; FileInformationClass : ULong) : ULong; StdCall; External 'ntdll' Name 'ZwQueryInformationFile';

function FileTimeToDateTime(FileTime : TFileTime) : TDateTime;

Var
  ModifiedTime : TFileTime;
  SystemTime   : TSystemTime;

begin
  Result   := 0;
  If (FileTime.dwLowDateTime = 0) And (FileTime.dwHighDateTime = 0) Then Exit;
  Try
    FileTimeToLocalFileTime(FileTime, ModifiedTime);
    FileTimeToSystemTime(ModifiedTime, SystemTime);
    Result := SystemTimeToDateTime(SystemTime)
  Except
    Result := Now
  End
end;

function GetFileDatesAndAttributes(Const AFileName : String; Var CrTime, LWTime, LATime, ChTime: TDateTime; Var FAttributes : Integer) : Boolean;

Var
  FHandle         : THandle;
  StatusBlock     : IO_STATUS_BLOCK;
  FileInformation : FILE_BASIC_INFORMATION;
  R               : ULong;

Begin
  Result          := False;
  FHandle         := CreateFile(Pchar(AFileName), GENERIC_READ, FILE_SHARE_READ, Nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
  If FHandle = INVALID_HANDLE_VALUE Then Exit;
  Try
    R             := NtQueryInformationFile(FHandle, @StatusBlock, @FileInformation, SizeOf(FileInformation), FileBasicInformation);
    {If R = STATUS_SUCCESS Then} With FileInformation Do
    Begin
      CrTime      := FileTimeToDateTime(CreationTime);
      LATime      := FileTimeToDateTime(LastAccessTime);
      LWTime      := FileTimeToDateTime(LastWriteTime);
      ChTime      := FileTimeToDateTime(ChangeTime);
      FAttributes := FileAttributes;
      Result      := True
    End
  Finally
    CloseHandle(FHandle)
  End
End;

procedure TForm1.Button1Click(Sender: TObject);

Var
  D1, D2, D3, D4 : TDateTime;
  I              : Integer;

begin
  If Not OD.Execute Then Exit;
  If GetFileDatesAndAttributes(OD.FileName, D1, D2, D3, D4, I) Then
  Begin
    Edit1.Text := DateTimeToStr(D1);
    Edit2.Text := DateTimeToStr(D2);
    Edit3.Text := DateTimeToStr(D3);
    Edit4.Text := DateTimeToStr(D4);
  End
  Else MessageDlg('Error!', mtError, [mbOk], 0)
end;

end.
24 июн 20, 19:20    [22156756]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1710
http://docwiki.embarcadero.com/Libraries/Rio/en/System.IOUtils.TFile

var
  FilePath: string;
  Attrs: TFileAttributes;
begin
  FilePath := 'c:\Users\desktop.ini';
  Edit1.Text := DateTimeToStr(TFile.GetCreationTime(FilePath));
  Edit2.Text := DateTimeToStr(TFile.GetLastAccessTime(FilePath));
  Edit3.Text := DateTimeToStr(TFile.GetLastWriteTime(FilePath));
  Attrs := TFile.GetAttributes(FilePath);
end;
24 июн 20, 19:43    [22156772]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
S_Gur
Member

Откуда: Беэр-Шева, Израиль
Сообщений: 353
X-Cite, если бы мне хватало только трех дат, я именно так бы и поступил. NtQueryInformationFile возвращает 4
24 июн 20, 19:46    [22156774]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
Michael Longneck
Member

Откуда: Москва
Сообщений: 2312
Note If the call to this function occurs in user mode, you should use the name "NtQueryInformationFile" instead of "ZwQueryInformationFile".
24 июн 20, 23:06    [22156836]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
S_Gur
Member

Откуда: Беэр-Шева, Израиль
Сообщений: 353
Michael Longneck, и что? А я что в коде использовал?
24 июн 20, 23:20    [22156839]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
GunSmoker
Member

Откуда:
Сообщений: 3140
0x80000002 = EXCEPTION_DATATYPE_MISALIGNMENT

У вас структуры неправильно объявлены.

https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_status_block
24 июн 20, 23:27    [22156842]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
S_Gur
Member

Откуда: Беэр-Шева, Израиль
Сообщений: 353
GunSmoker, а как объяснить, что в 32-хбитном варианте никаких проблем со структурами не возникает?
24 июн 20, 23:32    [22156845]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
alekcvp
Member

Откуда:
Сообщений: 2178
S_Gur
GunSmoker, а как объяснить, что в 32-хбитном варианте никаких проблем со структурами не возникает?

Каким-то чудом, судя по всему.

Для начала:
IO_STATUS_BLOCK = Packed Record
                      NTSTATUS    : Pointer;
                      Information : DWord;
                    End;
typedef struct _IO_STATUS_BLOCK {
  union {
    NTSTATUS Status;
    PVOID    Pointer;
  } DUMMYUNIONNAME;
  ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
В x64, если что, ULONG_PTR - это не DWord.

Для продолжения:
FILE_BASIC_INFORMATION = Packed Record
                             CreationTime, LastAccessTime, LastWriteTime, ChangeTime : FileTime;
                             FileAttributes, Reserve                                 : ULong
                           End;
typedef struct _FILE_BASIC_INFORMATION {
  LARGE_INTEGER CreationTime;
  LARGE_INTEGER LastAccessTime;
  LARGE_INTEGER LastWriteTime;
  LARGE_INTEGER ChangeTime;
  ULONG         FileAttributes;
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
25 июн 20, 01:11    [22156872]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
S_Gur
Member

Откуда: Беэр-Шева, Израиль
Сообщений: 353
alekcvp, судя по этой - http://delphiexpert.ru/tfiletime.html - статье, TFileTime - это и есть LARGE_INTEGER. Насколько я понимаю, FILE_BASIC_INFORMATION я описал вполне корректно

Сообщение было отредактировано: 25 июн 20, 06:04
25 июн 20, 06:06    [22156890]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
S_Gur
Member

Откуда: Беэр-Шева, Израиль
Сообщений: 353
В результате изысканий в указанном знающими товарищами направлении, наткнулся на следующую статейку: https://coderoad.ru/3707252/Как-преобразовать-объединение-C-внутри-структуры-в-Delphi

В результате оформилась вполне себе рабочая структура:

IO_STATUS_BLOCK = record
    case Integer of
      0: (
        Status: NTSTATUS;
        Pointer_: Pointer);
      1: (
        case Padding: DWORD of
          0: (
            Information: ULONG_PTR));
  end;


FILE_BASIC_INFORMATION оставлен без изменений - там все правильно

Функция заработала, всем спасибо. Тема закрыта

Сообщение было отредактировано: 25 июн 20, 06:34
25 июн 20, 06:36    [22156893]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11913
S_Gur
В результате оформилась вполне себе рабочая структура:
Сами поняли, что написали? А написан абсолютный сюр.

Для потомков оставлю правильные структуры
alekcvp
typedef struct _IO_STATUS_BLOCK {
  union {
    NTSTATUS Status;
    PVOID    Pointer;
  } DUMMYUNIONNAME;
  ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
IO_STATUS_BLOCK = record
  Misc: record
    case Byte of
      0: (Status: NTSTATUS);
      1: (Pointer_: Pointer);
    end;
  Information: ULONG_PTR;
end;

alekcvp
typedef struct _FILE_BASIC_INFORMATION {
  LARGE_INTEGER CreationTime;
  LARGE_INTEGER LastAccessTime;
  LARGE_INTEGER LastWriteTime;
  LARGE_INTEGER ChangeTime;
  ULONG         FileAttributes;
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
FILE_BASIC_INFORMATION = record
  CreationTime: LARGE_INTEGER;
  LastAccessTime: LARGE_INTEGER;
  LastWriteTime: LARGE_INTEGER;
  ChangeTime: LARGE_INTEGER;
  FileAttributes: ULONG;
end;

Обратите внимание на отсутствие packed
25 июн 20, 14:19    [22157208]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
GunSmoker
Member

Откуда:
Сообщений: 3140
S_Gur
GunSmoker, а как объяснить, что в 32-хбитном варианте никаких проблем со структурами не возникает?


Как известно, 90% кода в интернете - говно.
25 июн 20, 16:04    [22157286]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
alekcvp
Member

Откуда:
Сообщений: 2178
_Vasilisk_
Обратите внимание на отсутствие packed

Кстати, а typedef struct в х86 по-умолчанию какое выравнивание имеет?
S_Gur
alekcvp, судя по этой - http://delphiexpert.ru/tfiletime.html - статье, TFileTime - это и есть LARGE_INTEGER. Насколько я понимаю, FILE_BASIC_INFORMATION я описал вполне корректно

Где в исходной структуре вы увидели поле Reserve?..
26 июн 20, 00:56    [22157541]     Ответить | Цитировать Сообщить модератору
 Re: ntdll NtQueryInformationFile x64  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4214
alekcvp
в х86 по-умолчанию какое выравнивание имеет?

8 вроде всегда было.

Сообщение было отредактировано: 26 июн 20, 01:31
26 июн 20, 01:33    [22157548]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить