Конференция "WinAPI" » Как получить путь к файлу... [D7, WinXP]
 
  • Riply © (07.09.07 06:32) [20]
    > [19] Undri   (07.09.07 06:21)
    > Почему отбросим,
    Потому, что это старая проблемма.
    >если на них-то как раз и "не срабатывает" ? :)
    На них срабатывает, но иногда для срабатывания требуется неопределенное количество времени :)
  • Slym © (07.09.07 06:38) [21]
    unit NTApi;

    interface
    uses windows,sysutils;

    type
     NT_STATUS = Cardinal;

    function NtQuerySystemInformation(SystemInformationClass: DWORD; SystemInformation: Pointer;
    SystemInformationLength:DWORD; ReturnLength:PDWORD):NT_STATUS; stdcall;

    type
     PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;
     IO_STATUS_BLOCK = packed record
       Status: NT_STATUS;
       Information: DWORD;
     end;
     TIOStatusBlock=IO_STATUS_BLOCK;

     PFILE_NAME_INFORMATION = ^FILE_NAME_INFORMATION;
     FILE_NAME_INFORMATION = packed record
       FileNameLength: ULONG;
       FileName: array [0..MAX_PATH - 1] of WideChar;
     end;
     TFileNameInformation=FILE_NAME_INFORMATION;

     PUNICODE_STRING = ^TUNICODE_STRING;
     TUNICODE_STRING = packed record
       Length : WORD;
       MaximumLength : WORD;
       Buffer : array [0..MAX_PATH - 1] of WideChar;
     end;

     POBJECT_NAME_INFORMATION = ^OBJECT_NAME_INFORMATION;
     OBJECT_NAME_INFORMATION = packed record
       Name : TUNICODE_STRING;
     end;
     TObjectNameInformation=OBJECT_NAME_INFORMATION;

    const
     STATUS_SUCCESS = NT_STATUS($00000000);
     STATUS_INVALID_INFO_CLASS = NT_STATUS($C0000003);
     STATUS_INFO_LENGTH_MISMATCH = NT_STATUS($C0000004);
     STATUS_INVALID_DEVICE_REQUEST = NT_STATUS($C0000010);
     ObjectNameInformation = 1;
     FileDirectoryInformation = 1;
     FileNameInformation = 9;
     SystemProcessesAndThreadsInformation = 5;
     SystemHandleInformation = 16;

    function NtQueryInformationFile(FileHandle: THandle; IoStatusBlock: PIO_STATUS_BLOCK; FileInformation: Pointer;
    Length: DWORD; FileInformationClass: DWORD): NT_STATUS; stdcall;

    function NtQueryObject(ObjectHandle: THandle; ObjectInformationClass: DWORD; ObjectInformation: Pointer;
       ObjectInformationLength: ULONG; ReturnLength: PDWORD): NT_STATUS; stdcall;

    function GetLongPathNameA(lpszShortPath, lpszLongPath: PChar;
       cchBuffer: DWORD): DWORD; stdcall; external kernel32 name 'GetLongPathNameA';

    const
     ntdll  = 'ntdll.dll';

    function GetFileNameByHandle(FileHandle: THandle):string;

    implementation

    function NtQuerySystemInformation; external ntdll name 'NtQuerySystemInformation';
    function NtQueryInformationFile; external ntdll name 'NtQueryInformationFile';
    function NtQueryObject; external ntdll name 'NtQueryObject';

    function GetFileNameByHandle(FileHandle: THandle):string;
    var
     FileNameInfo: TFileNameInformation;
     ObjectNameInfo: TObjectNameInformation;
     IoStatusBlock: TIOStatusBlock;
     res,dwReturn: DWORD;
    begin
     result:='';
     res := NtQueryInformationFile(FileHandle,@IoStatusBlock,@FileNameInfo,
       SizeOf(FileNameInfo.FileName),FileNameInformation);
     if res = STATUS_SUCCESS then
     begin
       res := NtQueryObject(FileHandle,ObjectNameInformation,
         @ObjectNameInfo, SizeOf(ObjectNameInfo.Name.Buffer), @dwReturn);
       if res = STATUS_SUCCESS then
       begin
         SetLength(result,MAX_PATH);
         SetLength(result,WideCharToMultiByte(CP_ACP, 0,
           @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength -
           ObjectNameInfo.Name.Length],
           ObjectNameInfo.Name.Length div SizeOf(WideChar),
           @result[1],MAX_PATH, nil, nil));
       end else
       begin
         SetLength(result,MAX_PATH);
         SetLength(result,WideCharToMultiByte(CP_ACP, 0,
           @FileNameInfo.FileName[0], FileNameInfo.FileNameLength div SizeOf(WideChar),
           @result[1],MAX_PATH, nil, nil));
       end;
     end;
    end;

    end.

  • Slym © (07.09.07 07:01) [22]
    только как получить нормальный c:\ низнаю :)
    хотя... можно для всех DosDevice получить \Device\HarddiskVolumeX\ и тупо заменять
  • Riply © (07.09.07 07:04) [23]
    >[21] Slym ©   (07.09.07 06:38)
    А для чего вызывается NtQueryInformationFile ?
    Почему не обойтись только NtQueryObject ?
  • Slym © (07.09.07 07:27) [24]
    Riply ©   (07.09.07 7:04) [23]
    NtQueryObject

    хз с инета сдернул :)
    а так NtQueryObject - на пайпах виснет и NtQueryInformationFile используется (я так понял) аля GetFileType(FileHandle: THandle)=FILE_TYPE_CHAR
  • SLoW.AlfaMoon.Com (07.09.07 10:23) [25]
    RtlNtPathNameToDosPathName [WXP, 2K3]
  • Undri (07.09.07 12:59) [26]
    У меня код [21] вообще ничего не показывает. Единственное, что на пайпах не виснет :)

    > Riply ©   (07.09.07 06:32) [20]
    >
    > > [19] Undri   (07.09.07 06:21)
    > > Почему отбросим,
    > Потому, что это старая проблемма.

    Это не проблема. Решается простым драйвером.


    > Riply ©   (07.09.07 06:32) [20]
    >
    > >если на них-то как раз и "не срабатывает" ? :)
    > На них срабатывает, но иногда для срабатывания требуется
    > неопределенное количество времени :)

    Иногда до конца сеанса :)
  • Riply © (07.09.07 13:13) [27]
    > [26] Undri   (07.09.07 12:59)
    > У меня код [21] вообще ничего не показывает. Единственное, что на пайпах не виснет :)
    Не на тех пайпах пробовал :)
    P.S. Код не тестировала.

    > Это не проблема. Решается простым драйвером.
    Мне до написания драйвера как до луны :(
    Поэтому для меня это остается проблеммой.
  • Undri (07.09.07 14:10) [28]

    > Riply ©   (07.09.07 13:13) [27]
    >
    > Не на тех пайпах пробовал :)

    На тех - на тех :) Cинхронные пайпы, занятые в данный момент.


    > Riply ©   (07.09.07 13:13) [27]
    >
    > P.S. Код не тестировала.
    >

    Там просто память надо выделить для FileNameInfo и ObjectNameInfo.


    > Riply ©   (07.09.07 13:13) [27]
    >
    > > Это не проблема. Решается простым драйвером.
    > Мне до написания драйвера как до луны :(
    > Поэтому для меня это остается проблеммой.
    >

    Ещё вариант - создать поток, в ф-ции которого запрашивать имя. А если поток скажем через 100 мс. сам не завершится (типа WaitForSingleObject( hThread, 100 ) == WAIT_TIMEOUT ) - значит завис на пайпе. После чего прибить его TerminateThread'ом.
    Правда, имени его ты так и не узнаешь :) Это только из R0 сделать можно.
  • SLoW.AlfaMoon.Com (07.09.07 15:55) [29]
    пост [25]
    это в ответ на Slym ©   (07.09.07 07:01) [22]
  • Undri (08.09.07 02:01) [30]

    > SLoW.AlfaMoon.Com   (07.09.07 10:23) [25]
    >
    > RtlNtPathNameToDosPathName [WXP, 2K3]

    А сигнатуру можешь дать (хотя бы типы параметров)?  Полазил по Сети - ничего конкретного по этой ф-ции не обнаружил :(

    ЗЫ  ты сам-то пользовался этой функцией?
  • Cj © (09.09.07 12:10) [31]
    Всем спасибо, заработало, только путь выводит в виде
    \Device\HarddiskVolume1\
    я то знаю, что это c:\ раздел первый.
    а перевести вроде-бы можно QueryDosDevice - не подскажете?
  • Riply © (09.09.07 12:19) [32]
    > [31] Cj ©   (09.09.07 12:10)
    >а перевести вроде-бы можно QueryDosDevice - не подскажете?
    У [22] Slym © один из вариантов.
    Можно еще посмотреть исходники от Игоря Шевченко.
    Если память мне не изменяет, то в DeviceIoControl60 есть функция перевода.
  • Cj © (09.09.07 12:19) [33]
    А, все, разобрался, еще раз спасибо всем!
  • SLoW.AlfaMoon.Com (10.09.07 10:17) [34]

    > Undri


    функцию "копать" надо. сэмпла у себя не нашел чего-то :( Странно.
    Впрочем вот тебе решение

    http://www.wasm.ru/forum/viewtopic.php?pid=183057#p183057
  • Undri (11.09.07 07:40) [35]
    SLoW.AlfaMoon.Com, спасибо. Я просто нигде не нашел сигнатуры RtlNtPathNameToDosPathName. Думал, может у тебя имеется..

    А сам я пользую  вот такое:


    // device file name -> DOS file name
    function GetDOSFileName(lpDeviceFileName:pchar):string;
    var
    lpDeviceName:array[0..$1000-1] of char;
    lpDrive:array[0..2] of char;
    actDrive:char;
    begin
     Result:=lpDeviceFileName;
    lpDrive := 'A:';
    for actDrive :='A' to 'Z' do
    begin
     lpDrive[0] := actDrive;
     if (QueryDosDevice(lpDrive, lpDeviceName, $1000) <> 0) then
     begin
         if (CompareString(LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,lpDeviceName,lstrlen(lpDevi ceName),
                          lpDeviceFileName,lstrlen(lpDeviceName))=CSTR_EQUAL) then
      begin
       Result:=string(lpDrive)+PChar(cardinal(lpDeviceFileName) + lstrlen(lpDeviceName));
       break
      end
     end
    end
    end;

    // DOS file name -> device file name
    function GetDeviceFileName(lpDOSFileName:pchar):string;
    var
    lpDrive:array[0..2] of char;
    lpDeviceName:array[0..$1000-1] of char;
    begin
     Result:=lpDOSFileName;
    lstrcpyn(lpDrive,lpDOSFileName,3);
    if (QueryDosDevice(lpDrive, lpDeviceName, $1000 )<>0) then
    begin
       if (CompareString(LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,'\??\',4,
                          lpDeviceName,4)=CSTR_EQUAL) then
     begin
      Result:=PChar(lpDeviceName + 4)+ string(PChar(lpDOSFileName + 2));
      exit
     end;
     lstrcat(lpDeviceName, lpDOSFileName + 2 );
     Result := lpDeviceName
    end
    end;

  • Undri (11.09.07 08:08) [36]
    Забыл добавить: тут не учитываются Network drive'ы (всякие там LanmanRedirector/etc.). Но при желании и их можно довольно просто обработать.
  • SLoW.AlfaMoon.Com (11.09.07 10:00) [37]
    NTSTATUS NTAPI RtlNtPathNameToDosPathName   (    
                   ULONG     Unknown1,
     ULONG   Unknown2,
     ULONG   Unknown3,
     ULONG   Unknown4
    )
  • Игорь Шевченко © (11.09.07 11:42) [38]
    NTSTATUS RtlNtPathNameToDosPathName (UNICODE_STRING* NtPathName, UNICODE_STRING* DosPathName, ULONG* ReturnedLength, LPWSTR* FilePath)
  • SLoW.AlfaMoon.Com (11.09.07 16:18) [39]

    > Игорь Шевченко ©   (11.09.07 11:42) [38]

    Спасибо, ценно. Это в ваших модулях по Native API есть?
 
Конференция "WinAPI" » Как получить путь к файлу... [D7, WinXP]
Есть новые Нет новых   [134431   +15][b:0][p:0.003]