Как получить список физических дисков и узнать их размер
Как получить список физических дисков и узнать их размер
Как вы знаете, физические диски, установленные в системе, обозначаются символическими ссылками вида "\\.\PhysicalDrive0", "\\.\PhysicalDrive1" и так далее. Однако, в WinAPI нет простых штатных функций, чтобы получить их список. Для того, чтобы сделать это, в интернетах предлагают несколько различных способов. Например, самый дуболомный, это последовательный перебор всех значений от 0 до MAX_DRIVES. В разных компиляторах это значение может меняться от 16 до 26, также не исключено, что значение может дополнительно ограничиваться системой. Дальше в цикле формируется символическая ссылка с текущим индексом и с помощью вызова CreateFile осуществляется попытка открыть это устройство. Если функция вернула ERROR_FILE_NOT_FOUND, то такого физического диска в системе нет, если ошибки нет, то ссылка доступна для использования, в противном случае диск присутствует, но по какой-то причине у вас нет к нему доступа. В принципе, это решение имеет место на существование, но есть вариант более правильный.
Список дисков хранится в ключе реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Disk\Enum в виде перечня параметров, имеющих числовые имена. Там же находится параметр Count, в котором хранится количество подключенных дисков и вспомогательный параметр NextInstance, определяющий индекс, который получит следующий подключенный диск. При подключении или отключении диска данные в реестре обновляются. Насколько я могу судить по личным наблюдениям на разных системах, нумерация физических дисков в системе всегда сквозная и непрерывная, но никто не может дать стопроцентную гарантию, что так будет всегда и везде.
Значит для получения списка всех физических дисков системы достаточно перебрать параметры указанного ключа реестра и использовать их имена в качестве числового значения в символической ссылке "\\.\PhysicalDriveX". Начнем с сегмента данных:
Code (Assembler) : Убрать нумерацию
- section '.data' code readable writeable
- szRegKey db 'SYSTEM\CurrentControlSet\Services\Disk\Enum',0
- hKey dd ? ; Хэндл открытого ключа реестра
- dValuesIndex dd ? ; Индекс при перечислении значений
- szValueName rb 100h ; Название ключа реестра
- dValueType dd ? ; Тип значения ключа реестра
- tmp dd ?
Code (Assembler) : Убрать нумерацию
- ; Открыть ветку реестра
- ; HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Disk\Enum
- invoke RegOpenKey,HKEY_LOCAL_MACHINE,szRegKey,hKey
- or eax,eax
- jnz loc_done
- ; Перебрать все значения, начиная с 0
- mov [dValuesIndex],0
- loc_scan_values:
- ; Получить значение и его тип из ключа
- mov [tmp],MAX_PATH
- invoke RegEnumValue,[hKey],[dValuesIndex],szValueName,\
- tmp,NULL,dValueType,NULL,NULL
- or eax,eax
- jnz loc_no_more_values
- ; Ключ должен иметь тип STRING
- cmp [dValueType],REG_SZ
- jne loc_next_values
- ; Ключ должен быть типа "0", "1" и т.п.
- cmp byte [szValueName],'0'
- jb loc_next_values
- cmp byte [szValueName],'9'
- ja loc_next_values
- ; В переменной szValueName имя параметра
- ...
- ; Выполнить нужные действия с найденным диском
- ...
- loc_next_values:
- ; Проверить следующее значение
- inc [dValuesIndex]
- jmp loc_scan_values
- loc_no_more_values:
- ; Закрыть ключ
- invoke RegCloseKey,[hKey]
- loc_done:
Code (Assembler) : Убрать нумерацию
- IOCTL_DISK_GET_DRIVE_GEOMETRY = 00070000h
- IOCTL_DISK_GET_LENGTH_INFO = 0007405Ch
- struct DISK_GEOMETRY
- Cylinders dd ?
- dd ?
- MediaType dd ?
- TracksPerCylinder dd ?
- SectorsPerTrack dd ?
- BytesPerSector dd ?
- ends
- struct GET_LENGTH_INFORMATION
- Length dq ?
- ends
- align 16
- diskg DISK_GEOMETRY
- align 16
- diskl GET_LENGTH_INFORMATION
- szSymLink rb 100h
Code (Assembler) : Убрать нумерацию
- ; Сформировать символическую ссылку на диск
- invoke wsprintf,szSymLink,mask,szValueName
- add esp,12
- ; Открыть устройство
- invoke CreateFile,szSymLink,GENERIC_READ,FILE_SHARE_READ,\
- 0,OPEN_EXISTING,0,0
- cmp eax,-1
- je loc_next_values
- mov ebx,eax
- ; Получить геометрию диска
- invoke DeviceIoControl,ebx,IOCTL_DISK_GET_DRIVE_GEOMETRY,\
- 0,0,diskg,sizeof.DISK_GEOMETRY,tmp,0
- ; Получить размер диска
- invoke DeviceIoControl,ebx,IOCTL_DISK_GET_LENGTH_INFO,\
- 0,0,diskl,sizeof.GET_LENGTH_INFORMATION,tmp,0
- ; Закрыть устройство
- invoke CloseHandle,ebx
Code (Assembler) : Убрать нумерацию
- ; Общее количество секторов
- xor edx,edx
- mov eax,[diskg.TracksPerCylinder]
- imul eax,[diskg.SectorsPerTrack]
- mov ecx,eax
- xor edx,edx
- mov ebx,[diskg.Cylinders]
- mul ebx
- ; Размер диска
- mov eax,ecx
- ; EAX = размер одного цилиндра в байтах
- imul eax,[diskg.BytesPerSector]
- ; Перевести в килобайты
- shr eax,10
- imul eax,[diskg.Cylinders]
- ; EAX = размер диска в килобайтах
Code (Assembler) : Убрать нумерацию
- ; Размер диска в байтах
- mov eax,dword [diskl.Length+0]
- mov edx,dword [diskl.Length+4]
- ; Перевести в килобайты
- mov ebx,1024
- div ebx
- ; EAX = размер диска в килобайтах
В приложении пример программы с исходным текстом, которая получает список физических дисков из реестра, а затем определяет их размер.
Просмотров: 5959 | Комментариев: 9
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(17.01.2018 в 08:40):
Если использовать простой перебор без чтения реестра, то будет работать и без админа.
Владимир
(13.01.2018 в 00:29):
==DJ==[ZLO] был прав, надо было просто запустить с правами Админа, тогда работает. Спасибо за программу !
rtfm
(12.01.2018 в 02:14):
По поводу последнего коммента - примеры в UserMode:
IDENTIFY_DEVICE: TxBench, Ssd-z, HddIdentifyDrive
HPA/DCO: DiskCheckup, ATATool
IDENTIFY_DEVICE: TxBench, Ssd-z, HddIdentifyDrive
HPA/DCO: DiskCheckup, ATATool
rtfm
(11.01.2018 в 16:25):
Спасибо за пример.
Для более точного решения 2-го вопроса (размер каждого найденного диска), как вариант, можно разбирать IDENTIFY_DEVICE_DATA -> CurrentSectorCapacity.
Т.е. точная емкость в KiB будет равна CurrentSectorCapacity*LBA/1024.
В этом случае, возможно, придется учитывать a) HPA; b) размер LBA (512 или 4k)
Для более точного решения 2-го вопроса (размер каждого найденного диска), как вариант, можно разбирать IDENTIFY_DEVICE_DATA -> CurrentSectorCapacity.
Т.е. точная емкость в KiB будет равна CurrentSectorCapacity*LBA/1024.
В этом случае, возможно, придется учитывать a) HPA; b) размер LBA (512 или 4k)
ManHunter
(11.01.2018 в 10:45):
На больших винтах 4+ Тб тестовая прога будет падать с ошибкой переполнения или просто молча падать. Причину я указал в статье.
==DJ==[ZLO]
(11.01.2018 в 10:30):
Спасибо! Все работает. Тестил на : win2k3,win7x86-x64,win10x64 - так же проверил на WinPE win2k3,win7x64,win10x64 Strelec. У Владимира возможно нет прав на чтения куста.
Ellephant
(11.01.2018 в 10:18):
У мну тоже показало Вынь7-64
Exit
(11.01.2018 в 06:58):
Гм, а на Win-7 x64 все запустилось и показало ))
Владимир
(10.01.2018 в 23:32):
Добрый вечер, Дмитрий,
запустил, открывается окошко, но внутри пусто, ничего не отображается.
OС: x64 Win 10. Очень хотелось бы увидеть её в действии.
Спасибо.
запустил, открывается окошко, но внутри пусто, ничего не отображается.
OС: x64 Win 10. Очень хотелось бы увидеть её в действии.
Спасибо.
Добавить комментарий
Заполните форму для добавления комментария