Отображение разделов, начиная с PhysicalDrive

Я хочу сопоставить все разделы со всех дисков в Windows (те, которые еще не сопоставлены). Я имею в виду, я хочу назначить каждому из них буквы диска. Я знаю, что вы можете сделать это с помощью FindFirstVolume, FindNextVolume, FindVolumeClose, но есть ситуации, когда вы не можете их использовать. Я пытался с QueryDosDevice, то же самое.

Идея состоит в том, чтобы начать с \.\PhysicalDrive[n], найти разделы и отобразить их. Я знаю, что это выполнимо, потому что я видел программу, которая может сделать это. Но мне это не нравится, потому что он также отображает скрытые разделы.

Кто-нибудь знает способ...? Спасибо.

3 ответа

Решение

Я сделал это:) Я создал программу, которая добавляет или удаляет буквы дисков при запуске - если один или несколько дисков были добавлены или удалены с компьютера:

program MapDrives;

uses Windows;

type
   TPARTITION_INFORMATION = record
      StartingOffset: _LARGE_INTEGER; //TLargeInteger;
      PartitionLength: _LARGE_INTEGER; //TLargeInteger;
      HiddenSectors: DWORD;
      PartitionNumber: DWORD;
      PartitionType: BYTE;
      BootIndicator: BOOLEAN;
      RecognizedPartition: BOOLEAN;
      RewritePartition: BOOLEAN;
   end;

function IntToStr(Value: Integer): string;
begin
   if Value < 10 then
      Result := Char(Value + 48)
   else
      Result := Char(Value div 10 + 48) + Char(Value + 48);
end;

function GetNextAvailableLetter: AnsiChar;
var Drives, mask: DWord;
   i: Integer;
begin
   Drives := GetLogicalDrives;
   mask := 4;
   Result := 'Z';
   for i := 3 to 26 do //C to Z
   begin
      if mask and Drives = 0 then
      begin
         Result := AnsiChar(64 + i);
         Exit;
      end;
      mask := mask shl 1;
   end;
end;


const IOCTL_DISK_GET_PARTITION_INFO = $0074004;

var i, j, k: Integer;
   H: THandle;
   dwBytesReturned: DWORD;
   BreakCycle, DoMount: Boolean;
   NextLetter: AnsiChar;
   PartitionInformation: TPARTITION_INFORMATION;
   PartitionsInformation: array of TPARTITION_INFORMATION;
   Drives, mask: DWord;
   OldMode: UINT;

begin
   OldMode := SetErrorMode(SEM_FAILCRITICALERRORS); //so it shouldn't ask to insert CD or card

   //gets informations about already mounted partitions
   SetLength(PartitionsInformation, 0);
   Drives := GetLogicalDrives;
   mask := 4;
   for i := 3 to 26 do //C to Z
   begin
      if mask and Drives <> 0 then
      begin
         H := CreateFile(PAnsiChar('\\.\' + Char(64 + i) + ':'), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
         if H <> INVALID_HANDLE_VALUE then
         begin
            SetLength(PartitionsInformation, Length(PartitionsInformation) + 1);
            DeviceIoControl(H, IOCTL_DISK_GET_PARTITION_INFO, nil, 0, @PartitionsInformation[High(PartitionsInformation)], SizeOf(TPARTITION_INFORMATION), dwBytesReturned, nil);
            CloseHandle(H);
         end
         else     //removes unaccessible drives
            DefineDosDevice(DDD_REMOVE_DEFINITION or DDD_RAW_TARGET_PATH, PAnsiChar(string(Char(64 + i) + ':')), nil);
      end;
      mask := mask shl 1;
   end;

   for i := 0 to 99 do
   begin
      H := CreateFile(PAnsiChar('\\.\PhysicalDrive' + IntToStr(i)), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
      if H = INVALID_HANDLE_VALUE then //no more hdd's
         Break;
      CloseHandle(H);
      for j := 1 to 20 do
      begin
         BreakCycle := False;
         NextLetter := GetNextAvailableLetter;
         DefineDosDevice(DDD_RAW_TARGET_PATH or DDD_NO_BROADCAST_SYSTEM, PAnsiChar(string(NextLetter + ':')), PAnsiChar('\Device\Harddisk' + IntToStr(i) + '\Partition' + IntToStr(j)));
         DoMount := True;
         H := CreateFile(PAnsiChar('\\.\' + NextLetter + ':'), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
         if H = INVALID_HANDLE_VALUE then //no more partitions
            BreakCycle := True
         else
         begin
            PartitionInformation.PartitionType := 0;
            DeviceIoControl(H, IOCTL_DISK_GET_PARTITION_INFO, nil, 0, @PartitionInformation, SizeOf(TPARTITION_INFORMATION), dwBytesReturned, nil);
            DoMount := PartitionInformation.PartitionType in [0, 1, 6, 7, 11, 12, 114];
            CloseHandle(H);
         end;
         if DoMount then
         begin
            for k := 0 to High(PartitionsInformation) do  //compare with already mounted partitions
               if (PartitionsInformation[k].StartingOffset.LowPart = PartitionInformation.StartingOffset.LowPart) and
                  (PartitionsInformation[k].StartingOffset.HighPart = PartitionInformation.StartingOffset.HighPart) and
                  (PartitionsInformation[k].StartingOffset.QuadPart = PartitionInformation.StartingOffset.QuadPart) and
                  (PartitionsInformation[k].PartitionLength.LowPart = PartitionInformation.PartitionLength.LowPart) and
                  (PartitionsInformation[k].PartitionLength.HighPart = PartitionInformation.PartitionLength.HighPart) and
                  (PartitionsInformation[k].PartitionLength.QuadPart = PartitionInformation.PartitionLength.QuadPart) and
                  (PartitionsInformation[k].HiddenSectors = PartitionInformation.HiddenSectors) and
                  (PartitionsInformation[k].PartitionType = PartitionInformation.PartitionType) and
                  (PartitionsInformation[k].BootIndicator = PartitionInformation.BootIndicator) and
                  (PartitionsInformation[k].RecognizedPartition = PartitionInformation.RecognizedPartition) then
                  Break;
            DoMount := k > High(PartitionsInformation);
         end;
         DefineDosDevice(DDD_REMOVE_DEFINITION or DDD_RAW_TARGET_PATH, PAnsiChar(string(NextLetter + ':')), nil);
         if (not BreakCycle) and DoMount then
            DefineDosDevice(DDD_RAW_TARGET_PATH, PAnsiChar(string(NextLetter + ':')), PAnsiChar('\Device\Harddisk' + IntToStr(i) + '\Partition' + IntToStr(j)));
         if BreakCycle then
            Break;
      end;
   end;
   SetErrorMode(OldMode); //restore original mode
end.

На компьютерах, которые я упомянул, это работает отлично.

Спасибо, ребята, за все ваши идеи, которые помогли мне сделать этот код.

Если кто-то заметит какие-либо ошибки или у них есть хорошие идеи о том, как их исправить, я буду рад их исправить / реализовать.

Вы можете сделать это с помощью WMI.
В библиотеке GLibWMI ( http://neftali.clubdelphi.com/?p=589 или SourceForge) вы можете найти TDiskPartitionInfo и TDiskDriveInfo.
Первый может дать вам созданные разделы и все ваши свойства.
Проверьте общий образец и проверьте результаты. На многораздельном диске вот так:
альтернативный текст

Вы получаете 4 экземпляра со свойствами 4 разделов:

альтернативный текст

Библиотека абсолютно бесплатна, а источник доступен. Проверьте образцы.
Вы можете найти другие коды для доступа к этой информации с помощью WMI. Если вы хотите использовать другой, вы можете выполнить поиск "WMI и Win32_DiskPartition Class" ( Link doc).

Извините за ошибки с английским.
С уважением

Возможно, мой инструмент командной строки Change DriveLetter поможет вам, по крайней мере, вы можете запустить его с параметрами командной строки и посмотреть, содержит ли он все тома, которые вы ожидаете.

Эта ссылка также может быть полезна: преобразование имени тома в имя устройства

Другие вопросы по тегам