Seite 3 von 5

Re: Festplattenaktivität feststellen ?

Verfasst: 04.01.2012 12:30
von Helle
Hier ein schmuckloses (keine Grafik) Code-Beispiel:

Code: Alles auswählen

;- Festplatten-Aktivität AHCI-SATA-Geräte, 64-Bit-Windows 
;- "Helle" Klaus Helbing, 04.01.2012, PB v4.60 (x64)
;- Benötigt WinIo v3.0 und für 64-Bit die Atsiv.exe; es sei denn andere Treiber sind vorhanden 

#PROCESSOR_ARCHITECTURE_AMD64 = $9
#SATA_SIG_ATA	                = $00000101	  ;SATA drive = HDD
#SATA_SIG_ATAPI	              = $EB140101	  ;SATAPI drive = CD/DVD (optisches LW)
#SATA_SIG_SEMB	              = $C33C0101	  ;Enclosure management bridge
#SATA_SIG_PM	                = $96690101	  ;Port multiplier
#Class_ID                     = $01060000   ;Class $01=mass storage device, SubClass $06=serial ATA

;einmaliges Install für 32-Bit; Prinzip, ungetestet
;If OpenLibrary(0, "WinIo32.dll")      ;32-Bit-Version laden, Pfad beachten
  ;Prototype.i ProtoWinIo(Pfad.i, Bool.i)
  ;Global WIO_InstallWinIoDriver.ProtoWinIo = GetFunction(0, "InstallWinIoDriver")
  ;Pfad$ = "C:\Codes\PureBasic 4.0\IO\64-Bit\WinIO\PB\"    ;Pfad zu WinIo32.sys 
  ;WIO_InstallWinIoDriver(@Pfad$, #False)
  ;CloseLibrary(0)
;EndIf

OpenWindow(0, 0, 0, 400, 400, "Festplatten-Aktivität AHCI-SATA-Geräte", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
;ermitteln, ob 32- oder 64-Bit-Betriebssystem 
SI.SYSTEM_INFO                              ;Structure System_Info
GetSystemInfo_(@SI)
If SI\wProcessorArchitecture = #PROCESSOR_ARCHITECTURE_AMD64 
  DLLOK = OpenLibrary(0, "WinIo64.dll")     ;64-Bit-Version laden
  ;----- dies nur für 64-Bit; Pfad beachten (hier Atsiv.exe im selben Verzeichnis wie .pb oder .exe)
  RunProgram("Atsiv.exe" ," -u " + "WinIo64.sys", "", #PB_Program_Hide)   ;oder auslagern
  Delay(250)
  RunProgram("Atsiv.exe" ," -f " + "WinIo64.sys", "", #PB_Program_Hide)
  Delay(250)       ;evtl.anpassen
  ;-----
 Else
  DLLOK = OpenLibrary(0, "WinIo32.dll")     ;32-Bit-Version laden
EndIf 

If DLLOK
  Prototype.i ProtoWinIo_0()
  Global WIO_InitializeWinIo.ProtoWinIo_0   = GetFunction(0, "InitializeWinIo")
  Global WIO_ShutdownWinIo.ProtoWinIo_0 = GetFunction(0, "ShutdownWinIo")

  Prototype.i ProtoWinIo_2(physAddr.i, physVal.l)
  Global WIO_GetPhysLong.ProtoWinIo_2 = GetFunction(0, "GetPhysLong")  

  Prototype.i ProtoWinIo_3(Port.w, Value.l, G.b) 
  Global WIO_SetPortVal.ProtoWinIo_3 = GetFunction(0, "SetPortVal")  
  Global WIO_GetPortVal.ProtoWinIo_3 = GetFunction(0, "GetPortVal") 

  WIO_InitializeWinIo()

  ;- Aufbau Bus-Configuration-Address-Register, Adresse $0CF8: 
  ;- Bit 0-1:   Reserviert 
  ;- Bit 2-7:   Register-Nummern (DWords) 0-63, $2=Class/SubClass-ID
  ;- Bit 8-10:  Funktions-Nummer 0-7 
  ;- Bit 11-15  Device-Nummer 0-31 
  ;- Bit 16-23  Bus-Nummer 0-255, 0=PCI
  ;- Bit 24-30  Reserviert 
  ;- Bit 31:    Configuration-Address-Register Ein/Aus 

  ;PCI-Bus absuchen nach Class $01=mass storage device, SubClass $06=serial ATA
  Port_BCAR.w = $0CF8                            ;Bus-Configuration-Address-Register
  Port_BCDR.w = $0CFC                            ;Bus-Configuration-Data-Register
  GetValue.l
  SetValue.l = $80000000 + %1000                 ;Bit 31 setzen sowie Class/SubClass
  For i = 0 To 31                                ;Device-Nr. 
    SetValue & $FFFFF8FF                         ;Funktions-Nr. auf Null setzen 
    For k = 0 To 7                               ;Funktions-Nr. 
      WIO_SetPortVal(Port_BCAR, SetValue, 4)     ;4=Dword-Wert schreiben
      WIO_GetPortVal(Port_BCDR, @GetValue, 4)    ;Bus-Configuration-Data-Register auslesen 
      If (GetValue & $FFFF0000) = #Class_ID      ;$01060000
        SetValue = (SetValue & $FFFFFFF0) + %100100   ;ABAR auslesen (Register-Nummer 9)
        WIO_SetPortVal(Port_BCAR, SetValue, 4)   ;4=Dword-Wert schreiben
        WIO_GetPortVal(Port_BCDR, @GetValue, 4)  ;Bus-Configuration-Data-Register auslesen 
        ABAR = GetValue & $FFFFFFFF              ;ABAR=AHCI Base Address
        ABAR$ = "AHCI Base Address gefunden an Adresse : $" + Hex(ABAR) 
        Break 2
      EndIf 
      SetValue + $100 
    Next    
  Next 
  TextGadget(1, 10, 10, 380, 20, ABAR$)

  ;ermitteln, wieviel AHCI-Ports vorhanden sind
  WIO_GetPhysLong(ABAR + $0C, @GetValue)         ;$0C=Ports Implemented, jedes gesetzte Bit ist ein SATA-Port (0-31)
  Anz_SATA = Len(Bin(GetValue))
  Anz_SATA$ = "Anzahl SATA-Ports gefunden : " + Str(Anz_SATA)
  TextGadget(2, 10, 30, 380, 20, Anz_SATA$)

  ;was ist dran an gefundenen Ports?
  Signatur = ABAR + $124                         ;$124=Signatur Port0
  Matrix = 0
  k = 1
  For i = 1 To Anz_SATA
    WIO_GetPhysLong(Signatur, @GetValue)
    Typ = GetValue & $FFFFFFFF
    Select Typ
      Case #SATA_SIG_ATA
        Typ$ = "Port " + Str(i - 1) + " ist ein SATA-Drive (HDD)"
        Matrix | k
      Case #SATA_SIG_ATAPI
        Typ$ = "Port " + Str(i - 1) + " ist ein SATAPI-Drive (z.B. optisches LW)"
      Case #SATA_SIG_SEMB
        Typ$ = "Port " + Str(i - 1) + " ist eine Enclosure Management Bridge)"
      Case #SATA_SIG_PM
        Typ$ = "Port " + Str(i - 1) + " ist ein Port Multiplier"
      Default
        Typ$ = "Port " + Str(i - 1) + " ist z.Z. nicht belegt"
    EndSelect
    TextGadget(2 + i, 10, 30 + (20 * i), 380, 20, Typ$)
    Signatur + $80                               ;nächster Port
    k << 1
  Next

  If Matrix = 0
    MessageRequester("Achtung !", "Keine AHCI-SATA-Platte gefunden !")
    End
  EndIf

  k = i
  j = Matrix
  For n = i To Anz_SATA + i - 1
    If j & 1
      TextGadget(2 + k, 10, 50 + (20 * k), 100, 20, "Status Port " + Str(n - i) + " : ")
      TextGadget(2 + k + Anz_SATA, 120, 50 + (20 * k), 280, 20, "Ruhe")
      k + 1
      j >> 1
    EndIf
  Next

  ;jetzt die SATA-Platten beobachten
  AddWindowTimer(0, 0, 5)                        ;5 ms, Geschmackssache
  Repeat
    If Event = #PB_Event_Timer And EventTimer() = 0   ;Aktualisierung und Anzeige ca. alle 0.05 Sekunden
      SATA_Activ = ABAR + $134                   ;$134=Port0 Device Status auslesen, ist nur eine von mehreren Möglichkeiten
      k = i
      j = Matrix
      For n = i To Anz_SATA + i - 1
        If j & 1
          WIO_GetPhysLong(SATA_Activ, @GetValue)
          If GetValue
            SetGadgetText(2 + k + Anz_SATA, "Action") ;kann man natürlich auch grafisch gestalten
           Else
            SetGadgetText(2 + k + Anz_SATA, "Ruhe")
          EndIf
          k + 1
          j >> 1
        EndIf
        SATA_Activ + $80                         ;nächster Port
      Next
    EndIf
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow

  ;WIO_ShutdownWinIo()
  CloseLibrary(0)
EndIf
Für den "Normal-User" bleibt die 64-Bit-Treiber-Problematik. Die Atsiv.exe wurde seinerzeit z.B. zu etlichen Monitoring-Programmen mitgeliefert :wink: .

Viel Spaß!
Helle

Re: Festplattenaktivität feststellen ?

Verfasst: 04.01.2012 21:56
von Falko
@Bisonte,
Versuch mal diesen Code hier.
http://pbasic.spb.ru/phpBB2/viewtopic.php?t=1066
Leider verstehe ich kein russich, aber es scheint zu funktionieren.
[Edit]
Ich habe nun den Google-Translator probiert und soweit die Texte von russisch auf deutsch
ersetzt. Ok, es kann sein, das es nicht genau passt. :)

Code: Alles auswählen

;Informationen zur Festplatte
;http://pbasic.spb.ru/phpBB2/viewtopic.php?t=1066
; Author: kvitaliy 2010
; PureBasic v 4.4
;Programm, wenn die HDD LED blinkt dann auf SCROLL und ändern Sie das Tray-Icon.

#IOCTL_DISK_PERFORMANCE     = $70020;
 
Structure DISK_PERFORMANCE 
BytesRead.q 
BytesWritten.q 
ReadTime.q 
WriteTime.q 
IdleTime.q 
ReadCount.l 
WriteCount.l 
QueueDepth.l 
SplitCount.l 
QueryTime.q ; korrigiert v. L nach q [ http://msdn.microsoft.com/en-us/library/windows/desktop/aa363991%28v=vs.85%29.aspx]
StorageDeviceNumber.l 
StorageManagerName.l[8]
EndStructure
 SystemPath.s=Space(255)
Result=GetSystemDirectory_(SystemPath.s,255)
 Global hdh
;Procedure ScrollLock-blinken 
Procedure SetScrollLED(VKkey.l, bState.b)

Dim keyState.b(256)
GetKeyboardState_(@keyState(0))

If (bState = #True And keyState(VKkey) = 0) or (bState = #False And keyState(VKkey) = 1)
  keybd_event_(VKkey, 0, #KEYEVENTF_EXTENDEDKEY, 0)
  keybd_event_(VKkey, 0, #KEYEVENTF_EXTENDEDKEY + #KEYEVENTF_KEYUP, 0)
  keyState(VKkey) = bState
  SetKeyboardState_(@keyState(0))
EndIf

EndProcedure     
 
Procedure OpenPhysDrive(CurrentDrive.l)
hdh = CreateFile_("\\.\PhysicalDrive" + Str(CurrentDrive),0,0,0,#OPEN_EXISTING, 0, 0)
ProcedureReturn hdh
EndProcedure

   ;Prüft, ob eine physische Festplatte im System nach 0 (neben 1 Disc, etc.)  
    If OpenPhysDrive(0) = #INVALID_HANDLE_VALUE
       End ; es gibt keinen Ausstieg aus dem Programm-CD
    EndIf
   ; Programm-Icon in der Taskleiste wird aus der System-DLL übernommen
   IdIcon1=ExtractIcon_(0,SystemPath+"\SetupAPI.dll",29)     
   IdIcon2=ExtractIcon_(0,SystemPath+"\SetupAPI.dll",8)   
   
    dp.DISK_PERFORMANCE
     
 Window_Form1=OpenWindow(0,80,80,100,100,"HDD",#PB_Window_Invisible)

CreatePopupMenu(0)
  MenuItem(1, "Beenden")
  MenuItem(2, "Über")
 
AddSysTrayIcon(1, WindowID(0),IdIcon2) ;
SysTrayIconToolTip(1, "HDD PERFORMANCE")
 
   Repeat
 
   EventID = WaitWindowEvent(10)
      ; Lesen bis wir alt werden :)
    Result=DeviceIoControl_(hdh, #IOCTL_DISK_PERFORMANCE, 0, 0, @dp, SizeOf(DISK_PERFORMANCE), @lBytesReturned, 0);
           
   If PeekQ(@dp\ReadTime) <> OldReadTime.q; Wenn gelesen wird - LED-Anzeige-Symbol blinken lassen
          OldReadTime = PeekQ(@dp\ReadTime)
         SetScrollLED(#VK_SCROLL,#True)   
         ChangeSysTrayIcon(1,IdIcon2)
    Else
         SetScrollLED(#VK_SCROLL,#False) 
         ChangeSysTrayIcon(1,IdIcon1)
   EndIf; 
   
   If PeekQ(@dp\WriteTime)<>OldWriteTime.q ;Wenn geschrieben wird - LED-Anzeige-Symbol blinken lassen
          OldWriteTime= PeekQ(@dp\WriteTime)
        SetScrollLED(#VK_SCROLL,#True) 
        ChangeSysTrayIcon(1,IdIcon2)
    Else
         SetScrollLED(#VK_SCROLL,#False)   
         ChangeSysTrayIcon(1,IdIcon1)
     EndIf; 
    Delay (10)
   
   
 
         
 If EventID = #PB_Event_SysTray
    Select EventType()
      Case #PB_EventType_RightClick ;Die Verarbeitung der rechten Maustaste
      DisplayPopupMenu(0, WindowID(0)) ;zeige Popup-Menü
      EndSelect
  EndIf
   
    If EventID = #PB_Event_Menu
    Select EventMenu()
      Case 1
         Quit = 1
       Case 2
          MessageRequester("HDD", "ScrollLock -Herunterladen HDD LED", #PB_MessageRequester_Ok)
      EndSelect
  EndIf
    If EventID = #PB_Event_CloseWindow  ; Beenden Sie das Programm
      Quit = 1
    EndIf

  Until Quit = 1
  SetScrollLED(#VK_SCROLL,#False) 
[/Edit]

Gruß,
Falko

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 12:34
von dige
Scheint unter Win7x86 zu funktionieren :)

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 12:46
von RSBasic
Unter Win7x64 ebenfalls.

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 19:30
von NicknameFJ
@Falco
Vielen Dank.

Läuft hier bei mir zuhause (XP Home SP3) super.

Muss ich mal am Montag auf Arbeit (Win7 Prof. 64-Bit) testen.


@Helle
Auch Dir ein dickes Dankeschön. Leider steige ich bei dem Code überhaupt nicht durch - aber egal.


Grüße

NicknameFJ

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 19:42
von Falko
Muss ich mal am Montag auf Arbeit (Win7 Prof. 64-Bit) testen.
Wie RSBasic schon geschrieben hatte, habe ich es auch bei mir auf mein
Win7 Pro 64-Bit inclusive PB-64-Bit-Compilat getestet und es läuft scheinbar auch
unter 64-Bit.

Wenn du unten im Systray mit Rechtsklick und dann das Festplattensymbol die Eigenschaft "über" wählst,
kannst du noch etwas ändern. Dann blinkt die Scrollampe sehr schnell.
Ich denke, das hier dann die Schreib und Lesezugriffe aller Geräte oder nur
der Festplatte angezeigt werden, was ich aber nicht prüfen kann.

Interessant auch, wenn man die Taste Scroll-Lock jeweils ein oder ausschaltet. :)

Gruß,
Falko

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 20:52
von mk-soft
Hi, echt cool

aber das Ansteuerung der LED war nicht richtig.

Jetzt kommt das flackern der LED auch mit den Kracht meiner Festplatte gleich

Code: Alles auswählen

;Informationen zur Festplatte
;http://pbasic.spb.ru/phpBB2/viewtopic.php?t=1066
; Author: kvitaliy 2010
; PureBasic v 4.4
;Programm, wenn die HDD LED blinkt dann auf SCROLL und ändern Sie das Tray-Icon.

#IOCTL_DISK_PERFORMANCE     = $70020;

Structure DISK_PERFORMANCE
  BytesRead.q;
  BytesWritten.q;
  ReadTime.q;
  WriteTime.q;
  IdleTime.q;
  ReadCount.l;
  WriteCount.l;
  QueueDepth.l;
  SplitCount.l;
  QueryTime.l;
  StorageDeviceNumber.l;
  StorageManagerName.l[8];
EndStructure

Global SystemPath.s=Space(255)
Global Result=GetSystemDirectory_(SystemPath.s,255)
Global hdh
Global change
Global ledon

;Procedure ScrollLock-blinken

Procedure SetScrollLED(VKkey.l, bState.b)

  Dim keyState.b(256)
  GetKeyboardState_(@keyState(0))

  If (bState = #True And keyState(VKkey) = 0) Or (bState = #False And keyState(VKkey) = 1)
    keybd_event_(VKkey, 0, #KEYEVENTF_EXTENDEDKEY, 0)
    keybd_event_(VKkey, 0, #KEYEVENTF_EXTENDEDKEY + #KEYEVENTF_KEYUP, 0)
    keyState(VKkey) = bState
    SetKeyboardState_(@keyState(0))
  EndIf

EndProcedure     

Procedure OpenPhysDrive(CurrentDrive.l)
  
  Protected hdh
  
  hdh = CreateFile_("\\.\PhysicalDrive" + Str(CurrentDrive),0,0,0,#OPEN_EXISTING, 0, 0)
  ProcedureReturn hdh
    
EndProcedure

;-Main

;Prüft, ob eine physische Festplatte im System nach 0 (neben 1 Disc, etc.) 
hdh = OpenPhysDrive(0)
If hdh = #INVALID_HANDLE_VALUE
   End ; es gibt keinen Ausstieg aus dem Programm-CD
EndIf

; Programm-Icon in der Taskleiste wird aus der System-DLL übernommen
IdIcon1=ExtractIcon_(0,SystemPath+"\SetupAPI.dll",29)     
IdIcon2=ExtractIcon_(0,SystemPath+"\SetupAPI.dll",8)   
   
dp.DISK_PERFORMANCE
     
If OpenWindow(0,80,80,100,100,"HDD",#PB_Window_Invisible)

  CreatePopupMenu(0)
    MenuItem(1, "Beenden")
    MenuItem(2, "Über")
  
  AddSysTrayIcon(1, WindowID(0),IdIcon2) ;
  SysTrayIconToolTip(1, "HDD PERFORMANCE")
  
  Repeat
    EventID = WaitWindowEvent(10)
    ; Lesen bis wir alt werden :)
    Result=DeviceIoControl_(hdh, #IOCTL_DISK_PERFORMANCE, 0, 0, @dp, SizeOf(DISK_PERFORMANCE), @lBytesReturned, 0);
    
    change = #False
    
    If PeekQ(@dp\ReadTime) <> OldReadTime.q; Wenn gelesen wird - LED-Anzeige-Symbol blinken lassen
      OldReadTime = PeekQ(@dp\ReadTime)
      change = #True
    EndIf
    
    If PeekQ(@dp\WriteTime)<>OldWriteTime.q ;Wenn geschrieben wird - LED-Anzeige-Symbol blinken lassen
      OldWriteTime= PeekQ(@dp\WriteTime)
      change = #True
    EndIf
    
    If change = #True And ledon = #False
      SetScrollLED(#VK_SCROLL,#True)   
      ChangeSysTrayIcon(1,IdIcon2)
      ledon = #True
    EndIf
    
    If change = #False And ledon = #True
      SetScrollLED(#VK_SCROLL,#False)   
      ChangeSysTrayIcon(1,IdIcon1)
      ledon = #False
    EndIf  
    
    ;Delay (10) ;???
         
    If EventID = #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_RightClick ;Die Verarbeitung der rechten Maustaste
          DisplayPopupMenu(0, WindowID(0)) ;zeige Popup-Menü
      EndSelect
    EndIf
   
    If EventID = #PB_Event_Menu
      Select EventMenu()
        Case 1
          Quit = 1
        Case 2
          MessageRequester("HDD", "ScrollLock -Herunterladen HDD LED", #PB_MessageRequester_Ok)
      EndSelect
    EndIf
    
    If EventID = #PB_Event_CloseWindow  ; Beenden Sie das Programm
      Quit = 1
    EndIf

  Until Quit = 1
  
  SetScrollLED(#VK_SCROLL,#False)
  
EndIf

End
FF :wink:

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 22:46
von Bisonte
@Helle: Danke, Aber aus Ermangelung der .exe ist das probieren und nutzen nicht möglich...

Und das russische Dingens... ich kann kompilieren wie ich will, da flackert weder die Scroll LED noch das Icon im Systray...
Mit Debuganweisung an diversen Stellen, wird anscheinend nur einmal bei Programmstart ein "Schreib/Lese Event" entdeckt,
danach keins mehr. Weder als x86 noch als x64 Kompilat mit und ohne Debugger, keine Funktion bei mir... was mach ich da
falsch ?
Achja selbst die kompilierten Exen als Admin ausführen lassen... auch nix.

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 23:09
von Falko
Ich habe auch mal aus Jux die älteren PB-Compiler ausprobiert, als die aktuelle
Beta. Bei allen habe ich die schön blinkende Scroll-LED. Auch wenn ich das Scroll-Lock
ein und wieder ausschalte flackert sie zur Festplatte augenscheinlich synchron.

Nun wäre da evtl. der Gedanke, das der Virenscanner die Exe nicht ausführen läßt?
Wenn du exe probiert hast, hat es wohl keinen Sinn danach zu fragen, ob man dir
ein Kompilat vielleicht per Mail zusenden sollte.
[Edit]
Was auch sein kann, ist du mit zwei oder mehreren Festplatten arbeitest.
Folgendes steht in der API:
API CreateFile() hat geschrieben:Windows 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. The following requirements must be met in order for such a call to succeed:

· The caller must have administrative privileges for the operation to succeed on a hard disk drive.
· The lpFileName string should be of the form \\.\PHYSICALDRIVEx to open the hard disk x. Hard disk numbers start at zero. For example:

String Meaning
\\.\PHYSICALDRIVE2 Obtains a handle to the third physical drive on the user's computer.


· The lpFileName string should be \\.\x: to open a floppy drive x or a partition x on a hard disk. For example:

String Meaning
\\.\A: Obtains a handle to drive A on the user's computer.
\\.\C: Obtains a handle to drive C on the user's computer.
So könnte dann bei dir das Laufwerk was erkannt werden soll, dann so aussehen:
\\.\PHYSICALDRIVE1 oder \\.\PHYSICALDRIVE2 usw. Dann müsste man dazu noch
eine Programmroutine schreiben, die mehrere Festplatten dann überprüft und dementsprechend abfragt.
Ich habe mal zum Test, da ich ja nur ein Laufwerk habe eine andere Nummer vorgegeben.
Dann wird natürlich nichts angezeigt, da dieses Laufwerk nicht existiert und der Debugger
schlägt auch nicht darauf an, sowie die LED bleibt aus.
[/Edit]

Gruß,
Falko

Re: Festplattenaktivität feststellen ?

Verfasst: 05.01.2012 23:44
von Bisonte
Wenn ich aus dem

Code: Alles auswählen

"\\.\PhysicalDrive" + Str(CurrentDrive)
ein

Code: Alles auswählen

"\\.\C:"
mache gehts (natürlich nur bei C:)... merkwürdig, warum es dann bei anderen Usern funktioniert, ohne diese Änderung.