Zeitliche Abfragen im Systray; Suche 'guten/optimalen' Code

Anfängerfragen zum Programmieren mit PureBasic.
Kaltstart
Beiträge: 17
Registriert: 27.07.2008 12:43

Zeitliche Abfragen im Systray; Suche 'guten/optimalen' Code

Beitrag von Kaltstart »

Ich möchte im Systray eine Anwendung welche mir alle x Minuten eine Systemabfrage startet.
(Im konkreten Fall: -Wieviel Speicherplatz ist noch auf Laufwerk C:, bzw. Sende einen Ping und warte auf Rückmeldung)

Immer mal wieder lese ich im Board dazu Themen über Prozessorauslastung und Timerschleifen, Threads, etc..

Daher wieder einmal meine Frage wie man so etwas am besten 'richtig' programmiert:
- Wie baut man denn grundsätzliche eine Schleife für so eine Anwendung auf?
- Kennt jemand ein 'gutes' Grundgerüst für eine solche Anwendung?

(Mir geht es nur um den Beispiel-Code für die 'Zeitschleife' (Alle z.B: 5 Minuten eine Abfrage; dazwischen 'ruhen' und die anderen Programme (Prozessor,etc..) so wenig als möglich 'stören/belasten'.)

Danke
Kaltstart
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Was du suchst nennt sich SetTimer. Einfach hier im Forum suchen.
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag von cxAlex »

Einfach via Timer alle x - Minuten eine Abfrage starten und mit einem Systray - Icon koppeln. So sollte das gehen, die Abfrage musst du noch selbst machen:

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; Easy Timer
; Einfacher leicht erweiterbarer Timer
; PB 4.3 +
; Alexander Aigner
; V 1.0
; ------------------------------------------------------------------------------------

; ------------------------------------------------------------------------------------
; Internes Zeugs
; ------------------------------------------------------------------------------------

; ------------------------------------------------------------------------------------
; HighRes - Timer
; ------------------------------------------------------------------------------------
EnableExplicit

Prototype HR_Time()

Structure _HR_Internal
  StartTime.q
  Res.d
EndStructure

Define _HR._HR_Internal
Global GetTimeMS.HR_Time

Procedure _HR_InitTime()
  Shared _HR._HR_Internal
  Protected Frequency.q
  With _HR
    If Not QueryPerformanceFrequency_(@Frequency)
      ProcedureReturn #False
    Else
      QueryPerformanceCounter_(@\StartTime)
      \Res = 1000/Frequency
      ProcedureReturn #True
    EndIf
  EndWith
EndProcedure

Procedure _HR_Get()
  Shared _HR._HR_Internal
  Protected currentTime.q
  With _HR
    QueryPerformanceCounter_(@currentTime)
    ProcedureReturn (currentTime-\StartTime)*\Res
  EndWith
EndProcedure

Procedure _HR_oldPC_or_Linux()
  ProcedureReturn ElapsedMilliseconds()
EndProcedure

; Initialisierung des High-Res Timers

CompilerIf #PB_Compiler_OS<>#PB_OS_Windows
  GetTimeMS = @_HR_oldPC_or_Linux()
CompilerElse
  If _HR_InitTime()
    GetTimeMS = @_HR_Get()
  Else
    GetTimeMS = @_HR_oldPC_or_Linux()
  EndIf
CompilerEndIf

; ------------------------------------------------------------------------------------
; Eigentlicher Timer
; ------------------------------------------------------------------------------------

Prototype ET_Procedure(Event, UserData)

Enumeration ; Sollte klar sein ...
  #ET_Call
  #ET_Pause
  #ET_Resume
  #ET_Free
EndEnumeration

Structure ET_Data
  *CB.ET_Procedure
  UserData.i
  Delay.i
  CBEvent.i
  CBEventStop.i
  CBEventPause.i
EndStructure

Procedure _ET_Thread(*ET.ET_Data)
  Protected cTime, wTime
  With *ET
    wTime = \Delay
    Repeat
      
      cTime = GetTimeMS()
      While wTime>GetTimeMS()-cTime
        Delay(1)
      Wend
      
      If \CBEvent ; Nur 1. If-Abfrage für (später) beliebie viele Events
        If \CBEventPause ; Pausesignal
          \CB(#ET_Pause, \UserData)
          WaitSemaphore(\CBEventPause)
          \CB(#ET_Resume, \UserData)
        EndIf
        If \CBEventStop ; Stopsignal
          \CB(#ET_Free, \UserData)
          SignalSemaphore(\CBEventStop)
          ProcedureReturn #Null
        EndIf
        \CBEvent = #False
      EndIf
      
      ; Callback aufrufen und Ausgleichszeit errechnen
      cTime = GetTimeMS()
      \CB(#ET_Call, \UserData)
      wTime = \Delay-GetTimeMS() + cTime
      
      ; Delay(<0) = warte unendlich
      If wTime<0
        wTime = #Null
      EndIf
      
    ForEver
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
; Proceduren
; ------------------------------------------------------------------------------------

; Neuen Timer anlegen
Procedure ET_New(*Callback.ET_Procedure, Delay.i, UserData.i)
  Protected *ET.ET_Data = AllocateMemory(SizeOf(ET_Data))
  With *ET
    \CB = *Callback
    \Delay = Delay
    \UserData = UserData
    CreateThread(@_ET_Thread(), *ET)
    ProcedureReturn *ET
  EndWith
EndProcedure

; Timer pausieren
Procedure ET_Pause(*ET.ET_Data)
  With *ET
    If Not \CBEventPause
      \CBEventPause = CreateSemaphore()
      \CBEvent = #True
    EndIf
  EndWith
EndProcedure

; Timer fortsetzen
Procedure ET_Resume(*ET.ET_Data)
  With *ET
    If \CBEventPause
      SignalSemaphore(\CBEventPause)
      FreeSemaphore(\CBEventPause)
    EndIf
  EndWith
EndProcedure

; Timer freigeben
Procedure ET_Free(*ET.ET_Data)
  With *ET
    \CBEventStop = CreateSemaphore()
    \CBEvent = #True
    ET_Resume(*ET) ; Wenn nötig fortsetzen
    WaitSemaphore(\CBEventStop)
    FreeSemaphore(\CBEventStop)
    FreeMemory(*ET)
  EndWith
EndProcedure

DisableExplicit


Procedure Test(Event, Dummy)
  MessageRequester("Call","Call")
EndProcedure

; Timer auf 1. Minut stellen
Timer = ET_New(@Test(), 1*60000, #Null)

Image = LoadImage(#PB_Any, #PB_Compiler_Home+"Examples\Sources\Data\CdPlayer.ico")

Dummy = OpenWindow(#PB_Any, 0, 0, 0, 0, "", #PB_Window_Invisible)
AddSysTrayIcon(#PB_Any, WindowID(Dummy), ImageID(Image))

Popup = CreatePopupMenu(#PB_Any)
MenuItem(1, "Exit")

Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_Menu
      Select EventMenu()
        Case 1
          ET_Free(Timer)
          End
      EndSelect
    Case #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_LeftClick, #PB_EventType_RightClick
          DisplayPopupMenu(Popup, WindowID(Dummy))
      EndSelect
  EndSelect
Until #False

Gruß, Alex
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Kaltstart
Beiträge: 17
Registriert: 27.07.2008 12:43

Beitrag von Kaltstart »

Hallo cxAlex,

WOW! Also mit SetTimer(). Danke für den kompletten Beispielcode!

OK.
Mite dem 'EXIT' habe ich noch Probleme. Er führt den Exit erst aus wenn der Timer wieder ausgelaufen ist.

Das muss ich mir jetzt aber dann erst in aller Ruhe 'auseinanderpfümeln'

Gruss
Kaltstart
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag von cxAlex »

Kaltstart hat geschrieben: Mite dem 'EXIT' habe ich noch Probleme. Er führt den Exit erst aus wenn der Timer wieder ausgelaufen ist.
Hab den Code aktualisiert, nun sollte das Exit sofort ausgeführt werden:

http://www.purebasic.fr/german/viewtopi ... 815#244815
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Kaltstart
Beiträge: 17
Registriert: 27.07.2008 12:43

Beitrag von Kaltstart »

Hi cxAlex,

habe die Procedure ausgetauscht.
Nun bleibt er aber komplett hängen.

Schaue es mir morgen/heute nochmals genauer an.
Danke Dir

Gruss
Kaltstart
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag von cxAlex »

So funktioniert bei mir alles korrekt:

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; Easy Timer
; Einfacher leicht erweiterbarer Timer
; PB 4.3 +
; Alexander Aigner
; V 1.0
; ------------------------------------------------------------------------------------

; ------------------------------------------------------------------------------------
; Internes Zeugs
; ------------------------------------------------------------------------------------

; ------------------------------------------------------------------------------------
; HighRes - Timer
; ------------------------------------------------------------------------------------
EnableExplicit

Prototype HR_Time()

Structure _HR_Internal
  StartTime.q
  Res.d
EndStructure

Define _HR._HR_Internal
Global GetTimeMS.HR_Time

Procedure _HR_InitTime()
  Shared _HR._HR_Internal
  Protected Frequency.q
  With _HR
    If Not QueryPerformanceFrequency_(@Frequency)
      ProcedureReturn #False
    Else
      QueryPerformanceCounter_(@\StartTime)
      \Res = 1000/Frequency
      ProcedureReturn #True
    EndIf
  EndWith
EndProcedure

Procedure _HR_Get()
  Shared _HR._HR_Internal
  Protected currentTime.q
  With _HR
    QueryPerformanceCounter_(@currentTime)
    ProcedureReturn (currentTime-\StartTime)*\Res
  EndWith
EndProcedure

Procedure _HR_oldPC_or_Linux()
  ProcedureReturn ElapsedMilliseconds()
EndProcedure

; Initialisierung des High-Res Timers

CompilerIf #PB_Compiler_OS<>#PB_OS_Windows
  GetTimeMS = @_HR_oldPC_or_Linux()
CompilerElse
  If _HR_InitTime()
    GetTimeMS = @_HR_Get()
  Else
    GetTimeMS = @_HR_oldPC_or_Linux()
  EndIf
CompilerEndIf

; ------------------------------------------------------------------------------------
; Eigentlicher Timer
; ------------------------------------------------------------------------------------

Prototype ET_Procedure(Event, UserData)

Enumeration ; Sollte klar sein ...
  #ET_Call
  #ET_Pause
  #ET_Resume
  #ET_Free
EndEnumeration

Structure ET_Data
  *CB.ET_Procedure
  UserData.i
  Delay.i
  CBEvent.i
  CBEventStop.i
  CBEventPause.i
EndStructure

Procedure _ET_Thread(*ET.ET_Data)
  Protected cTime, wTime
  With *ET
    wTime = \Delay
    Repeat
      
      If \CBEvent ; Nur 1. If-Abfrage für (später) beliebie viele Events
        If \CBEventPause ; Pausesignal
          \CB(#ET_Pause, \UserData)
          WaitSemaphore(\CBEventPause)
          \CB(#ET_Resume, \UserData)
        EndIf
        If \CBEventStop ; Stopsignal
          \CB(#ET_Free, \UserData)
          SignalSemaphore(\CBEventStop)
          ProcedureReturn #Null
        EndIf
        \CBEvent = #False
      EndIf
      
      cTime = GetTimeMS()
      While wTime>GetTimeMS()-cTime
        Delay(1)
        If \CBEvent ; Nur 1. If-Abfrage für (später) beliebie viele Events
          If \CBEventPause ; Pausesignal
            \CB(#ET_Pause, \UserData)
            WaitSemaphore(\CBEventPause)
            \CB(#ET_Resume, \UserData)
          EndIf
          If \CBEventStop ; Stopsignal
            \CB(#ET_Free, \UserData)
            SignalSemaphore(\CBEventStop)
            ProcedureReturn #Null
          EndIf
          \CBEvent = #False
        EndIf
      Wend
      
      ; Callback aufrufen und Ausgleichszeit errechnen
      cTime = GetTimeMS()
      \CB(#ET_Call, \UserData)
      wTime = \Delay-GetTimeMS() + cTime
      
      ; Delay(<0) = warte unendlich
      If wTime<0
        wTime = #Null
      EndIf
      
    ForEver
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
; Proceduren
; ------------------------------------------------------------------------------------

; Neuen Timer anlegen
Procedure ET_New(*Callback.ET_Procedure, Delay.i, UserData.i)
  Protected *ET.ET_Data = AllocateMemory(SizeOf(ET_Data))
  With *ET
    \CB = *Callback
    \Delay = Delay
    \UserData = UserData
    CreateThread(@_ET_Thread(), *ET)
    ProcedureReturn *ET
  EndWith
EndProcedure

; Timer pausieren
Procedure ET_Pause(*ET.ET_Data)
  With *ET
    If Not \CBEventPause
      \CBEventPause = CreateSemaphore()
      \CBEvent = #True
    EndIf
  EndWith
EndProcedure

; Timer fortsetzen
Procedure ET_Resume(*ET.ET_Data)
  With *ET
    If \CBEventPause
      SignalSemaphore(\CBEventPause)
      FreeSemaphore(\CBEventPause)
    EndIf
  EndWith
EndProcedure

; Timer freigeben
Procedure ET_Free(*ET.ET_Data)
  With *ET
    \CBEventStop = CreateSemaphore()
    \CBEvent = #True
    ET_Resume(*ET) ; Wenn nötig fortsetzen
    WaitSemaphore(\CBEventStop)
    FreeSemaphore(\CBEventStop)
    FreeMemory(*ET)
  EndWith
EndProcedure

DisableExplicit






Procedure Test(Event, Dummy)
  If Event = #ET_Call
    MessageRequester("Call", "Call")
  EndIf
EndProcedure

; Timer auf 1. Minut stellen
Timer = ET_New(@Test(), 1*60000, #Null)

Image = LoadImage(#PB_Any, #PB_Compiler_Home + "Examples\Sources\Data\CdPlayer.ico")

Dummy = OpenWindow(#PB_Any, 0, 0, 0, 0, "", #PB_Window_Invisible)
AddSysTrayIcon(#PB_Any, WindowID(Dummy), ImageID(Image))

Popup = CreatePopupMenu(#PB_Any)
MenuItem(1, "Exit")

Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_Menu
      Select EventMenu()
        Case 1
          ET_Free(Timer)
          End
      EndSelect
    Case #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_LeftClick, #PB_EventType_RightClick
          DisplayPopupMenu(Popup, WindowID(Dummy))
      EndSelect
  EndSelect
Until #False
Gruß, Alex
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Kaltstart
Beiträge: 17
Registriert: 27.07.2008 12:43

Beitrag von Kaltstart »

Hallo cxAlex,

es funktioniert! (Natürlich :) )

Auch wenn ich vom Ablauf her (noch) nicht alles verstehe ist das genau das was ich gesucht habe.

Auf der anderen Seite zeigt es mir aber auch, daß PureBasic genau die Programmiersprache ist, welche ich gesucht habe. (...und sich damit die Programmieranforderungen - welche ich habe - umsetzen lassen.)

Danke und Gruss
Kaltstart
Antworten