Entwickler-Ecke

Windows API - Unterstützt die Festplatte S.M.A.R.T


Delete - Fr 02.06.17 10:36
Titel: Unterstützt die Festplatte S.M.A.R.T
- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Fr 02.06.17 23:37

Bei mir funktioniert die Funktion korrekt. Du musst diese allerdings mit Adminrechten ausführen.


Delete - Sa 03.06.17 00:45

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Sa 03.06.17 08:33

Hast du Delphi 10.1 benutzt? Ich Delphi 10.2, da sollte kein Unterschied liegen...
Und ich habe den Code 1:1 kopiert.

Hast du einmal mit Adminrechten debuggt? Bekommst du ein Handle von CreateFile?


t.roller - Sa 03.06.17 10:34

CrystalDiskInfo zeigt bei manchen USB-Drives S.M.A.R.T.-Werte an, bei manchen nicht.

Der Code vom TE scheint aber bei USB-Drives nie richtig zu funktionieren.


Delete - Sa 03.06.17 12:58

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Sa 03.06.17 15:03

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Habe es nun auch mit Delphi 10.1 getestet und es lief genauso erfolglos ab. Das Handle scheint gültig zu sein.
Was heißt scheint... Hast du das im Debugger geprüft und immer auch SysErrorMessage(GetLastError) in Strg + F7 ausgewertet?
Dann müsstest du doch ganz genau wissen was passiert... Ein Aufsplitten der Methoden brauchst du doch gar nicht.

Ich habe natürlich jetzt nur unter Windows 10 getestet, nicht unter alten Systemen.


Delete - Sa 03.06.17 15:42

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Sa 03.06.17 22:28

Du kannst ja die Werte einmal im Debugger bzw. im API Monitor vergleichen...
DebugSmartCheck
DeviceIOControlCall


Delete - Sa 03.06.17 23:53

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - So 04.06.17 19:53

Ich benutze nur Windows 10 64 Bit.

Leider habe ich keinen physischen PC mit einem anderen Betriebssystem mehr zur Verfügung aktuell... und in einer VM geht SMART nicht.

Die Befehlslänge ist falsch müsste ja eigentlich heißen, dass die Strukturgröße falsch ist. Ist die denn identisch zu mir (36 bzw. 20)?


t.roller - So 04.06.17 22:50

Hier ist eine Liste von smartmontools, die USB-Bridges und HDDs enthält.
https://www.smartmontools.org/wiki/Supported_USB-Devices

Wenn smartmontools und CrystalDiskInfo nicht funktionieren, werden DELPHI-Programme auch nicht funktionieren.


jaenicke - So 04.06.17 22:57

user profile icont.roller hat folgendes geschrieben Zum zitierten Posting springen:
Wenn smartmontools und CrystalDiskInfo nicht funktionieren, werden DELPHI-Programme auch nicht funktionieren.
Das Problem ist ja offenbar, dass der Aufruf fehlschlägt. Dass es prinzipiell mit der Festplatte geht, hat er ja auch schon geschrieben:
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Die Anwendung CrystalDiskInfo sagt mir, dass die Laufwerke SMART unterstützen. :nixweiss:


Delete - Mo 05.06.17 00:30

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Mo 05.06.17 06:23

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
cmdIn.bDriveNumber den Wert 176 zugwiesen bekommt
Du solltest den Inhalt des Records einmal mit 0 initialisieren. bDriveNumber wird zwar laut Doku ignoriert, aber vielleicht stören ja andere nicht initialisierte Werte...
Denn da stehen ja dann "zufällige" Werte drin.

Vielleicht so?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
//...
  if hnd <> INVALID_HANDLE_VALUE then
  begin
    ZeroMemory(@cmdIn, SizeOf(cmdIn));
    with cmdIn.irDriveRegs do
    begin
      bFeaturesReg := ENABLE_SMART;
      bSectorCountReg := 1;
      bSectorNumberReg := 1;
      bCylLowReg := SMART_CYL_LOW;
      bCylHighReg := SMART_CYL_HI;
      bDriveHeadReg := DRIVE_HEAD_REG;
      bCommandReg := SMART_CMD;

      ZeroMemory(@cmdOut, SizeOf(cmdOut));
      result := DeviceIoControl(hnd, SMART_SEND_DRIVE_COMMAND,
                                @cmdIn, SizeOf(cmdIn), @cmdOut, SizeOf(cmdOut),
                                bytesReturned, nil);
    end;
  end;
//...

// EDIT:
Und dann steht da in der Doku noch das...
https://msdn.microsoft.com/en-us/library/windows/hardware/ff566206(v=vs.85).aspx hat folgendes geschrieben:
If SMART status is being requested, the output buffer must be >= (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS)).

Vielleicht funktioniert das erst ab Windows 10 auch ohne diesen Bufferteil...
Füge doch einfach mal diese IdeRegs noch in die OutParams ein:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  _SENDCMDOUTPARAMS = record
    cBufferSize: DWord;
    DriverStatus: TDriverStatus;
    bBuffer: array[0..0of Byte;
    irDriveRegs: TIdeRegs;
  end;
Übergebe ich als Größe der Out-Params aber zu wenig, bekomme ich den Fehler:
Zitat:
Der an einen Systemaufruf übergebene Datenbereich ist zu klein
Deshalb vermute ich nicht, dass es daran liegt.

// EDIT2:
Ich habe gerade gelesen, dass nicht alle Mainboards mit nForce Chipsatz diese SMART Kommandos unterstützen. Hast du zufällig so eins?

// EDIT3:
Bist du sicher, dass du für die Abfrage des SMART Status den richtigen Befehl benutzt? Ich verstehe deinen Befehl so, dass du SMART damit versuchst zu aktivieren...
Sollte nicht eher SMART_RCV_DRIVE_DATA dafür geeignet sein?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
const
  SMART_SEND_DRIVE_COMMAND     = $0007C084;
  ENABLE_SMART                 = $000000D8;
  SMART_CYL_LOW                = $0000004F;
  SMART_CYL_HI                 = $000000C2;
  SMART_CMD                    = $000000B0;
  DRIVE_HEAD_REG               = $000000A0;
  READ_ATTRIBUTES              = $D0;
  READ_THRESHOLDS              = $D1;

function SmartExists(ADriveLetter: Char): Boolean;
var
  root: PChar;
  hnd: THandle;
  cmdIn: TSendCmdInParams;
  cmdOut: TSendCmdOutParams;
  bytesReturned: DWord;
begin
  result := false;
  root := PChar('\\.\' + UpCase(ADriveLetter) + ':');
  hnd := CreateFile(root, GENERIC_READ or GENERIC_WRITE,
                    FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
                    OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);

  if hnd <> INVALID_HANDLE_VALUE then
  begin
    ZeroMemory(@cmdIn, SizeOf(cmdIn));
    cmdIn.cBufferSize := 512;
    with cmdIn.irDriveRegs do
    begin
      bFeaturesReg := READ_ATTRIBUTES;
      bCommandReg := SMART_CMD;
      bDriveHeadReg := DRIVE_HEAD_REG;

      ZeroMemory(@cmdOut, SizeOf(cmdOut));
      result := DeviceIoControl(hnd, SMART_RCV_DRIVE_DATA,
                                @cmdIn, SizeOf(cmdIn), @cmdOut, SizeOf(cmdOut),
                                bytesReturned, nil);
    end;
  end;
end;


Delete - Mo 05.06.17 07:41

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Mo 05.06.17 08:34

Mit SMART_RCV_DRIVE_DATA bekomme ich auch problemlos die einzelnen Werte für die Smart-Daten. Die stimmen auch mit CrystalDiskInfo überein.


Delete - Mo 05.06.17 08:43

- Nachträglich durch die Entwickler-Ecke gelöscht -


Delete - Di 06.06.17 09:26

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Di 06.06.17 09:43

Du hast wieder das ZeroMemory vergessen... ;-)


t.roller - Di 06.06.17 09:53

C: Der Vorgang wurde erfolgreich beendet // unterstützt SMART
USB-DRIVES:
H: Die Anforderung konnte wegen eines E/A-Gerätefehlers nicht ausgeführt werden // unterstützt nicht SMART
Erneuter Aufruf:
H: Die angeforderte Ressource wird bereits verwendet // unterstützt nicht SMART
G: Die Anforderung wird nicht unterstützt // unterstützt SMART

Alles sehr rätselhaft.


Delete - Di 06.06.17 09:57

- Nachträglich durch die Entwickler-Ecke gelöscht -


Delphi-Laie - Di 06.06.17 11:09

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Wenn es so ist, wie t_roller schreibt, dann unterstützt keines meiner Laufwerke SMART. :lol:


Leider kann ich fachlich / inhaltlich nicht mitreden, aber ist denn die letzte Aussage wirklich wahrscheinlich oder gar zutreffend? Oder anders, ist SMART nicht längst Standard, ohne den keine Festplatte heutzutage mehr hergestellt wird?


t.roller - Di 06.06.17 12:03

user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Oder anders, ist SMART nicht längst Standard, ohne den keine Festplatte heutzutage mehr hergestellt wird?


Jede HDD hat SMART, aber ob man die Werte auslesen kann, liegt am S-ATA-Contoller bzw. an der USB-Bridge.


Delete - Mi 07.06.17 02:02

- Nachträglich durch die Entwickler-Ecke gelöscht -


Holgerx - Do 08.06.17 19:09

Hmm..

Also an HOME liegt es nicht..

Habe hier WIndows 8.1 Home..


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
[#] Laufwerk C  (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk D  (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk E  (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk F  
HandleError = 0
SmartVersionError = 1
SmartDataError = 1
[#] Laufwerk G  (Festplatte)
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk Z  
HandleError = 0
SmartVersionError = 1
SmartDataError = 1


Was deine Fehlercodes bedeuten kann ich nicht sagen, jedoch habe ich eine eigene Routine (mit D6), welche mir die gültigen SMART- Werte liefert.
Ich habe sie mal angehängt, ist eine Kombination aus diversen Beiträgen aus verschiedenen Foren und Techdocs von HD-Herstellern. ;)


t.roller - Do 08.06.17 19:25

WIN8.1 Version 6.3, Build 9600


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
[#] Laufwerk C  (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk D  (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk E  (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk F  (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk H  (Festplatte) = USB-DISK
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk I  
HandleError = 0
SmartVersionError = 1
SmartDataError = 1


Delete - Fr 09.06.17 00:22

- Nachträglich durch die Entwickler-Ecke gelöscht -


Holgerx - Fr 09.06.17 05:24

Hmm..

Ich glaube, das Problem deiner Routinen ist die falsche Fehlerbehandlung!

Delphi-Quelltext
1:
2:
3:
  DeviceIoControl(hDrive, SMART_GET_VERSION, nil0,
                  @gvParams, SizeOf(gvParams), bytesReturned, nil);
  result := GetLastError;


Nur wenn DeviceIoControl 'fehlschlägt' kann mit GetLastError der dazu gehörende Fehler ausgelesen werden!
Ansonsten kann da irgend ein alter Fehlercode drinnen stehen!

also:


Delphi-Quelltext
1:
2:
3:
4:
5:
  
  Result := 0;
  if not DeviceIoControl(hDrive, SMART_GET_VERSION, nil0,
                  @gvParams, SizeOf(gvParams), bytesReturned, nilthen
  result := GetLastError;


Dann sollte es richtig klappen ;)


Delete - Fr 09.06.17 06:46

- Nachträglich durch die Entwickler-Ecke gelöscht -


Holgerx - Fr 09.06.17 08:07

Hmm..

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Das geht schon in Ordnung. Der Test soll nur zeigen, ob DeviceIoControl() erfolgreich war. In dem Fall ist GetLastError() = 0, ansonsten größer 0. So erfahre ich, warum es nicht geht, im gegebenen Fall.


Ob dass so stimmt bezweifle ich!
Die meisten API-Aufrufe setzen den LastError NICHT zurück.
Deshalb ist GetLastError nur dann Gültig, wenn der API-Aufruf 'Fehlgeschlagen' ist!
Ansonsten steht da ein Error-Code von einem anderen API-Aufruf drinnen, welcher irgendwan vorher stattgefunden hat.
Somit auch FehlerCodes, welche seitens deines eigendlichen Aufrufes garnicht möglich sind.. ;)

(Ich spreche da aus Erfahrung ;) )

Angehängt ist ein Testprogramm, welches bei mir unter Win7 Prof 64Bit wie auch unter Win8.1 HOME 64Bit die SMART-Werte der Laufwerke zurück gibt.


jaenicke - Fr 09.06.17 08:15

Auch in dem Testprogramm produziert das (logischerweise) falsche Werte. Original:
Zitat:
[#] Laufwerk C (Festplatte)
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk D (Festplatte)
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk E
HandleError = 0
SmartVersionError = 1
SmartDataError = 1
[#] Laufwerk O (Festplatte)
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk U (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk V (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk W (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk X (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5
[#] Laufwerk Y (Festplatte)
HandleError = 0
SmartVersionError = 5
SmartDataError = 5

Nach der Korrektur (0 zurückliefern, wenn Rückgabewert True war):
Zitat:
[#] Laufwerk C (Festplatte)
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk D (Festplatte)
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk E
HandleError = 0
SmartVersionError = 1
SmartDataError = 1
[#] Laufwerk O (Festplatte)
HandleError = 0
SmartVersionError = 1117
SmartDataError = 1117
[#] Laufwerk U (Festplatte)
HandleError = 0
SmartVersionError = 0
SmartDataError = 0
[#] Laufwerk V (Festplatte)
HandleError = 0
SmartVersionError = 0
SmartDataError = 0
[#] Laufwerk W (Festplatte)
HandleError = 0
SmartVersionError = 0
SmartDataError = 0
[#] Laufwerk X (Festplatte)
HandleError = 0
SmartVersionError = 0
SmartDataError = 0
[#] Laufwerk Y (Festplatte)
HandleError = 0
SmartVersionError = 0
SmartDataError = 0

Es sind alles lokale Laufwerke, C, D und O sind auf einer SSD, E ist ein DVD-Brenner, U und V eine ältere SSD und die anderen liegen auf einer Festplatte.
Interessanterweise geht es mit einer der beiden SSDs.

// EDIT:
user profile iconHolgerx hat folgendes geschrieben Zum zitierten Posting springen:
Angehängt ist ein Testprogramm, welches bei mir unter Win7 Prof 64Bit wie auch unter Win8.1 HOME 64Bit die SMART-Werte der Laufwerke zurück gibt.
Das funktioniert bei mir für die Festplatte, bei der SSD wird nichts angezeigt.


Delete - Fr 09.06.17 08:29

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Fr 09.06.17 08:50

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Ich weiss nicht was ihr habt, aber in der Doku zu DeviceIoControl() steht
Eben drum, du machst es nicht wie es dort steht.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
MSDN [https://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx] hat folgendes geschrieben:
Return value

If the operation completes successfully, the return value is nonzero.

If the operation fails or is pending, the return value is zero. To get extended error information, call GetLastError.

Dort steht, dass die Unterscheidung, ob die Funktion erfolgreich war, am Rückgabewert hängt (eigentlich auch logisch), und im Fehlerfall GetLastError benutzt werden kann um Details zu bekommen. Du benutzt GetLastError aber als Indikator, ob die Funktion erfolgreich war. Und das funktioniert nicht, weder laut Doku noch (siehe meine Ergebnisse) in der Realität.


Delete - Fr 09.06.17 10:26

- Nachträglich durch die Entwickler-Ecke gelöscht -


jaenicke - Fr 09.06.17 10:44

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Ich habs dann falsch verstanden. So wie es geschrieben steht heißt es:
Da hast du aber die Absätze weggelassen. Die trennen das ganze ja schon einmal. Und dazu kommt, dass man ja nur für Fehlerinformation GetLastError nutzen soll und für nix anderes.
Egal, das gilt ja für die ganze API, jetzt weißt du es ja. ;-)

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
... anders als beim CrystalDiskInfo:
Dann setze doch einfach mal einen Haltepunkt auf DeviceIoControl und schaue was das Tool da so alles aufruft...
Jedenfalls keine der hier bisher genannten Funktionen... wenn ich das so sehe, greift das Ding direkt auf die ATA Schnittstelle zu, es wird nur genutzt:
IOCTL_DISK_GET_DRIVE_GEOMETRY, IOCTL_SCSI_MINIPORT, IOCTL_ATA_PASS_THROUGH, IOCTL_STORAGE_QUERY_PROPERTY, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
Crystal

Ein Blick in den Quelltext lohnt dann wohl doch. ;-)


Delete - Fr 09.06.17 11:16

- Nachträglich durch die Entwickler-Ecke gelöscht -


t.roller - Sa 10.06.17 20:31

Hier gefunden:
http://www.delphipraxis.net/attachments/37919d1351158451-winhexapi-unformatierter-usb-datentraeger-wmi_sql.zip

CIMV2 - CIM_MediaAccessDevice
Win32_DiskDrive - Capabilities - CapabilityDescriptions

Ausgabe (teilweise):
instance of Win32_DiskDrive
{BytesPerSector = 512;
Capabilities = {3, 4, 10}; // 10 = SMART Notification
CapabilityDescriptions = {"Random Access", "Supports Writing", "SMART Notification"};

Das geht auch im CMD-Fenster (Als Administrator ausführen) :
wmic diskdrive get capabilities, capabilitydescriptions, caption, status
Ausgabe-Beispiel:
Capabilities CapabilityDescriptions Caption Status
{3, 4} {"Random Access", "Supports Writing"} LogiLink SCSI Disk Device OK
{3, 4, 10} {"Random Access", "Supports Writing", "SMART Notification"} ST2000LM003 HN-M201RAD OK


Delete - So 11.06.17 09:07

- Nachträglich durch die Entwickler-Ecke gelöscht -


t.roller - So 11.06.17 11:00

Andere Version (ohne WbemScripting_TLB)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
uses ...Winapi.ActiveX, System.Win.ComObj, ...

procedure MM(s:string); begin Form1.Memo1.Lines.Add(s); end;

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

procedure  GetCIM_MediaAccessDeviceInfo;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  I : Integer;
  Data : array of WORD;
  params: OleVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM CIM_MediaAccessDevice','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    MM(Format('Availability                   %d',[VartoInt(FWbemObject.Availability)]));// Uint16
//    MM(Format('Capabilities                   %d',[VartoInt(FWbemObject.Capabilities)]));// Array of Uint16
//    MM(Format('CapabilityDescriptions         %s',[VartoStr(FWbemObject.CapabilityDescriptions)]));// Array of String
      if not VarIsNull(FWbemObject.Capabilities) then
      begin
        Data := FWbemObject.Capabilities;
        for I:= VarArrayLowBound(data,1to VarArrayHighBound(data,1do
          MM('Capabilities: '+IntToStr(Data[I]));// Array of WORD /Uint16
      end;

      if not VarIsNull(FWbemObject.CapabilityDescriptions) then
      begin
        Params := FWbemObject.CapabilityDescriptions;
        for I:= VarArrayLowBound(Params,1to VarArrayHighBound(Params,1do
          MM('CapabilityDescriptions: '+ VarToStr(Params[I]));// Array of VarToStr
      end;

    MM(Format('Caption                        %s',[VartoStr(FWbemObject.Caption)]));// String
    MM(Format('CompressionMethod              %s',[VartoStr(FWbemObject.CompressionMethod)]));// String
    MM(Format('ConfigManagerErrorCode         %d',[VartoInt(FWbemObject.ConfigManagerErrorCode)]));// Uint32
    MM(Format('ConfigManagerUserConfig        %s',[VartoStr(FWbemObject.ConfigManagerUserConfig)]));// Boolean
    MM(Format('CreationClassName              %s',[VartoStr(FWbemObject.CreationClassName)]));// String
    MM(Format('DefaultBlockSize               %d',[VartoInt(FWbemObject.DefaultBlockSize)]));// Uint64
    MM(Format('Description                    %s',[VartoStr(FWbemObject.Description)]));// String
    MM(Format('DeviceID                       %s',[VartoStr(FWbemObject.DeviceID)]));// String
    MM(Format('ErrorCleared                   %s',[VartoStr(FWbemObject.ErrorCleared)]));// Boolean
    MM(Format('ErrorDescription               %s',[VartoStr(FWbemObject.ErrorDescription)]));// String
    MM(Format('ErrorMethodology               %s',[VartoStr(FWbemObject.ErrorMethodology)]));// String
    MM(Format('InstallDate                    %s',[VartoStr(FWbemObject.InstallDate)]));// Datetime
    MM(Format('LastErrorCode                  %d',[VartoInt(FWbemObject.LastErrorCode)]));// Uint32
    MM(Format('MaxBlockSize                   %d',[VartoInt(FWbemObject.MaxBlockSize)]));// Uint64
    MM(Format('MaxMediaSize                   %d',[VartoInt(FWbemObject.MaxMediaSize)]));// Uint64
    MM(Format('MinBlockSize                   %d',[VartoInt(FWbemObject.MinBlockSize)]));// Uint64
    MM(Format('Name                           %s',[VartoStr(FWbemObject.Name)]));// String
    MM(Format('NeedsCleaning                  %s',[VartoStr(FWbemObject.NeedsCleaning)]));// Boolean
    MM(Format('NumberOfMediaSupported         %d',[VartoInt(FWbemObject.NumberOfMediaSupported)]));// Uint32
    MM(Format('PNPDeviceID                    %s',[VartoStr(FWbemObject.PNPDeviceID)]));// String
//    MM(Format('PowerManagementCapabilities    %d',[VartoInt(FWbemObject.PowerManagementCapabilities)]));// Array of Uint16
      if not VarIsNull(FWbemObject.PowerManagementCapabilities) then
      begin
        Data := FWbemObject.PowerManagementCapabilities;
        for I:= VarArrayLowBound(data,1to VarArrayHighBound(data,1do
          MM('PowerManagementCapabilities: '+IntToStr(Data[I]));// Array of WORD /Uint16
      end;
    MM(Format('PowerManagementSupported       %s',[VartoStr(FWbemObject.PowerManagementSupported)]));// Boolean
    MM(Format('Status                         %s',[VartoStr(FWbemObject.Status)]));// String
    MM(Format('StatusInfo                     %d',[VartoInt(FWbemObject.StatusInfo)]));// Uint16
    MM(Format('SystemCreationClassName        %s',[VartoStr(FWbemObject.SystemCreationClassName)]));// String
    MM(Format('SystemName                     %s',[VartoStr(FWbemObject.SystemName)]));// String

    MM('---------------------------------------------------------------------');
    FWbemObject:=Unassigned;
  end;
end;


Ausgabe (teilweise):
Availability 0
Capabilities: 3
Capabilities: 4
Capabilities: 10
CapabilityDescriptions: Random Access
CapabilityDescriptions: Supports Writing
CapabilityDescriptions: SMART Notification
Caption ST2000LM003 HN-M201RAD
CompressionMethod
ConfigManagerErrorCode 0
ConfigManagerUserConfig False
CreationClassName Win32_DiskDrive
DefaultBlockSize 0
Description Laufwerk
DeviceID \\.\PHYSICALDRIVE0
---------------------------------------------------
Availability 0
Capabilities: 3
Capabilities: 4
CapabilityDescriptions: Random Access
CapabilityDescriptions: Supports Writing
Caption Intenso External USB 3.0 SCSI Disk Device
CompressionMethod
ConfigManagerErrorCode 0
ConfigManagerUserConfig False
CreationClassName Win32_DiskDrive
DefaultBlockSize 0
Description Laufwerk
DeviceID \\.\PHYSICALDRIVE1


t.roller - So 11.06.17 11:34

Kurze Version:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
procedure TForm1.Button1Click(Sender: TObject);
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  I : Integer;
  Data : array of WORD;
  params: OleVariant;
begin;
    MM('Win32_DiskDrive');
    MM('---------------');
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT Model,Capabilities,CapabilityDescriptions,Name FROM
Win32_DiskDrive'
,'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
      if not VarIsNull(FWbemObject.Capabilities) then
      begin
        Data := FWbemObject.Capabilities;
        for I:= VarArrayLowBound(data,1to VarArrayHighBound(data,1do
          MM('Capabilities: '+IntToStr(Data[I]));// Array of WORD /Uint16
      end;

      if not VarIsNull(FWbemObject.CapabilityDescriptions) then
      begin
        Params := FWbemObject.CapabilityDescriptions;
        for I:= VarArrayLowBound(Params,1to VarArrayHighBound(Params,1do
          MM('CapabilityDescriptions: '+ VarToStr(Params[I]));// Array of VarToStr
      end;

    MM(Format('Model                %s',[VarToStr(FWbemObject.Model)]));// String
    MM(Format('Name                 %s',[VarToStr(FWbemObject.Name)]));// String
    MM('-------------------------------------------------------------------');
    FWbemObject:=Unassigned;
  end;
end;

Ausgabe:
Win32_DiskDrive
---------------
Capabilities: 3
Capabilities: 4
CapabilityDescriptions: Random Access
CapabilityDescriptions: Supports Writing
Model Intenso External USB 3.0 SCSI Disk Device
Name \\.\PHYSICALDRIVE1
-------------------------------------------------------------------
Capabilities: 3
Capabilities: 4
Capabilities: 10
CapabilityDescriptions: Random Access
CapabilityDescriptions: Supports Writing
CapabilityDescriptions: SMART Notification
Model ST2000LM003 HN-M201RAD
Name \\.\PHYSICALDRIVE0