Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   SSD erkennen? (https://www.delphipraxis.net/165571-ssd-erkennen.html)

Mattze 6. Jan 2012 09:12

SSD erkennen?
 
Hallo,

sicher schon mal gefragt, aber ich finde nix.

Wie erkennt man im Programm eigentlich sicher, dass man es mit einer SSD zu tun hat?

(D7pro, Win7 64)

Danke!
Mattze

bernerbaer 6. Jan 2012 13:18

AW: SSD erkennen?
 
_Ich_ denke, dass es dazu keine allgemein gültige Lösung gibt, da SSDs sich als Festplatten ausgeben. Vermutlich musst du über Umwege rausfinden zu versuchen, ob es sich um eine SSD-HD handelt. Anbieten würde sich da z.B.
  • Ermitteln der Zugriffszeit
  • ermitteln der Geschwindigkeit
oder du führst intern eine Liste mit allen Gerätekennungen von SSD-Festplatten und liest SMART aus und vergleichst mit deiner Liste.

himitsu 6. Jan 2012 13:29

AW: SSD erkennen?
 
Jupp, es gibt zwar einige standardisierte IDE-Befehle für SSDs, wie z.B. TRIM, aber nicht in allen SSDs sind diese implementiert.

PS: Es gibt auch Möglichkeiten um Speicherkarten via IDE anzuschließen. (quasi der Vorfahre von SSD)
z.B. die Compact-Flash-Karten oder SD-Karten
Die sind ja auch nicht sooo langsam, so daß es da mit dem Erkennen, über die Zugriffszeiten nicht so einfach aussieht.

DanielProgramming 6. Jan 2012 13:47

AW: SSD erkennen?
 
Hallo,

Kollege von mir meinte vor kurzem SSDs geben bei der Rotationsgeschwindigkeit 0 an wenn man diese abfragt, vielleicht wäre das ja ein Ansatzpunkt für Dich. Bin da nicht weiter drauf eingegangen, empfand es aber als logisch, da drin rotiert ja nix:idea:

bernerbaer 6. Jan 2012 14:06

AW: SSD erkennen?
 
Zitat:

Zitat von DanielProgramming (Beitrag 1144667)
Hallo,

Kollege von mir meinte vor kurzem SSDs geben bei der Rotationsgeschwindigkeit 0 an wenn man diese abfragt, vielleicht wäre das ja ein Ansatzpunkt für Dich. Bin da nicht weiter drauf eingegangen, empfand es aber als logisch, da drin rotiert ja nix:idea:

ja, das stimmt vermutlich, ist aber vermutlich kein ausschliessliches Erkennungsmerkmal, auch andere Medien haben Rotationsgeschwindigkeit 0. (Hast du z.b. schon mal die Rotationsgeschwindigkeit eines Raid 0 Systems mit normalen Festplatten ermittelt?)

devidespe 6. Jan 2012 15:24

AW: SSD erkennen?
 
Ja, die Rotationsgeschwindigkeit ist das Stichwort. Windows 7 deaktiviert die automatische Datenträgerdefragmentierung für ein Laufwerk, sobald die Rotationsgeschwindigkeit 0 beträgt. Das hat auch den Huintergrund, dass eine Defragmentierung bei SSD's und USB-Sticks eher kontraproduktiv ist.

Luckie 6. Jan 2012 15:29

AW: SSD erkennen?
 
Wozu musst du denn das wissen?

bernerbaer 6. Jan 2012 15:36

AW: SSD erkennen?
 
Zitat:

Zitat von devidespe (Beitrag 1144683)
... Das hat auch den Huintergrund, dass eine Defragmentierung bei SSD's und USB-Sticks eher kontraproduktiv ist.

[OT]Das kann man so nicht pauschalisieren. Es gibt SSD-Hersteller die eine Defragmentierung von SSDs sogar empfehlen (siehe Wikipedia)[/OT]

DanielProgramming 6. Jan 2012 15:39

AW: SSD erkennen?
 
Zitat:

Zitat von bernerbaer (Beitrag 1144673)
(Hast du z.b. schon mal die Rotationsgeschwindigkeit eines Raid 0 Systems mit normalen Festplatten ermittelt?)

Nein und da du so fragst nehme ich an man bekommt keinen Mittelwert von den beteiligten Platten sondern auch 0:-D

bernerbaer 6. Jan 2012 15:40

AW: SSD erkennen?
 
Zitat:

Zitat von DanielProgramming (Beitrag 1144688)
Zitat:

Zitat von bernerbaer (Beitrag 1144673)
(Hast du z.b. schon mal die Rotationsgeschwindigkeit eines Raid 0 Systems mit normalen Festplatten ermittelt?)

Nein und da du so fragst nehme ich an man bekommt keinen Mittelwert von den beteiligten Platten sondern auch 0:-D

genau!

Mattze 6. Jan 2012 16:40

AW: SSD erkennen?
 
Hallo,

vielen Dank für Eure Antworten.
Es ist eigentlich nur Interesse und für meinen Versuch, die Hardware auszulesen.
Ich wusste nicht, was ich damit lostrete!

Ich war eben nur recht verblüfft, als O&O Defrag 12 prof beim (testweisen) Aufruf der SSD gleich ausgab, dass das eine SSD sei und die nicht defragmentiert werden sollte. Und schon kam die Frage: Woher weiß O&O das?
Da das ja auch bei allen SSD funktionieren sollte, dachte ich da wirklich, dass es einen allgemeinen Hinweis (z. B. im Controller) gibt!

Nebenbei: Es gibt eine Reihe Statusprogramme für SSD (z. B. SSD Life free). Die bieten schon bei der Laufwerkswahl nur SSDs an.
Also müssen die das auch irgendwie mitkriegen. Nur: Wie? Nur über die Rotationsgeschwindigkeit würde ja offenbar auch nicht ganz richtig werden.

Trotzdem, ein guter Ansatz ist das allemale.

Bevor ich nun anfange zu suchen, wie ermittelt man die Rotationsgeschwindigkeit?

Gruß
Mattze

himitsu 6. Jan 2012 16:41

AW: SSD erkennen?
 
Zitat:

Zitat von bernerbaer (Beitrag 1144687)
[OT]Das kann man so nicht pauschalisieren. Es gibt SSD-Hersteller die eine Defragmentierung von SSDs sogar empfehlen (siehe Wikipedia)[/OT]

Auf die Ausführungsgeschwindigkeit hat dieses wirklich keinen Einfluß mehr, aber auf die Datensicherheit hat es das sehr wohl.

Komplett defekte Datenträger kann man zwar vergessen, aber sobal man noch Lesezugriff bekommt, könnten Datenwiederherstellungsprogramme zusammenhängende Dateien besser wiederherstellen.
(vorallem wenn Volumebitmaps und Co. defekt sind)



PS: Wenn man für SSDs im Programm Optimierungen verbaut hat, warum das dann nicht einfach den Benutzer einstellen lassen?

Morphie 6. Jan 2012 17:28

AW: SSD erkennen?
 
Ich habe mal irgendwo gelesen, dass sich SSDs als RAM-Drive anmelden.
GetDriveType müsste bei einer SSD also DRIVE_RAMDISK (6) ausgeben.

Habe aber leider keine SSD um das zu testen.

Insider2004 6. Jan 2012 17:34

AW: SSD erkennen?
 
SSD defragmentieren? Bald kommt der Osterhase!

samso 6. Jan 2012 17:39

AW: SSD erkennen?
 
Also bei mir nicht: GetDriveType('C:\') ergibt 3 = dtFixed

himitsu 6. Jan 2012 18:40

AW: SSD erkennen?
 
Wieso sollten die ein RAM-Drive sein?
Das sind spezielle Treiber, für virtuelle Laufwerke.

SSD sind an IDE/SATA angeschlossen und werden auch über die normalen Festplattentreiber angesprochen.

Mattze 7. Jan 2012 07:13

AW: SSD erkennen?
 
Hallo,

inzwischen habe ich zwar ziemlich gesucht, aber ich finde nix.
Wie liest man die Rotationsgeschwindigkeit einer Festplatte im Code aus?

Soweit ich das gelesen habe, kann Win 7, laut MS, keine SSD im RAID erkennen.
Das deutet darauf hin, dass die wirklich über die Rotationsgeschwindigkeit gehen!
Und dann noch Raid testen.
Geschwindigkeit = 0, kein RAID --> SSD
Geschwindigkeit = 0, RAID --> als HDD erkannt und angesprochen.

Gruß
Mattze

hathor 7. Jan 2012 09:11

AW: SSD erkennen?
 
Non-rotating media
Windows 7 detects SSDs by using ATA8-ACS identify word 217: Nominal media rotation rate, with value 0001h as Non-rotating media like solid state devices. But not all SSDs adhere to the ATA8-ACS1 spec section 7.16.7.77, some may need firmware updates.

Seek Time
Unlike a magnetic rotating disk, the SSD has no read/write heads or platter. There is no seek time or
rotational latency issues. Zeus SSDs dramatically improve transaction throughput, particularly for
applications that are configured to take advantage of the characteristics of the drive.

WINDOWS 7
The random read threshold test was added to the final product to address the fact that few SSDs on the market today properly identify themselves as SSDs. 8 MB/sec is a relatively conservative rate. While none of our tested HDDs could approach 8 MB/sec, all of our tested SSDs exceeded that threshold. SSD performance ranged between 11 MB/sec and 130 MB/sec. Of the 182 HDDs tested, only 6 configurations managed to exceed 2 MB/sec on our random read test. The other 176 ranged between 0.8 MB/sec and 1.6 MB/sec.
http://blogs.msdn.com/b/e7/archive/2...rives-and.aspx

Mattze 7. Jan 2012 09:31

AW: SSD erkennen?
 
Vielen Dank, hathor.
Das ist doch schon was.

Nun müsste ich nur noch wissen, wie ich das ATA8-ACS, Word 217 mit Delphi (7 pro) auslesen kann. Hast Du einen Tipp?

Und die Frage ganz allgemein, weil es mich interessiert, wie man die Rotationsgeschwindigkeit einer Platte auslesen kann.

Danke!
Mattze

jaenicke 7. Jan 2012 09:37

AW: SSD erkennen?
 
Hier übrigens die passende ATA Spezifikation T13/e06176r1, die du hier in der Liste findest:
http://t13.org/Documents/MinutesDefa...DocumentType=8
Der direkte Link:
http://www.t13.org/Documents/Uploade...orm_factor.doc

Auslesen kannst du das mit DeviceIoControl und IOCTL_ATA_PASS_THROUGH. ;-)

Mattze 7. Jan 2012 09:49

AW: SSD erkennen?
 
Vielen Dank und Au-weiha!
Ich werde wohl langsam alt!

Vielleicht nicht direkt das, aber mit diesen Dingen habe ich doch schon gearbeitet
als ich die ganzen Speicher und deren Herstellerbezeichnung (und ein paar Daten) auslesen wollte.

Ich muss dringend etwas tun, damit mein Hirn nicht ganz einrostet!

Gruß
Mattze

Mattze 28. Mär 2012 17:32

AW: SSD erkennen?
 
Hallo,

ich komme leider erst jetzt wieder dazu, mich damit weiter zu beschäftigen und...
ich finde es nicht!
Ich kriege die Rotationsgeschwindigkeit einfach nicht raus.
Irgendwann, als ich mich mit DeviceIoControl näher beschäftigt habe, habe ich mal etwas davon gelesen - bin ich mir sicher.
Nun finde ich es nicht mehr. In der Struktur für IOCTL_ATA_PASS_THROUGH finde ich auch nix.
Für einen kleiner Tipp wäre ich dankbar.

Gruß
Mattze

Benmik 23. Apr 2016 15:19

AW: SSD erkennen?
 
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.

t.roller 23. Apr 2016 18:52

AW: SSD erkennen?
 
Es gibt S.M.A.R.T.-Werte, die nur bei SSD vorhanden sind, z.B.
230, E6, Drive Life Protection Status:
100 (protection is not active) oder 90 (protection is active)
231, E7, SSD Life Left 1-100 %
Info:
MKP_306_SMART_attribute.pdf

Benmik 23. Apr 2016 19:04

AW: SSD erkennen?
 
Leider ist es so, dass sich die Hersteller nicht an standardisierte S.M.A.R.T.-Werte halten. Bei der hier untersuchten SSD fehlt die 231 zum Beispiel einfach.

Shark99 30. Mai 2016 17:45

AW: SSD erkennen?
 
Ich habe den Code von Benmik getestet und merkwürdigerweise funktioniert er nur auf meinem Windows 10 PC. Auf einem Windows 7 PC mit der gleichen SSD bekomme ich hier:
Delphi-Quellcode:
    if DeviceIoControl(h,IOCTL_ATA_PASS_THROUGH,
                       @ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
                       @ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
                       RSize,nil) = False then
    begin
      RaiseLastOSError;
    end;
den Fehler: The program issued a command but the command length is incorrect.

Ich vermute dass diese Struktur:
Delphi-Quellcode:
 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);
nicht ganz richtig ist.

Für Hilfe wäre ich dankbar.

Shark99 30. Mai 2016 18:40

AW: SSD erkennen?
 
Hab einen Fix gefunden:
Delphi-Quellcode:
  { ATAIdentifyDeviceQuery }
  TATAIdentifyDeviceQuery = packed record
    header: ATA_PASS_THROUGH_EX;
    data: array [0..8191] of Word;
  end;

Mattze 31. Mai 2016 05:20

AW: SSD erkennen?
 
Hallo,

so mache ich das nun seit langer Zeit auch.
Allerdings reichen bei mir 255 Worte.

Delphi-Quellcode:
// 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;
Bisher hatte ich damit keine Probleme (Win 7, 8, 8.1, 10. Alles pro und 64Bit. Übersetzt mit Delphi 7 pro, also 32 Bit)

Gruß
Mattze

Benmik 5. Jun 2016 13:22

AW: SSD erkennen?
 
Aber an der Notwendigkeit der Administratorrechte hat sich nichts geändert?

t.roller 5. Jun 2016 15:52

AW: SSD erkennen?
 
Ab WINDOWS8 gibt es über WMI mehr Informationen, siehe:

MSFT_PhysicalDisk class

MediaType
Data type: UInt16
Access type: Read-only
The media type of the physical disk.
Value Meaning
0 Unspecified
3 HDD
4 SSD

SpindleSpeed
Data type: UInt32
Access type: Read-only
Qualifiers: Required, Units ("RPM")
The rotational speed of spindle-based physical disks. For solid
state devices (SSDs) or other non-rotational media, this member
should be set to 0. For rotating media that has an unknown speed,
this member should be set to 0xFFFFFFFF (UINT32_MAX).

Beispiel geht auch OHNE Administrator-Rechte und bei USB-Disks.
Delphi-Quellcode:
//     This code was generated by the Wmi Delphi Code Creator http://theroadtodelphi.wordpress.com
//     Version: 1.8.3.0
//     LIABILITY DISCLAIMER
//     THIS GENERATED CODE IS DISTRIBUTED "AS IS". NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED.
//     YOU USE IT AT YOUR OWN RISK. THE AUTHOR NOT WILL BE LIABLE FOR DATA LOSS,
//     DAMAGES AND LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING OR MISUSING THIS CODE.
program WMI_PhysicalDisk;

{$APPTYPE CONSOLE}

uses
 // SysUtils, ActiveX, ComObj, Variants;
  System.SysUtils,
  Winapi.ActiveX,
  System.Win.ComObj,
  System.Variants;

function VarToInt(const AVariant: Variant): INT64;// integer;
begin Result := StrToIntDef(Trim(VarToStr(AVariant)), 0); end;

procedure GetMSFT_PhysicalDiskInfo;
const
  WbemUser =''; WbemPassword =''; WbemComputer ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService  : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject  : OLEVariant;
  oEnum        : IEnumvariant;
  iValue       : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService  := FSWbemLocator.ConnectServer(WbemComputer, 'root\Microsoft\Windows\Storage', WbemUser, WbemPassword);
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM MSFT_PhysicalDisk','WQL',wbemFlagForwardOnly);
  oEnum        := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('AllocatedSize                      %d',[VarToInt(FWbemObject.AllocatedSize)]));// Uint64
    Writeln(Format('BusType                            %d',[VarToInt(FWbemObject.BusType)]));// Uint16
//    Writeln(Format('CannotPoolReason                   %d',[VarToInt(FWbemObject.CannotPoolReason)]));// Array of Uint16
    Writeln(Format('CanPool                            %s',[VarToStr(FWbemObject.CanPool)]));// Boolean
    Writeln(Format('Description                        %s',[VarToStr(FWbemObject.Description)]));// String
    Writeln(Format('DeviceId                           %s',[VarToStr(FWbemObject.DeviceId)]));// String
    Writeln(Format('EnclosureNumber                    %d',[VarToInt(FWbemObject.EnclosureNumber)]));// Uint16
    Writeln(Format('FirmwareVersion                    %s',[VarToStr(FWbemObject.FirmwareVersion)]));// String
    Writeln(Format('FriendlyName                       %s',[VarToStr(FWbemObject.FriendlyName)]));// String
    Writeln(Format('HealthStatus                       %d',[VarToInt(FWbemObject.HealthStatus)]));// Uint16
    Writeln(Format('IsIndicationEnabled                %s',[VarToStr(FWbemObject.IsIndicationEnabled)]));// Boolean
    Writeln(Format('IsPartial                          %s',[VarToStr(FWbemObject.IsPartial)]));// Boolean
    Writeln(Format('LogicalSectorSize                  %d',[VarToInt(FWbemObject.LogicalSectorSize)]));// Uint64
    Writeln(Format('Manufacturer                       %s',[VarToStr(FWbemObject.Manufacturer)]));// String
    Writeln(Format('MediaType                          %d',[VarToInt(FWbemObject.MediaType)]));// Uint16
    Writeln(Format('Model                              %s',[VarToStr(FWbemObject.Model)]));// String
    Writeln(Format('ObjectId                           %s',[VarToStr(FWbemObject.ObjectId)]));// String
//    Writeln(Format('OperationalStatus                  %d',[VarToInt(FWbemObject.OperationalStatus)]));// Array of Uint16
    Writeln(Format('OtherCannotPoolReasonDescription   %s',[VarToStr(FWbemObject.OtherCannotPoolReasonDescription)]));// String
    Writeln(Format('PartNumber                         %s',[VarToStr(FWbemObject.PartNumber)]));// String
    Writeln(Format('PassThroughClass                   %s',[VarToStr(FWbemObject.PassThroughClass)]));// String
    Writeln(Format('PassThroughIds                     %s',[VarToStr(FWbemObject.PassThroughIds)]));// String
    Writeln(Format('PassThroughNamespace               %s',[VarToStr(FWbemObject.PassThroughNamespace)]));// String
    Writeln(Format('PassThroughServer                  %s',[VarToStr(FWbemObject.PassThroughServer)]));// String
    Writeln(Format('PhysicalLocation                   %s',[VarToStr(FWbemObject.PhysicalLocation)]));// String
    Writeln(Format('PhysicalSectorSize                 %d',[VarToInt(FWbemObject.PhysicalSectorSize)]));// Uint64
    Writeln(Format('SerialNumber                       %s',[VarToStr(FWbemObject.SerialNumber)]));// String
    Writeln(Format('Size                               %d',[VarToInt(FWbemObject.Size)]));// Uint64
    Writeln(Format('SlotNumber                         %d',[VarToInt(FWbemObject.SlotNumber)]));// Uint16
    Writeln(Format('SoftwareVersion                    %s',[VarToStr(FWbemObject.SoftwareVersion)]));// String
    Writeln(Format('SpindleSpeed                       %d',[VarToInt(FWbemObject.SpindleSpeed)]));// Uint32
//    Writeln(Format('SupportedUsages                    %d',[VarToInt(FWbemObject.SupportedUsages)]));// Array of Uint16
    Writeln(Format('UniqueId                           %s',[VarToStr(FWbemObject.UniqueId)]));// String
    Writeln(Format('Usage                              %d',[VarToInt(FWbemObject.Usage)]));// Uint16

    Writeln('-------------------------------------------------------------------');
    FWbemObject:=Unassigned;
  end;
end;
begin
 try
    CoInitialize(nil);
    try
      GetMSFT_PhysicalDiskInfo;
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.
Beispiel-Ausgabe: PhysicalDisk1 = SSD/USB, PhysicalDisk0 = HDD0

AllocatedSize 0
BusType 7
CanPool False
Description
DeviceId 1
EnclosureNumber 0
FirmwareVersion 3004
FriendlyName PhysicalDisk1
HealthStatus 0
IsIndicationEnabled
IsPartial True
LogicalSectorSize 512
Manufacturer KINGSTON
MediaType 0
Model SV300S37A240G
OtherCannotPoolReasonDescription
PartNumber
PassThroughClass
PassThroughIds
PassThroughNamespace
PassThroughServer
PhysicalLocation
PhysicalSectorSize 512
SerialNumber 00A1234xxxxxx
Size 0
SlotNumber 0
SoftwareVersion
SpindleSpeed -1
UniqueId
Usage 1
--------------------------------------------------
AllocatedSize 0
BusType 11
CanPool False
Description
DeviceId 0
EnclosureNumber 0
FirmwareVersion 2BC10001
FriendlyName PhysicalDisk0
HealthStatus 0
IsIndicationEnabled
IsPartial True
LogicalSectorSize 512
Manufacturer
MediaType 3
Model ST2000LM003 HN-M201RAD
OtherCannotPoolReasonDescription
PartNumber
PassThroughClass
PassThroughIds
PassThroughNamespace
PassThroughServer
PhysicalLocation
PhysicalSectorSize 4096
SerialNumber S346J9xxxxxxxx
Size 0
SlotNumber 0
SoftwareVersion
SpindleSpeed -1
UniqueId 50004xxxxxxxxx
Usage 1
--------------------------------------------------

Shark99 29. Jun 2016 15:12

AW: SSD erkennen?
 
Ich möchte von der Benutzung von DeviceIoControl() warnen. Hab den Code von hier an 250 Beta Tester geschickt. Auf 5 Systemen dauert die Ausführung von DeviceIoControl() satte 3 Minuten. Dabei bleibt Windows stehen (Mauszeiger bewegt sich nicht). Nach den 3 Minuten gibt die Funktion ein Success zurück und alles geht wie gehabt weiter. Die User mit den Problem haben SSDs von Samsung (unterschiedliche) und von Corsair. Ich kann das Problem auf keinem von meinen Systemen reproduzieren, weiß nur von Debuglogs was los war. Von den Usern haben 4 Windows 10 und einer Windows 7.

a.def 28. Dez 2016 15:00

AW: SSD erkennen?
 
Ich habe gerade mal den WMI Code Creator rausgekramt und versucht herauszubekommen woran man unter Windows 7 erkennen kann, was eine HDD und was eine SSD ist.
Bis auf die völlig stupide Prüfung, ob "SSD" im Modellnamen vorkommt, wüsste ich nichts.

Ich würde ja gerne die RPM oder Zugriffszeit messen habe aber keine Ahnung wie.

himitsu 28. Dez 2016 16:17

AW: SSD erkennen?
 
Wie wohl Windows beim Installieren erkennt, ob es auf einer SSD installiert wird? (für die Aktivierung des TRIM)

Die Windows-Defragmentierung beachtet das doch auch irgendwie?


Und was ist mit Hybrid-Laufwerken?

a.def 28. Dez 2016 16:18

AW: SSD erkennen?
 
Ich kann gerade nicht unterscheiden, ob es sich bei deinem Beitrag um Ironie handelt oder nicht :stupid:

Benmik 28. Dez 2016 16:23

AW: SSD erkennen?
 
Abseits der Frage, ob man bei himitsu Ironie erkennen kann, verstehe ich deine Frage nicht: Mit Admin-Rechten kann man doch eine SSD erkennen ?!

Luckie 28. Dez 2016 17:22

AW: SSD erkennen?
 
Ja und die Frage ist jetzt wohl wie das Windows macht, damit man es in einem eigenen Programm nutzen kann.

a.def 28. Dez 2016 17:46

AW: SSD erkennen?
 
Die Adminrechte sind eine große Hürde. Ohne funktioniert das wahrscheinlich nicht?

Benmik 28. Dez 2016 18:40

AW: SSD erkennen?
 
Du hast dir jetzt aber nicht die Diskussion durchgelesen? Mit genau dieser Frage habe ich seinerzeit diesen Thread reanimiert.

a.def 28. Dez 2016 18:58

AW: SSD erkennen?
 
Ich habe den Thread mehr oder weniger schnell überflogen und weiß, dass es mit Administratorrechten wohl funktioniert, per SMART (nicht zwingend), es aber auch zu Problemen führen kann bei bestimmten SSDs... schwieriges Thema wie es scheint.

Benmik 28. Dez 2016 20:58

AW: SSD erkennen?
 
Vielleicht hast du dir selbst die Antwort gegeben. Es ist zwar "bäh", aber
  • Gibt es eine SSD ohne "SSD" im Namen?
  • Gibt es eine Festpatte mit "SSD" im Namen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:52 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz