Помогите пожалуйста узнать размер физического носителя. Код (Text): function GetdiskSize(h:THANDLE):int64; const IOCTL_DISK_GET_DRIVE_GEOMETRY = $70000; type TDiskGeometry = packed record Cylinders: Int64; MediaType: DWORD; TracksPerCylinder: DWORD; SectorsPerTrack: DWORD; BytesPerSector: DWORD; end; var DiskGeometry:TDiskGeometry; junk:dword; begin result:=(-1); if DeviceIoControl(h,IOCTL_DISK_GET_DRIVE_GEOMETRY,nil,0, @DiskGeometry,SizeOf(TDiskGeometry),junk,nil) and (junk = SizeOf(TDiskGeometry)) then begin with DiskGeometry do Result:=Cylinders * TracksPerCylinder * SectorsPerTrack * BytesPerSector; writeln('Cylinders ', DiskGeometry.Cylinders); writeln('TracksPerCylinder ', DiskGeometry.TracksPerCylinder); writeln('SectorsPerTrack ', DiskGeometry.SectorsPerTrack); writeln('BytesPerSector ',DiskGeometry.BytesPerSector); end; end; Код (Text): hDisk:=CreateFile(PChar('\\.\PhysicalDrive0') ), GENERIC_WRITE or GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); Открываю устройство как диск, потом вызываю указанную выше функцию. Возвращяет он мне близкое к настоящему, но не точное значение. Cylinders 77825 TracksPerCylinder 255 SectorsPerTrack 63 BytesPerSector 512 640132416000 Это близко, т.к. винт на 640 Гб. Я открываю winHex этот диск, показывается следующая информаци: Емкость: 640 133 946 880 Number of cylinders 12289 Number of heads 255 Number of track 63 Bytes per sectors 512 Того у меня разница получается на 1 530 880 байт. Винхексу я больше верю, т.к. он и показывает эту физическую область, и ее можно отредактировать, переоткрыть и данные будут. Я так и не понял, как винхекс считает размер диска. Обычные АПИ функции типа GetFileSize(Ex) не помогают.. Что делать? Нужно корректно определить размер физического носителя. Игра с АПи SetFilePointer не помогла. Хотел сдвинуть ее на последнюю позицию и прочесть позицию.. Не получается.. (работает если сдвигать сначала на значение, меньшее емкости.. Тогда все корректно). Если же сдвинуть сначала на размер более емкости винта, то он так и показывает эту позицию большую...Пробовал сдвигать на -4096 от конца, ничего.. Если от начала сдвинуть вперед, то корректно показывает позицию. Гетластеррор показывает 1 (если с конца двигать). ХЗ что делать. Промониторил как работает винхекс (написал драйвер-перехватчик . После открытия устройства от шлет им DeviceIoControl: SCSI_PASS_THROUGH_DIRECT SCSI_PASS_THROUGH структуры.. Так вот, почитал описание.. (думал что там будет типа поля "размер диска".. Ну так вот, ничего подобного не нашел)... Могу посмотреть полностью структуру ДО и ПОСЛЕ вызова функции, но это мне пока мало чем помогло.. Всем спасибо. Нужно конкретно физического устройства..
IOCTL_SCSI_PASS_THROUGH_DIRECT и IOCTL_SCSI_PASS_THROUGH содержат в себе SCSI-команды, тебя интересует SCSIOP_READ_CAPACITY. Заполняй правильно один из этих ирпов с этой командой. Получишь размер физического диска в секторах и размер сектора в эндиан - формате. Был примерчик для заполнения SCSIOP_INQUIRY на работе. Там самая шляпа с ModeSense. Удачи! ЗЫ: да, и не все виртуальные устройства тебе на эту команду честно ответят!
GetDiskFreeSpace(...,...,...,...,TotalNumberOfClusters); TotalNumberOfClusters Points to variable for the total number of clusters on the disk.
max7C4, Нужно конкретно физического устройства.. А не раздела. Перед тем как запостить - испробовал функцию. Не пашет с '\\.\PhysicalDrive0'....
ams007, пока что-то не могу разобраться где содержиться SCSI команда. Судя по ДДК Код (Text): typedef struct _SCSI_PASS_THROUGH_DIRECT { USHORT Length; UCHAR ScsiStatus; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR CdbLength; UCHAR SenseInfoLength; UCHAR DataIn; ULONG DataTransferLength; ULONG TimeOutValue; PVOID DataBuffer; ULONG SenseInfoOffset; UCHAR Cdb[16]; }SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; Есть некий буфер, на который указывает DataBuffer и есть блок Cdb из 16 байт. Вот думал что я этом блоке будут и команды и данные, но нет.. Перед вызовом оригинальное функции и после - все байты в этом блоке равны нулю.. Не знаю пока что делать с DataBuffer... Может подсказочку небольшую?
Вопрос решен. Пока копался в исходниках ДДК storage\class\disk\disk.c, нашел что есть структура Код (Text): typedef struct _DISK_GEOMETRY_EX { DISK_GEOMETRY Geometry; // Standard disk geometry: may be faked by driver. LARGE_INTEGER DiskSize; // Must always be correct UCHAR Data[1]; // Partition, Detect info } DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX; Которая и выдает настоящий размер диска.. Кормим запросом IOCTL_DISK_GET_DRIVE_GEOMETRY_Ex...
test555 Зря веришь вин-хексу. Перемнож цифры и сравни. Коректный размер в CHS может быть только до дисков размером менее 16 514 064 байт согласно спецификации ATA\ATAPI-5 в последующих стандартах от CHS отказались. BIOS продержался немногим долее. Он сам начал транслировать CHS в LBA. Но регистры вдруг закончились и это произошло на 8ГБ. BIOS исходит из того что 512 байт на кластер. Один байт под головки максимум 255 головок. Секторов на дорожки максимум 63 (6 бит) . Число цилиндров максимум 1024 (8бит от одного регистра и те 2 что остались от другого) 1024*63*255*512=8 422 686 720 Что касается ошибки то просто Cylinders+1 это от биоса осталось.
Pavia, не понял, если перемножать число цилиндров, секторов и дорожек, то получается меньше чем винхекс, в придачу ты говоришь что это справедливо только для для малых винтов.
Я не знаю откуда винхекс брал эти параметры, т.к. когда моя программа считала Код (Text): Cylinders 77825 TracksPerCylinder 255 SectorsPerTrack 63 BytesPerSector 512 То получалось чуть другое значение от того что показывал винхекс... А полный размер он показывает такой же, как и дает DISK_GEOMETRY_EX... Вот.
Cdb содержит сказевую команду, Cdb[0] - опкод. завтра пример кину, просто нет у меня дома ни ддк, ни студии, ни мсдн, а было это давно... ЗЫ: я верю только в SCSI-команды, т.к. в конечном счете все дисковые устройства работают через них (disk.sys вниз шлет только их...)
Код (Text): #include "stdafx.h" #include <Windows.h> #include <WinIoCtl.h> #include <stdlib.h> #include <conio.h> #include <memory.h> #include <ntddscsi.h> // размер буфера sense info - как правило 0xa,0xb #define SENSE_B_SIZE 0xb // размер буфера данных - вроде как МАХ значение 0x100 #define TRANSFER_B_SIZE 0x100 #pragma pack(push,1) typedef union _ULONG_BT { UCHAR m_cBytes[4]; ULONG m_dwAsULONG; } ULONG_BT, *PULONG_BT; typedef union _USHORT_BT { UCHAR m_cBytes[2]; USHORT m_wAsUSHORT; } USHORT_BT, *PUSHORT_BT; // из scsi.h или ntddscsi.h typedef struct _SENSE_DATA { UCHAR ErrorCode:7; UCHAR Valid:1; UCHAR SegmentNumber; UCHAR SenseKey:4; UCHAR Reserved:1; UCHAR IncorrectLength:1; UCHAR EndOfMedia:1; UCHAR FileMark:1; UCHAR Information[4]; UCHAR AdditionalSenseLength; UCHAR CommandSpecificInformation[4]; UCHAR AdditionalSenseCode; UCHAR AdditionalSenseCodeQualifier; UCHAR FieldReplaceableUnitCode; UCHAR SenseKeySpecific[3]; } SENSE_DATA, *PSENSE_DATA; // из scsi.h или ntddscsi.h typedef struct _READ_CAPACITY_DATA { ULONG LogicalBlockAddress; ULONG BytesPerBlock; } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; #pragma pack(pop) HANDLE OpenDevice( IN PWCHAR pName) { return CreateFile( pName, GENERIC_READ |GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0x0, NULL); } LPTSTR GetStrLastError() { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); CharToOem((LPCWSTR)lpMsgBuf,(LPSTR)lpMsgBuf); return (LPTSTR)lpMsgBuf; } // крутит вертит из литл эндиан формата __inline USHORT CrvdScsiInvWORD( IN USHORT wValue) { USHORT_BT Value; USHORT_BT Result; Value.m_wAsUSHORT = wValue; Result.m_cBytes[0] = Value.m_cBytes[1]; Result.m_cBytes[1] = Value.m_cBytes[0]; return Result.m_wAsUSHORT; } // крутит вертит из биг эндиан формата __inline ULONG CrvdScsiInvDWORD( IN ULONG dwValue) { ULONG_BT Value; ULONG_BT Result; Value.m_dwAsULONG = dwValue; Result.m_cBytes[0] = Value.m_cBytes[3]; Result.m_cBytes[1] = Value.m_cBytes[2]; Result.m_cBytes[2] = Value.m_cBytes[1]; Result.m_cBytes[3] = Value.m_cBytes[0]; return Result.m_dwAsULONG; } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hDevice; PSENSE_DATA pSenseBuffer; PSCSI_PASS_THROUGH pPass; PREAD_CAPACITY_DATA pData; PUCHAR pInputBuffer; ULONG dwInputBufferSize; ULONG dwBytesReturned; BOOL fSuccess; ULONG dwSectorSize; ULONG dwSectorsAmount; // только для Х :)))) hDevice = OpenDevice(L"\\\\.\\X:"); if( INVALID_HANDLE_VALUE == hDevice ) { wprintf(L"Error open device, %s",GetStrLastError()); return 2; } dwInputBufferSize = sizeof(SCSI_PASS_THROUGH) + SENSE_B_SIZE + TRANSFER_B_SIZE; pInputBuffer = (PUCHAR)malloc(dwInputBufferSize); memset(pInputBuffer,0,dwInputBufferSize); pPass = (PSCSI_PASS_THROUGH)pInputBuffer; pPass->Length = sizeof(SCSI_PASS_THROUGH); pPass->CdbLength = 6; pPass->SenseInfoLength = SENSE_B_SIZE; pPass->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH); pPass->DataTransferLength = TRANSFER_B_SIZE; pPass->DataBufferOffset = sizeof(SCSI_PASS_THROUGH) + SENSE_B_SIZE; pPass->TimeOutValue = 15; pPass->DataIn = SCSI_IOCTL_DATA_IN; pPass->Cdb[0] = 0x25; // SCSIOP_READ_CAPACITY fSuccess = DeviceIoControl( hDevice, IOCTL_SCSI_PASS_THROUGH, pInputBuffer, dwInputBufferSize, pInputBuffer, dwInputBufferSize, &dwBytesReturned, NULL); if ( FALSE == fSuccess ) { printf("Error send cmd, error code = %d",GetLastError()); return 2; } pPass = (PSCSI_PASS_THROUGH)pInputBuffer; pData = (PREAD_CAPACITY_DATA)(pInputBuffer + sizeof(SCSI_PASS_THROUGH) + SENSE_B_SIZE); pSenseBuffer = (PSENSE_DATA)(pInputBuffer + sizeof(SCSI_PASS_THROUGH)); dwSectorsAmount = CrvdScsiInvDWORD(pData->LogicalBlockAddress); dwSectorsAmount += 1; dwSectorSize = CrvdScsiInvDWORD(pData->BytesPerBlock); printf(" Sector size == %d, Sectors amount == %d", dwSectorSize, dwSectorsAmount); free(pInputBuffer); CloseHandle(hDevice); return 0; } pData->LogicalBlockAddress содержит адрес последнего сектора на диске в эндиан формате, т.е. размер в секторах на 1цу больше. pData->BytesPerBlock содержит размер сектора в том же формате. pSenseBuffer содержит расширенную инф-ю об ошибке. Если там все нули, то гуд. Пример для 3кольца. Структуры из ддк, кроме USHORT_BT, ULONG_BT, но там есль вроде и аналоги. Также вроде есль макросы, которые делают то же самое, что и CrvdScsiInvDWORD(), CrvdScsiInvWORD(). ЗЫ: SCSI рулит!