Как это сделать через WMI я вроде разобрался.

Только не нравиться мне, что приходится перебирать в цикле все свойства

Win32_CDROMDrive. Может кто знает как сразу к конкретному свойству обратиться, т.е.

избавиться от строки "while PropEnum.Next(1, TempObj, Value) = S_OK do"

 

Вот рабочий пример для D7.

CD может иметь или не иметь серийный номер и/или универсальный код продукта (Universal Product Code). MCI-расширение Windows предоставляет эту информации с помощью комманды MCI_INFO_MEDIA_IDENTITY command. Эта команда возвращает уникальную ID-строку.

Пример:

Теперь об информации о дисках:

 

исчерпывающую информацию по этому поводу дает функция GetVolumeInformation,

посмотри help, там все понятно (там и серийный номер диска, и тип файловой системы, и прочее и прочее).

 

Вот параметры FileSysFlags:

 

Некоторые приложения должны знать, когда пользователь вставляет или  удаляет компакт-диска или DVD-диска с компакт-дисков без

 опрос для медиа-изменений. Windows предоставляет способ уведомить об этом  приложения через сообщение WM_DEVICECHANGE.

 

Посмотри функцию DeviceIoControl - может там что получиться. Я ее мало использовал, но что-то там было.

 Там есть ссылка на CreateFile - эта функция под NT может действительно вернуть хэндл на физический диск.

 You can use the CreateFile function to open a disk drive or a partition on a disk drive. The function returns a handle to the disk device; that handle can be used with the DeviceIOControl function.

 Автор AntonSaburov

 Поличение серийного номера IDE диска.

Вступление

 Наконец, я решился на написание этой статьи, идея пришла давно, но полностью систематизировать решился только сегодня. Сегодня мы не будем рассматривать конкретного взлома. На это есть две причины:

 1) У меня начал глючить CD-ROM, пора менять

2) Статья получилась бы слишком длинной

 В принципе вторая причина меня волнует мало, но первая встала доста- точно остро.

 

 

 

Code:

const

{©Drkb v.3}

 

FILE_DEVICE_FILE_SYSTEM: Integer = $00000009;

METHOD_BUFFERED: Integer = $00000000;

FILE_ANY_ACCESS: Integer = $00000000;

 

function CTL_CODE(DeviceType, FunctionNo, Method, Access: Integer): Integer;

begin

Result := (DeviceType shl 16) or (Access shl 14) or (FunctionNo shl 2) or (Method);

end;

 

procedure TForm1.Button1Click(Sender: TObject);

var

LHandle: THandle;

BytesReturned: Cardinal;

MsgBuf: PChar;

FSCTL_LOCK_VOLUME: Integer;

begin

FSCTL_LOCK_VOLUME := CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6,

                                                 METHOD_BUFFERED, FILE_ANY_ACCESS);

LHandle := CreateFile('\\.\A:', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ

                     or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or

                     FILE_FLAG_DELETE_ON_CLOSE, 0);

if LHandle <> 0 then

begin

  if DeviceIOControl(LHandle, FSCTL_LOCK_VOLUME, nil, 0, nil, 0, BytesReturned, nil) then

    ShowMessage('Дисковод заблокирован. Нажмите ОК для разблокирования.')

  else

  begin

    if FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER or

         FORMAT_MESSAGE_FROM_SYSTEM, nil, GetLastError(), 0, @MsgBuf, 0, nil) > 0 then

    begin

      ShowMessage('Ошибка DeviceIOControl: ' + MsgBuf);

      LocalFree(Cardinal(MsgBuf));

    end

    else

      ShowMessage('Ошибка при вызове DeviceIOControl!');

  end;

  CloseHandle(LHandle);

end

else

  ShowMessage('Ошибка при вызове CreateFile!');

end;

 

 

Code:

function DriveExists (Drive: Byte) : boolean;

begin

Result := Boolean (GetLogicalDrives and (1 shl Drive));

end;

 

procedure TForm1.Button1Click(Sender : TObject);

var Drive : byte;

begin

for Drive := 0 to 25 do

If DriveExists (Drive) then

begin

ListBox1.Items.Add (Chr(Drive+$41));

end;

end;

 

 

Code:

program ScsiSN;

 

// PURPOSE: Simple console application that display SCSI harddisk serial number

 

{$APPTYPE CONSOLE}

 

uses

Windows, SysUtils;

 

//-------------------------------------------------------------

 

function GetDeviceHandle(sDeviceName: string): THandle;

begin

Result := CreateFile(PChar('\\.\' + sDeviceName),

   GENERIC_READ or GENERIC_WRITE,

   FILE_SHARE_READ or FILE_SHARE_WRITE,

   nil, OPEN_EXISTING, 0, 0)

end;

 

//-------------------------------------------------------------

 

function ScsiHddSerialNumber(DeviceHandle: THandle): string;

{$ALIGN ON}

type

TScsiPassThrough = record

   Length: Word;

   ScsiStatus: Byte;

   PathId: Byte;

   TargetId: Byte;

   Lun: Byte;

   CdbLength: Byte;

   SenseInfoLength: Byte;

   DataIn: Byte;

   DataTransferLength: ULONG;

   TimeOutValue: ULONG;

   DataBufferOffset: DWORD;

   SenseInfoOffset: ULONG;

   Cdb: array[0..15] of Byte;

end;

TScsiPassThroughWithBuffers = record

   spt: TScsiPassThrough;

   bSenseBuf: array[0..31] of Byte;

   bDataBuf: array[0..191] of Byte;

end;

{ALIGN OFF}

var

dwReturned: DWORD;

len: DWORD;

Buffer: array[0..SizeOf(TScsiPassThroughWithBuffers) +

SizeOf(TScsiPassThrough) - 1] of Byte;

sptwb: TScsiPassThroughWithBuffers absolute Buffer;

begin

Result := '';

FillChar(Buffer, SizeOf(Buffer), #0);

with sptwb.spt do

begin

   Length := SizeOf(TScsiPassThrough);

   CdbLength := 6; // CDB6GENERIC_LENGTH

   SenseInfoLength := 24;

   DataIn := 1; // SCSI_IOCTL_DATA_IN

   DataTransferLength := 192;

   TimeOutValue := 2;

   DataBufferOffset := PChar(@sptwb.bDataBuf) - PChar(@sptwb);

   SenseInfoOffset := PChar(@sptwb.bSenseBuf) - PChar(@sptwb);

   Cdb[0] := $12; // OperationCode := SCSIOP_INQUIRY;

   Cdb[1] := $01; // Flags := CDB_INQUIRY_EVPD;  Vital product data

   Cdb[2] := $80; // PageCode            Unit serial number

   Cdb[4] := 192; // AllocationLength

end;

len := sptwb.spt.DataBufferOffset + sptwb.spt.DataTransferLength;

if DeviceIoControl(DeviceHandle, $0004D004, @sptwb, SizeOf(TScsiPassThrough),

   @sptwb, len, dwReturned, nil)

   and ((PChar(@sptwb.bDataBuf) + 1)^ = #$80) then

   SetString(Result, PChar(@sptwb.bDataBuf) + 4,

     Ord((PChar(@sptwb.bDataBuf) + 3)^));

end;

 

/=============================================================

var

hDevice: THandle = 0;

sSerNum, sDeviceName: string;

 

begin

sDeviceName := ParamStr(1);

if sDeviceName = '' then

begin

   WriteLn;

   WriteLn('Display SCSI-2 device serial number.');

   WriteLn;

   WriteLn('Using:');

   WriteLn;

   if Win32Platform = VER_PLATFORM_WIN32_NT then // Windows NT/2000

     WriteLn('  ScsiSN PhysicalDrive0')

   else

     WriteLn('  ScsiSN C:');

   WriteLn('  ScsiSN Cdrom0');

   WriteLn('  ScsiSN Tape0');

   WriteLn;

   Exit;

end;

hDevice := GetDeviceHandle(sDeviceName);

if hDevice = INVALID_HANDLE_VALUE then

   WriteLn('Error on GetDeviceHandle: ', SysErrorMessage(GetLastError))

else

try

   sSerNum := ScsiHddSerialNumber(hDevice);

   if sSerNum = '' then

     WriteLn('Error on DeviceIoControl: ',

       SysErrorMessageGetLastError))

else

WriteLn('Device ' + sDeviceName

   + ' serial number = "', sSerNum, '"');

finally

CloseHandle(hDevice);

end;

end.

 

Часть информации о диске можно получить при помощи функции GetVolumeInformation. Она позволяет узнать метку, тип файловой системы, серийный номер, максимальную длину имен файлов, а также несколько параметров, связанных с регистром букв в именах файлов, сжатием информации и др.

Для определения типа диска используется функция GetDriveType. Для определения объема диска и свободного пространства - GetDiskFreeSpaceEx. Для определения размера кластера и сектора можно использовать GetDiskFreeSpace. Здесь это не используется.

 

Code:

procedure TForm1.Button1Click(Sender: TObject);

var

VolumeName,

FileSystemName : array [0..MAX_PATH-1] of Char;

VolumeSerialNo : DWord;

MaxComponentLength,

FileSystemFlags : Integer;

begin

GetVolumeInformation('C:\',VolumeName,MAX_PATH,@VolumeSerialNo,

MaxComponentLength,FileSystemFlags,

FileSystemName,MAX_PATH);

Memo1.Lines.Add('VName = '+VolumeName);

Memo1.Lines.Add('SerialNo = $'+IntToHex(VolumeSerialNo,8));

Memo1.Lines.Add('CompLen = '+IntToStr(MaxComponentLength));

Memo1.Lines.Add('Flags = $'+IntToHex(FileSystemFlags,4));

Memo1.Lines.Add('FSName = '+FileSystemName);

end;