AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

SSD erkennen?

Ein Thema von Mattze · begonnen am 6. Jan 2012 · letzter Beitrag vom 28. Dez 2016
 
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#7

AW: SSD erkennen?

  Alt 23. Apr 2016, 15:19
Ja, jetzt sind ja schlappe 4 Jährchen vergangen, ob Mattze immer noch über der Antwort brütet?
Jedenfalls brauchte ich auch eine funktionierende SSD-Erkennung und habe mich mal ungeniert hier bedient.
Das funktioniert auch, hat aber einen großen Pferdefuß: Man braucht Administratorrechte für das CreateFile.
Kennt jemand eine Lösung, wo es auch ohne geht? Oder ist das prinzipiell unmöglich?
Delphi-Quellcode:
uses Winapi.Windows,System.SysUtils,System.Types,System.UITypes,Vcl.Dialogs;

type
  { ATA_PASS_THROUGH_EX }
  _ATA_PASS_THROUGH_EX = packed record
    Length: Word;
    AtaFlags: Word;
    PathId: UCHAR;
    TargetId: UCHAR;
    Lun: UCHAR;
    ReservedAsUchar: UCHAR;
    DataTransferLength: ULONG;
    TimeOutValue: ULONG;
    ReservedAsUlong: ULONG;
    DataBufferOffset: ULONG_PTR;
    PreviousTaskFile: array [0..7] of UCHAR;
    CurrentTaskFile: array [0..7] of UCHAR;
  end;
  {$EXTERNALSYM _ATA_PASS_THROUGH_EX}
  ATA_PASS_THROUGH_EX = _ATA_PASS_THROUGH_EX;
  {$EXTERNALSYM  ATA_PASS_THROUGH_EX}
  TAtaPassThroughEx = _ATA_PASS_THROUGH_EX;
  PAtaPassThroughEx = ^TAtaPassThroughEx;

  { ATAIdentifyDeviceQuery }
  TATAIdentifyDeviceQuery = packed record
    header: ATA_PASS_THROUGH_EX;
    data: array [0..255] of Word;
  end;

const
{$IF RTLVersion < 22.0}
  FILE_DEVICE_CONTROLLER = $00000004;
  {$EXTERNALSYM FILE_DEVICE_CONTROLLER}

  FILE_READ_ACCESS = $0001;
  {$EXTERNALSYM FILE_READ_ACCESS}

  FILE_WRITE_ACCESS = $0002;
  {$EXTERNALSYM FILE_WRITE_ACCESS}
{$IFEND}

  ATA_FLAGS_DRDY_REQUIRED = $01;
  ATA_FLAGS_DATA_IN = $02;
  ATA_FLAGS_DATA_OUT = $04;
  ATA_FLAGS_48BIT_COMMAND = $08;
  ATA_FLAGS_USE_DMA = $10;
  ATA_FLAGS_NO_MULTIPLE = $20;

  IOCTL_SCSI_BASE = FILE_DEVICE_CONTROLLER;
  IOCTL_ATA_PASS_THROUGH = (IOCTL_SCSI_BASE shl 16) or
                            ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or
                            ($040B shl 2) or
                            (METHOD_BUFFERED);
{$IF RTLversion < 22.0}
const
  FILE_READ_DATA = $0001;
  {$EXTERNALSYM FILE_READ_DATA}

  FILE_READ_ATTRIBUTES = $0080;
  {$EXTERNALSYM FILE_READ_ATTRIBUTES}

  FILE_DEVICE_MASS_STORAGE = $0000002d;
  {$EXTERNALSYM FILE_DEVICE_MASS_STORAGE}

  IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
  {$EXTERNALSYM IOCTL_STORAGE_BASE}

  FILE_ANY_ACCESS = 0;
  {$EXTERNALSYM FILE_ANY_ACCESS}

  METHOD_BUFFERED = 0;
  {$EXTERNALSYM METHOD_BUFFERED}

  IOCTL_STORAGE_QUERY_PROPERTY = (IOCTL_STORAGE_BASE shl 16) or
                                 (FILE_ANY_ACCESS shl 14) or
                                 ($0500 shl 2) or
                                 (METHOD_BUFFERED);
  {$EXTERNALSYM IOCTL_STORAGE_QUERY_PROPERTY}
{$IFEND}

type
  { STORAGE_PROPERTY_ID }
  _STORAGE_PROPERTY_ID = (
    StorageDeviceProperty = 0,
    StorageAdapterProperty = 1,
    StorageDeviceIdProperty = 2,
    StorageDeviceUniqueIdProperty = 3,
    StorageDeviceWriteCacheProperty = 4,
    StorageMiniportProperty = 5,
    StorageAccessAlignmentProperty = 6,
    StorageDeviceSeekPenaltyProperty = 7,
    StorageDeviceTrimProperty = 8,
    StorageDeviceWriteAggregationProperty = 9,
    StorageDeviceDeviceTelemetryProperty = 10
  );
  {$EXTERNALSYM _STORAGE_PROPERTY_ID}
  STORAGE_PROPERTY_ID = _STORAGE_PROPERTY_ID;
  {$EXTERNALSYM  STORAGE_PROPERTY_ID}
  TStoragePropertyId = _STORAGE_PROPERTY_ID;
  PStoragePropertyId = ^TStoragePropertyId;

  { STORAGE_QUERY_TYPE }
  _STORAGE_QUERY_TYPE = (
    PropertyStandardQuery = 0,
    PropertyExistsQuery = 1,
    PropertyMaskQuery = 2,
    PropertyQueryMaxDefined = 3
  );
  {$EXTERNALSYM _STORAGE_QUERY_TYPE}
  STORAGE_QUERY_TYPE = _STORAGE_QUERY_TYPE;
  {$EXTERNALSYM  STORAGE_QUERY_TYPE}
  TStorageQueryType = _STORAGE_QUERY_TYPE;
  PStorageQueryType = ^TStorageQueryType;

  { STORAGE_PROPERTY_QUERY }
  _STORAGE_PROPERTY_QUERY = packed record
    PropertyId: DWORD;
    QueryType: DWORD;
    AdditionalParameters: array[0..9] of Byte;
  end;
  {$EXTERNALSYM _STORAGE_PROPERTY_QUERY}
  STORAGE_PROPERTY_QUERY = _STORAGE_PROPERTY_QUERY;
  {$EXTERNALSYM  STORAGE_PROPERTY_QUERY}
  TStoragePropertyQuery = _STORAGE_PROPERTY_QUERY;
  PStoragePropertyQuery = ^TStoragePropertyQuery;

  { DEVICE_SEEK_PENALTY_DESCRIPTOR }
  _DEVICE_SEEK_PENALTY_DESCRIPTOR = packed record
    Version: DWORD;
    Size: DWORD;
    IncursSeekPenalty: ByteBool;
    Reserved: array[0..2] of Byte;
  end;
  {$EXTERNALSYM _DEVICE_SEEK_PENALTY_DESCRIPTOR}
  DEVICE_SEEK_PENALTY_DESCRIPTOR = _DEVICE_SEEK_PENALTY_DESCRIPTOR;
  {$EXTERNALSYM  DEVICE_SEEK_PENALTY_DESCRIPTOR}
  TDeviceSeekPenaltyDescriptor = _DEVICE_SEEK_PENALTY_DESCRIPTOR;
  PDeviceSeekPenaltyDescriptor = ^TDeviceSeekPenaltyDescriptor;
    type
      { DISK_EXTENT }
      _DISK_EXTENT = packed record
        DiskNumber: DWORD;
        StartingOffset: LARGE_INTEGER;
        ExtentLength: LARGE_INTEGER;
        Reserved: array [0..3] of Byte;
      end;
      {$EXTERNALSYM _DISK_EXTENT}
      DISK_EXTENT = _DISK_EXTENT;
      {$EXTERNALSYM  DISK_EXTENT}
      TDiskExtent = _DISK_EXTENT;
      PDiskExtent = ^TDiskExtent;

      { VOLUME_DISK_EXTENTS }
      _VOLUME_DISK_EXTENTS = packed record
        NumberOfDiskExtents: DWORD;
        Reserved: array [0..3] of Byte;
        Extents: array [0..0] of DISK_EXTENT;
      end;
      {$EXTERNALSYM _VOLUME_DISK_EXTENTS}
      VOLUME_DISK_EXTENTS = _VOLUME_DISK_EXTENTS;
      {$EXTERNALSYM  VOLUME_DISK_EXTENTS}
      TVolumeDiskExtents = VOLUME_DISK_EXTENTS;
      PVolumeDiskExtents = ^TVolumeDiskExtents;

    {$IF RTLVersion < 22.0}
    const
      IOCTL_VOLUME_BASE = $00000056;
      {$EXTERNALSYM IOCTL_VOLUME_BASE}

      IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = (IOCTL_VOLUME_BASE shl 16) or
                                             (FILE_ANY_ACCESS shl 14) or
                                             (0 shl 2) or
                                             (METHOD_BUFFERED);
  {$EXTERNALSYM IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS}
{$IFEND}

function HasNominalMediaRotationRate(const PhysicalDrivePath: String): Boolean;
function HasNoSeekPenalty(const PhysicalDrivePath: String): Boolean;
procedure PathnameToPhysicalDriveNumber(const Path: String; var PhysicalDrives: TIntegerDynArray);
function IstSSD(LW:Char):Boolean;

implementation

function HasNominalMediaRotationRate(const PhysicalDrivePath: String): Boolean;
var
  h: THandle;
  ATAIdentifyDeviceQuery: TATAIdentifyDeviceQuery;
  RSize: DWORD;
begin

  h := CreateFile(PChar(PhysicalDrivePath),GENERIC_READ or GENERIC_WRITE,
                  FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
                  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if h = INVALID_HANDLE_VALUE then
  begin
    RaiseLastOSError;
  end;

  try
    FillChar(ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),0);
    with ATAIdentifyDeviceQuery do
    begin
      header.Length := SizeOf(header);
      header.AtaFlags := ATA_FLAGS_DATA_IN;
      header.DataTransferLength := SizeOf(data);
      header.TimeOutValue := 3; // sec
      header.DataBufferOffset := SizeOf(header);
      header.CurrentTaskFile[6] := $EC; // ATA IDENTIFY DEVICE command
    end;

    RSize := 0;
    if DeviceIoControl(h,IOCTL_ATA_PASS_THROUGH,
                       @ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
                       @ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
                       RSize,nil) = False then
    begin
      RaiseLastOSError;
    end;

    Result := (ATAIdentifyDeviceQuery.data[217] = 1);

  finally
    CloseHandle(h);
  end;

end;

function HasNoSeekPenalty(const PhysicalDrivePath: String): Boolean;
var
  h :THandle;
  StoragePropertyQuery: TStoragePropertyQuery;
  DeviceSeekPenaltyDescriptor: TDeviceSeekPenaltyDescriptor;
  RSize: DWORD;
begin

  h := CreateFile(PChar(PhysicalDrivePath),FILE_READ_ATTRIBUTES,
                  FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
                  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if h = INVALID_HANDLE_VALUE then
  begin
    RaiseLastOSError;
  end;

  try
    with StoragePropertyQuery do
    begin
      PropertyId := Ord(StorageDeviceSeekPenaltyProperty);
      QueryType := Ord(PropertyStandardQuery);
    end;

    FillChar(DeviceSeekPenaltyDescriptor,SizeOf(DeviceSeekPenaltyDescriptor),0);
    RSize := 0;
    if DeviceIoControl(h,IOCTL_STORAGE_QUERY_PROPERTY,
                       @StoragePropertyQuery,SizeOf(StoragePropertyQuery),
                       @DeviceSeekPenaltyDescriptor,SizeOf(DeviceSeekPenaltyDescriptor),
                       RSize,nil) = False then
    begin
      RaiseLastOSError;
    end;

    Result := not DeviceSeekPenaltyDescriptor.IncursSeekPenalty;

  finally
    CloseHandle(h);
  end;
end;

procedure PathnameToPhysicalDriveNumber(const Path: String; var PhysicalDrives: TIntegerDynArray);
var
  h: THandle;
  I: Integer;
  MountPoint: String;
  VolumeName: String;
  Size: DWORD;
  RSize: DWORD;
  P: PVolumeDiskExtents;
  lpFilePart : PWideChar;
  lpBuffer : PWideChar;
begin

  SetLength(PhysicalDrives,0);
  lpBuffer := nil;
  { Pathname to mount point }
  Size := GetFullPathName(PWideChar(Path),0,lpBuffer,lpFilePart);
  SetLength(MountPoint,Size);
  if GetVolumePathName(PAnsiChar(Path),PAnsiChar(MountPoint),Size) = False then
  begin
    RaiseLastOSError;
  end;
  SetLength(MountPoint,StrLen(PWideChar(MountPoint)));

  { Mount point to logical volume name }
  Size := 50; // Recomended size from http://msdn.microsoft.com/en-us/library/windows/desktop/aa364994.aspx
  SetLength(VolumeName,Size);
  if GetVolumeNameForVolumeMountPoint(PAnsiChar(MountPoint),PAnsiChar(VolumeName),Size) = False then
  begin
    RaiseLastOSError;
  end;
  SetLength(VolumeName,StrLen(PChar(VolumeName)));
  VolumeName := ExcludeTrailingPathDelimiter(VolumeName);

  { Open volume }
  h := CreateFile(PChar(VolumeName),FILE_READ_ATTRIBUTES,
                  FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
                  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if h = INVALID_HANDLE_VALUE then
  begin
    RaiseLastOSError;
  end;

  try
    Size := SizeOf(TVolumeDiskExtents);
    P := AllocMem(Size);
    try
      FillChar(P^,Size,0);
      RSize := 0;
      if DeviceIoControl(h,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
                         nil,0,
                         P,Size,
                         RSize,nil) = False then
      begin
        if GetLastError <> ERROR_MORE_DATA then
        begin
          RaiseLastOSError;
        end;

        Size := SizeOf(TVolumeDiskExtents) +
                SizeOf(DISK_EXTENT) * (P^.NumberOfDiskExtents - 1);
        ReallocMem(P,Size);
        FillChar(P^,Size,0);
        if DeviceIoControl(h,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
                           nil,0,
                           P,Size,
                           RSize,nil) = False then
        begin
          RaiseLastOSError;
        end;
      end;

      SetLength(PhysicalDrives,P^.NumberOfDiskExtents);
      for I := 0 to P^.NumberOfDiskExtents - 1 do
      begin
        PhysicalDrives[I] := P^.Extents[I].DiskNumber;
      end;

    finally
      FreeMem(P);
    end;

  finally
    CloseHandle(h);
  end;

end;

function IstSSD(LW:Char):Boolean;
var
  Index: Integer;
  Filename: String;
  PhysicalDrives: TIntegerDynArray;
  PhysicalDrivePath: String;
  IsSSD: Boolean;
begin
  Result := False;
  Filename := LW + ':\';
  SetLength(PhysicalDrives,0);
  PathnameToPhysicalDriveNumber(Filename,PhysicalDrives);
  try
    IsSSD := False;
    for Index := Low(PhysicalDrives) to High(PhysicalDrives) do
    begin
      PhysicalDrivePath := Format('\\.\PhysicalDrive%d',[PhysicalDrives[Index]]);
      try
        IsSSD := IsSSD or HasNominalMediaRotationRate(PhysicalDrivePath);
      except
        { Ignore }
      end;
      if IsSSD = True then
      begin
        exit(True);
      end;
    end;
  finally
    SetLength(PhysicalDrives,0);
  end;
end;

end.
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz