Seite 1 von 1

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

Verfasst: 27.06.2009 10:16
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

Verfasst: 27.06.2009 10:32
von edel
Was du suchst nennt sich SetTimer. Einfach hier im Forum suchen.

Verfasst: 27.06.2009 10:41
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

Verfasst: 27.06.2009 13:25
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

Verfasst: 05.07.2009 17:33
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

Verfasst: 06.07.2009 00:53
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

Verfasst: 06.07.2009 13:20
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

Verfasst: 07.07.2009 01:34
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