history | TOP |
2005/12/17:作成
overview | TOP |
まず最初に。このページの内容に独自性はありません。完全無欠にパクリです。
USERS GROUP : Delphi メーリングリスト で [Delphi:87049] ハードディスクシリアルNo という投稿があって、「GetIdeDiskSerialNumber」という関数があるらしいのですが...という質問がされていました。
Googleで検索してみると、海外の特に英語でない国のサイトばかりがヒットします。でもそこは人口言語Delphiですので、自然言語箇所は全く不明でも問題ありません。そのまま実行してみるとなにやら文字列が取得できました。
どうやったらコレがシリアル番号を意味しているかを判定する方法はわからないし、何に使うのかももう一つわからないし、Googleの「GetIdeDiskSerialNumber の検索結果 約 551 件」のおそらく全てで、同じ構造同じ変数名のサンプルコードが使いまわされていると思われ、今さら何を勝手に複製するのか微妙なところですが、いつかのために、他の全てのサイトが参照できなくなった時のために、ここにも書いておくことにします。
ただ、わかる範囲でコメントをつけることにしました。焼け石に水でしたが。構造体の定義を何処から持ってきたのかとか...。
根本的に気になる箇所が一点。
hDevice := CreateFile('\\.\Scsi0:', ...とあって、職人フォーラム::記事閲覧(一覧表示)- HDD ATA 接続デバイスから SMART の取得をする方法 にあるように、それって「SCSIデバイスに、SCSIコマンドを発行」してるんじゃないのか、と。でも今は、SCSIじゃなくて、IDEのことを話してるんじゃないのかと。
わかりません。
コード | TOP |
// [Delphi:87049] ハードディスクシリアルNo // [Delphi:87050] Re: ハードディスクシリアルNo // [Delphi:87052] Re: ハードディスクシリアルNo // GetIdeDiskSerialNumber // http://www.cdown.net/Info/32413.html // Active Delphi // http://www.activedelphi.com.br/print.php?sid=214 // DELPHI FAQ // http://delphi.cartall.com.pl/Pytania/pyt41.htm // GetIdeDiskSerialNumber でGoogle検索するとかなりの数のサイトが // ヒットするけど、どのサイトも一言一句違わず(っぽい)同じ構成。 // 最初にかきあげた誰かのコードが広まってるような感じ。 // 関係していそうなURL // Storage Devices: Windows Driver Kit // I/O Requests for Mass Storage Drivers // http://msdn.microsoft.com/library/default.asp? // url=/library/en-us/Storage_r/hh/Storage_r/k307_4cd1d823-5899-43f9-8076-3ebd8dfe97ba.xml.asp unit HddSerial; interface // (名前からして)IDEのHDDのシリアル#を取得する関数 function GetIdeDiskSerialNumber(): String; implementation uses Windows, SysUtils; type //------------------------------------------------------------------------- // Storage Devices: Windows DDK // SRB_IO_CONTROL // http://msdn.microsoft.com/library/default.asp? // url=/library/en-us/storage/hh/storage/structs-scsibus_d7cd0432-d4be-4609-a3f9-91ef842caf7e.xml.asp // This structure is used by applications to send requests directly to an // application-dedicated HBA. Note that such an application also must set // up requests to program its dedicated HBA. TSrbIoControl = packed record HeaderLength : ULONG; Signature : array[0..7] of Char; Timeout : ULONG; ControlCode : ULONG; ReturnCode : ULONG; Length : ULONG; end; SRB_IO_CONTROL = TSrbIoControl; PSrbIoControl = ^TSrbIoControl; //------------------------------------------------------------------------- // Storage Devices: Windows Driver Kit // IDEREGS // http://msdn.microsoft.com/library/default.asp? // url=/library/en-us/Storage_r/hh/Storage_r/structs-IDE_aeab294c-9363-4207-bbcb-d9d442ab5c92.xml.asp // The IDEREGS structure is used to report the contents of the IDE controller // registers TIDERegs = packed record bFeaturesReg : Byte; // Used for specifying SMART "commands". bSectorCountReg : Byte; // IDE sector count register bSectorNumberReg : Byte; // IDE sector number register bCylLowReg : Byte; // IDE low order cylinder value bCylHighReg : Byte; // IDE high order cylinder value bDriveHeadReg : Byte; // IDE drive/head register bCommandReg : Byte; // Actual IDE command. bReserved : Byte; // reserved. Must be zero. end; IDEREGS = TIDERegs; PIDERegs = ^TIDERegs; //------------------------------------------------------------------------- // Storage Devices: Windows DDK // SENDCMDINPARAMS // http://msdn.microsoft.com/library/default.asp? // url=/library/en-us/storage/hh/storage/structs-IDE_b80faf9d-dfcf-4eac-b0be-fb18964c4c2b.xml.asp // The SENDCMDINPARAMS structure contains the input parameters for the // SMART_SEND_DRIVE_COMMAND request. // The SMART_SEND_DRIVE_COMMAND is used to send a Self-Monitoring Analysis // and Reporting Technology (SMART) commands to a device. TSendCmdInParams = packed record cBufferSize : DWORD; irDriveRegs : TIDERegs; bDriveNumber : Byte; bReserved : array[0..2] of Byte; dwReserved : array[0..3] of DWORD; bBuffer : array[0..0] of Byte; end; SENDCMDINPARAMS = TSendCmdInParams; PSendCmdInParams = ^TSendCmdInParams; //------------------------------------------------------------------------- TIdSector = packed record wGenConfig : Word; wNumCyls : Word; wReserved : Word; wNumHeads : Word; wBytesPerTrack : Word; wBytesPerSector : Word; wSectorsPerTrack : Word; wVendorUnique : array[0..2] of Word; sSerialNumber : array[0..19] of Char; wBufferType : Word; wBufferSize : Word; wECCSize : Word; sFirmwareRev : array[0..7] of Char; sModelNumber : array[0..39] of Char; wMoreVendorUnique : Word; wDoubleWordIO : Word; wCapabilities : Word; wReserved1 : Word; wPIOTiming : Word; wDMATiming : Word; wBS : Word; wNumCurrentCyls : Word; wNumCurrentHeads : Word; wNumCurrentSectorsPerTrack : Word; ulCurrentSectorCapacity : ULONG; wMultSectorStuff : Word; ulTotalAddressableSectors : ULONG; wSingleWordDMA : Word; wMultiWordDMA : Word; bReserved : array[0..127] of Byte; end; PIdSector = ^TIdSector; const IDE_ID_FUNCTION = $EC; IDENTIFY_BUFFER_SIZE = 512; DFP_RECEIVE_DRIVE_DATA = $0007c088; IOCTL_SCSI_MINIPORT = $0004d008; IOCTL_SCSI_MINIPORT_IDENTIFY = $001b0501; DataSize = SizeOf(TSendCmdInParams) -1 + IDENTIFY_BUFFER_SIZE; BufferSize = SizeOf(SRB_IO_CONTROL) + DataSize; W9xBufferSize = IDENTIFY_BUFFER_SIZE + 16; //----------------------------------------------------------------------------- // バイトオーダー変更 procedure ChangeByteOrder(var Data; const Size: Integer); var ptr: PChar; i: Integer; c: Char; begin ptr := @Data; for i := 0 to (Size shr 1) - 1 do begin c := ptr^; ptr^ := (ptr + 1)^; (ptr + 1)^ := c; Inc(ptr, 2); end; end; //----------------------------------------------------------------------------- // IDEのHDDのシリアル#を取得する function GetIdeDiskSerialNumber(): String; var hDevice: THandle; cbBytesReturned: DWORD; pInData: PSendCmdInParams; pOutData: Pointer; // PSendCmdOutParams Buffer: array[0..BufferSize-1] of Byte; srbControl: TSrbIoControl absolute Buffer; // absolute で他の変数(この場合Buffer)と同じアドレスを持つ変数を宣言できる begin // 空文字で初期化 Result := ''; // バッファを初期化 FillChar(Buffer, BufferSize, #0); //--------------------------------------------------------------- // Windows NT, Windows 2000 の場合 //--------------------------------------------------------------- if (Win32Platform = VER_PLATFORM_WIN32_NT) then begin // Get SCSI port handle hDevice := CreateFile('\\.\Scsi0:', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); // ハンドル取れなければ中止 if (hDevice = INVALID_HANDLE_VALUE) then Exit; try srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL); System.Move('SCSIDISK', srbControl.Signature, 8); srbControl.Timeout := 2; srbControl.Length := DataSize; srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY; pInData := PSendCmdInParams(PChar(@Buffer) + SizeOf(SRB_IO_CONTROL)); pOutData := pInData; with pInData^ do begin cBufferSize := IDENTIFY_BUFFER_SIZE; bDriveNumber := 0; with irDriveRegs do begin bFeaturesReg := 0; bSectorCountReg := 1; bSectorNumberReg := 1; bCylLowReg := 0; bCylHighReg := 0; bDriveHeadReg := $A0; bCommandReg := IDE_ID_FUNCTION; end; end; // デバイスドライバへ制御コードを直接送信 // http://www.microsoft.com/japan/msdn/library/default.asp? // url=/japan/msdn/library/ja/jphard/html/_win32_DeviceIoControl.asp if not DeviceIoControl( hDevice, // デバイスハンドル IOCTL_SCSI_MINIPORT, // 実行する動作の制御コード @Buffer, // 入力バッファのポインタ BufferSize, // 入力バッファのバイトサイズ @Buffer, // 出力バッファのポインタ BufferSize, // 出力バッファのバイトサイズ cbBytesReturned, // バイト数を受け取る変数へのポインタ nil) // 非同期動作を表す構造体へのポインタ then Exit; finally CloseHandle(hDevice); end; end //--------------------------------------------------------------- // Windows 95 OSR2, Windows 98 の場合 //--------------------------------------------------------------- else begin hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0); if (hDevice = INVALID_HANDLE_VALUE) then Exit; try pInData := PSendCmdInParams(@Buffer); pOutData := @pInData^.bBuffer; with pInData^ do begin cBufferSize := IDENTIFY_BUFFER_SIZE; bDriveNumber := 0; with irDriveRegs do begin bFeaturesReg := 0; bSectorCountReg := 1; bSectorNumberReg := 1; bCylLowReg := 0; bCylHighReg := 0; bDriveHeadReg := $A0; bCommandReg := IDE_ID_FUNCTION; end; end; if not DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, pInData, SizeOf(TSendCmdInParams) - 1, pOutData, W9xBufferSize, cbBytesReturned, nil) then Exit; finally CloseHandle(hDevice); end; end; //--------------------------------------------------------------- // 共通 //--------------------------------------------------------------- with PIdSector(PChar(pOutData) + 16)^ do begin ChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber)); SetString(Result, sSerialNumber, SizeOf(sSerialNumber)); end; // 末尾のNULLをはつる Result := Trim(Result); end; end.
使い方 | TOP |
こんな感じで。
uses HDDSerial; procedure TForm1.FormCreate(Sender: TObject); begin ShowMessage(GetIdeDiskSerialNumber()); end;
実行結果 | TOP |
上の使い方をそのまま実行したら、シリアル番号らしき文字列を表示します(下のは、ダイアログを CTRL+C でコピったものです。念のため。別にみられてもよさそうなので、コピってそのまま貼り付けてます)。
--------------------------- Project1 --------------------------- 0191J1FN200091 --------------------------- OK ---------------------------
EOF | TOP |