отображение разделов, начиная с PhysicalDrive - PullRequest
0 голосов
/ 12 января 2011

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

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

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

Ответы [ 3 ]

3 голосов
/ 14 января 2011

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

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.

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

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

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

2 голосов
/ 13 января 2011

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

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

alt text

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

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

1 голос
/ 12 января 2011

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

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

...