Idle_Timer bei aktiver Zelle

Informationen und Beispiele zu den hier genannten Dialog-Elementen:
MsgBox
Bild

Betrifft: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 09.09.2015 15:17:25

Hallo zusammen,
ich setze folgenden Idle Timer bei mir ein:


Function IdleTime() As Single
  Dim a As LASTINPUTINFO
  a.cbSize = LenB(a)
  GetLastInputInfo a
  IdleTime = (GetTickCount - a.dwTime) / 1000 'Idletime in Sekunden
End Function
Sub Idle_Timer()
    If IdleTime >= Time_To_Idle Then 'Vergleich Idletime mit Zeitvorgabe in Sekunden
        Call CloseIt
    End If
Application.OnTime Now + TimeValue("0:0:1"), "Idle_Timer2" 'Wiederholungsprüfung nach 1 Sekunde
End Sub
Sub Idle_Timer2()
    If IdleTime >= Time_To_Idle Then 'Vergleich Idletime mit Zeitvorgabe in Sekunden
        Call CloseIt
    End If
Application.OnTime Now + TimeValue("0:0:1"), "Idle_Timer" 'Wiederholungsprüfung nach 1 Sekunde
End Sub

Dies funktioniert soweit auch ganz gut, jedoch ist mir aufgefallen, dass eine angewählte Zelle in der der Cursor steht(blinkt) diesen Mechanismus außer Kraft setzt.
Hat jemand eine Idee, wie das umgangen werden kann?
Danke im Voraus
Marcus

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: fcs
Geschrieben am: 09.09.2015 15:31:13
Hallo Marcos,
keine Chance dies zu umgehen.
Anstehende OnTime-Ereignisse werden erst ausgeführt, wenn die Zellbearbeitung oder geöffnete Menüs/Dialoge beendet werden.
Gruß
Franz

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 09.09.2015 15:46:37
Hallo Franz,
siehst Du eine andere Möglichkeit die sekündliche Wiederholung zu realisieren?
Gruß Marcus

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Nepumuk
Geschrieben am: 09.09.2015 16:27:56
Hallo,
das geht schon, per API-Timer. Welche Aktion löst denn dein Timer bisher aus? Wenn du nämlich im Editiermodus bist und du willst per Timer in eine andere Zelle schreiben dann stürzt dir Excel ab.
Gruß
Nepumuk

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 09.09.2015 16:48:21
Hallo ausglöst wird der Timer durch Workbook_Open und über dann alle 1000ms ihn toggled , so der Plan.
Ich habe jetzt Folgendes gefunden und im Modul1 implementiert:

Option Explicit
'=============================================================================================== _
====================================================================
'=============================================================================================== _
====================================================================
'=============================================================================================== _
====================================================================
Private Const Time_To_Idle As Single = 60 ' Zeit nach der ausgeloggt werden soll in Sekunden
'=============================================================================================== _
====================================================================
'=============================================================================================== _
====================================================================
'=============================================================================================== _
====================================================================
Private Type LASTINPUTINFO
  cbSize As Long
  dwTime As Long
End Type
Private Declare PtrSafe Sub GetLastInputInfo Lib "user32" (ByRef plii As LASTINPUTINFO)
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
Public Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long,  _
ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As  _
Long
Public TimerID As Long
Public TimerSeconds As Single
'Sekundentakt starten
Sub StartTimer()
    TimerSeconds = 1
    TimerID = SetTimer(0&, 0&, TimerSeconds * 1000&, AddressOf TimerProc)
End Sub
'Sekundentakt beenden
Sub EndTimer()
    On Error Resume Next
    KillTimer 0&, TimerID
End Sub
'Inaktivität prüfen aufrufen im Sekundentakt
Sub TimerProc(ByVal HWnd As Long, ByVal uMsg As Long, ByVal nIDEvent As Long, ByVal dwTimer As  _
Long)
    'Inaktivität prüfen aufrufen
    Call Idle_Timer
End Sub
Function IdleTime() As Single
  Dim a As LASTINPUTINFO
  a.cbSize = LenB(a)
  GetLastInputInfo a
  IdleTime = (GetTickCount - a.dwTime) / 1000 'Idletime in Sekunden
End Function
Sub Idle_Timer()
    If IdleTime >= Time_To_Idle Then 'Vergleich Idletime mit Zeitvorgabe in Sekunden
        'Sekundentakt beenden
        Call EndTimer
        'Arbeitsmappe speichern und schließen
        ActiveWorkbook.Close savechanges:=True
    End If
End Sub
Aufgerufen wird der Timer in "DieseArbeitsmappe" mit:
Option Explicit
Private Sub Workbook_Open()
    'Sekundentakt starten
    Call StartTimer
    End Sub
Das funktioniert soweit auch, es resultiert jedoch ein Fehler von Excel mit diefferenzierendem Fehlercode.

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Nepumuk
Geschrieben am: 09.09.2015 16:55:08
Hallo,
du musst den Timer zwingend an die Application binden. Also:
TimerID = SetTimer(Application.hWnd, 0&, TimerSeconds * 1000&, AddressOf TimerProc)
KillTimer Application.hWnd, TimerID
Gruß
Nepumuk

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 09.09.2015 17:03:04
Auch dies führt leider immer noch zur Arbeitsverweigerung von Excel nach speichern und schließen der Datei. :-(

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Nepumuk
Geschrieben am: 09.09.2015 18:08:42
Hallo,
kannst du eine Mustermappe hochladen?
Gruß
Nepumuk

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 10.09.2015 08:22:19
Hallo Nepumuk,
habe es leider gestern nicht mehr geschafft, hier jetzt aber die Mustermappe:
https://www.herber.de/bbs/user/100110.xlsm
Gruß
Marcus

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 10.09.2015 11:55:42
Also ich habe mittlerweile herausgefunden, dass der Fehler dadurch verursacht wird, dass der Timer nicht beendet wird.
Mir ist jedoch nicht klar, warum er nicht beendet wird.

Option Explicit
'=============================================================================================== _
 _
====================================================================
'=============================================================================================== _
 _
====================================================================
'=============================================================================================== _
 _
====================================================================
Private Const Time_To_Idle As Single = 10 ' Zeit nach der ausgeloggt werden soll in Sekunden
'=============================================================================================== _
 _
====================================================================
'=============================================================================================== _
 _
====================================================================
'=============================================================================================== _
 _
====================================================================
Private Type LASTINPUTINFO
  cbSize As Long
  dwTime As Long
End Type
Private Declare PtrSafe Sub GetLastInputInfo Lib "user32" (ByRef plii As LASTINPUTINFO)
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
Public Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long,  _
ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As  _
Long
Public TimerID As Long
Public Initial As Boolean
'Sekundentakt starten
Sub StartTimer()
    TimerID = SetTimer(0&, 0&, 1000&, AddressOf TimerProc)
End Sub
'Sekundentakt beenden
Sub EndTimer()
    KillTimer 0&, TimerID
End Sub
'Inaktivität prüfen aufrufen im Sekundentakt
Sub TimerProc(ByVal HWnd As Long, ByVal uMsg As Long, ByVal nIDEvent As Long, ByVal dwTimer As  _
Long)
    'Inaktivität prüfen aufrufen
    If IdleTime >= Time_To_Idle Then 'Vergleich Idletime mit Zeitvorgabe in Sekunden
        'Sekundentakt beenden
        MsgBox "Erfüllt" & vbCr & IdleTime & vbCr & Time_To_Idle
        Call EndTimer
        'Arbeitsmappe speichern und schließen
'        ActiveWorkbook.Close savechanges:=True
    End If
End Sub
Function IdleTime() As Single
  Dim a As LASTINPUTINFO
  a.cbSize = LenB(a)
  GetLastInputInfo a
  IdleTime = (GetTickCount - a.dwTime) / 1000 'Idletime in Sekunden
End Function
Die hervorgehobene Stelle sollte dies eigentlich bewriken, tut es aber nicht.
Stoße ich Endtimer über einen Button an, funktioniert es.

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Nepumuk
Geschrieben am: 10.09.2015 12:53:07
Hallo,
ich hab jetzt alles mögliche versucht, aber es klappt nicht.
Sorry !!!
Gruß
Nepumuk

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 10.09.2015 15:13:55
Also das Problem liegt defintiv bei

ActiveWorkbook.Close
wobei savechanges hier keinen Unterschied macht.
Aber erklären kann ich es mir auch nicht.

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: EtoPHG
Geschrieben am: 10.09.2015 15:28:21
Hallo Marcus,
Was willst du den mit diesem Timer erreichen?
Wenn ich so zwischen den Zeilen lese und dazu fantasiere:
Du willst vermutlich die Arbeitsmappe schliessen, wenn eine bestimmte Zeit keine User-Aktion erfolgte.
Das könnte man mit anderen Mitteln erreichen.
Wenn ich mit meiner Annahme falsch liege, vergiss meinen Beitrag einfach. Ansonsten, erkläre bitte genau, was der Zweck des 'Timings' sein soll.
Gruess Hansueli

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 10.09.2015 15:51:52
Hallo Hansueli,
Du hast das Ziel genau richtig erkannt.
Die Arbeitsmappe soll nach einer definierten Zeit der Inaktivität gespeichert und geschlossen werden.
Bitte keine Grundsatzdikussion über die Sinnhaftigkeit, diese habe ich bereits ausführlich intern diskutiert, es ist jedoch so gewünscht.
Sollte deine Lösung auf Application.ontime abzielen, so möchte ich gleich vorweg nehmen, dass hier das Problem der Nichtbearbeitung bei angewählter Zelle besteht.
Ansonsten bin ich sehr gespannt.
Gruß Marcus

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: EtoPHG
Geschrieben am: 10.09.2015 17:13:13
Hallo Marcus,
Zitat:
Sollte deine Lösung auf Application.Ontime abzielen, so möchte ich gleich vorweg nehmen, dass hier das Problem der Nichtbearbeitung bei angewählter Zelle besteht.
Was für ein Problem genau? Wenn sich Excel im Editiermodus befindet, so ist die Application gesperrt, bis dieser Modus wieder verlassen wird. Da helfen keine Externen API / Timer oder VBA Code. Aber schliesslich hat der Anwender diesen Modus bewusst initiiert.
Immerhin würde die Datei automatisch geschlossen, sobald er den Editiermodus verlässt, was aber in ,meinen Augen wiederum eine Benutzeraktion ist, die den Timer auf 0 zurückstellen müsste, da er ja vielleicht eine weitere Aktion ausführen will.
Ja meine Idee war die Mouse-Koordinaten im Sekundentakt zu kontrollieren und wenn diese sich innerhalb dem definierten Zeitfenster nicht verändern, das OntimeMakro für das (sofortige) Schliessen der Datei zu initieren.
Gruess Hansueli

Bild

Betrifft: AW: Idle_Timer bei aktiver Zelle
von: Marcus Kempf
Geschrieben am: 10.09.2015 19:07:47
Hallo Hanueli,
das Problem besteht darin, dass das Makro bei aktivierter Zelle, also im Editiermodus, nicht abgearbeitet wird.
Ich Muss Dir leider gleich doppelt widersprechen, zum einen werden Makros auf API-Timer-Basis sehr wohl ausgeführt und zum anderen wird ein gestopptes ontime-Makro nicht direkt nach Verlassen des Editiermodus zu Ende geführt.
Dies wäre nur der Fall würde man genau den Moment der ontime-Toggelung treffen.
Zudem sehe ich es wie Du, dass das Verlassen des Editiermodus sehr wohl eine weitere Handlung des Bedieners ist und das speichern und schließen verhindern und nicht auslösen sollte.
Es geht eigentlich auch schon nicht mehr um die Art und Weise der Timer-Ausführung, sondern um die Frage warum Excel bei automatisiertem Aufruf des Makros "Endtimer" abstürzt, bei jeder Art händischen Aufrufes jedoch nicht.
Vielleicht sollte ich dazu einen neuen Thread eröffnen, denn dies hat ja eigentlich schon nichts mehr mit der eigentlichen Fragestellung zu tun.
Gruß
Marcus

Bild

Betrifft: widerspreche deinen Widersprüchen...
von: EtoPHG
Geschrieben am: 11.09.2015 09:34:58
Hallo Marcus,
Zitat: zum einen werden Makros auf API-Timer-Basis ... ist Quatsch. Natürlich können Prozesses asynchron zum VBA Code ablaufen, die über API-Schnittstellen vor dem Starten des Editiermodus in XL abgesetzt wurden. Keinesfalls wird aber irgendwelcher VBA-Code, ob mit oder ohne OnTime-Methode gestartet oder ausgeführt. Die Möglichkeit für XL weiteren VBA-Code auszuführen ist erst nach dem Verlassen des Editiermodus wieder gegeben.
Zitat: ...Ontime Schedule=False...Dies wäre nur der Fall würde man genau den Moment der ontime-Toggelung treffen. auch das ist Quatsch. Die OnTime-Methode macht nichts anderes als eine Queue zu füllen. Die Queue-Kontrolle läuft Asynchron zu XL. Entscheidend ist: Die Ausführung kann nur dann gestartet werden, wenn XL für die VBA-Kontrolle bereit ist, also sicher nicht im Editiermodus! Das kann in der XL Hilfe zur OnTime Methode nachgelesen werden:
XL Hilfe:EarliestTime : Die Zeit, zu der diese Prozedur ausgeführt werden soll.
Man beachte: werden soll, nicht wird! D.h. die Prozedur wird nach diesem definierten Zeitpunkt ausgeführt, sobald XL in der Lage ist VBA-Code auszuführen. Also z.B. nach der Aufhebung des Editiermodus!
XL Hilfe:LatestTime : Der späteste Zeitpunkt zum Ausführen der Prozedur. Wenn beispielsweise LatestTime auf EarliestTime + 30 festgelegt wird und Microsoft Excel sich nicht für EarliestTime im Modus Ready, Copy, Cut oder Find befindet, da eine andere Prozedur ausgeführt wird, wird in Microsoft Excel 30 Sekunden auf das Beenden der ersten Prozedur gewartet. Wenn sich Microsoft Excel innerhalb von 30 Sekunden nicht im Modus Ready befindet, wird die Prozedur nicht ausgeführt. Wenn dieses Argument nicht angegeben wird, wartet Microsoft Excel, bis die Prozedur ausgeführt werden kann.
Fazit: Ein Aufheben des Editiermodus von XL, könnte ggf. durch ein komplett entkoppeltes externes Programm ausgeführt werden, indem dieses die Zeit überwacht, in der sich XL in diesem Modus befindet und es durch einen SendKey {ESCAPE} veranlasst diesen zu verlassen und damit wieder in der Lage ist VBA-Code auszuführen.
Eine ziemlich aufwändiges Projekt, dass IMHO für den 'Editierfall' aufwandmässig nicht vertretbar ist.
Gruess Hansueli

Bild

Betrifft: AW: widerspreche deinen Widersprüchen...
von: Marcus Kempf
Geschrieben am: 11.09.2015 09:45:37
Hallo Hanueli,
dann verstehe ich das Verhalten der angehänten Excel-Datei erst recht nicht mehr.
Bitte tue mir den Gefallen und öffne die Mappe, beschreibe eine Zelle und lasse sie angewählt.
Nach deiner Ausführung dürfte nach 10 Sekunden Inaktivität nichts passieren.
Datei mit API-Timer: https://www.herber.de/bbs/user/100126.xlsm
Bitte versuche es wegen mir auch mit dem folgenden Code und Du wirst sehen, dass OnTime-Makro wird nicht wie von dir beschrieben reagieren.

                Function IdleTime() As Single
                  Dim a As LASTINPUTINFO
                  a.cbSize = LenB(a)
                  GetLastInputInfo a
                  IdleTime = (GetTickCount - a.dwTime) / 1000 'Idletime in Sekunden
                End Function
                
                Sub Idle_Timer()
                    If IdleTime >= Time_To_Idle Then 'Vergleich Idletime mit Zeitvorgabe in  _
Sekunden
                        msgbox "OnTime ausgeführt"
                    End If
                Application.OnTime Now + TimeValue("0:0:1"), "Idle_Timer2" 'Wiederholungsprü _
fung nach 1 Sekunde
                End Sub
                
                Sub Idle_Timer2()
                    If IdleTime >= Time_To_Idle Then 'Vergleich Idletime mit Zeitvorgabe in  _
Sekunden
                        msgbox "OnTime ausgeführt"
                    End If
                Application.OnTime Now + TimeValue("0:0:1"), "Idle_Timer" 'Wiederholungsprüfung  _
nach 1 Sekunde
                End Sub
Gruß
Marcus

Bild

Betrifft: AW: widerspreche deinen Widersprüchen...
von: EtoPHG
Geschrieben am: 11.09.2015 10:06:56
Hallo Marcus,
Deine Beispielmappe verhält sich bei mir so:
a) Öffnen - nichts tun - Die Mappe schliesst sich automatisch nach 10 Sekunden ohne irgendwelche Meldungen.
b) Öffne - innerhalb von 10 Sekunden in den Editiermodus gehen - Mind. 10 Sekunden im Editiermodus bleiben - Editiermodus verlassen - Die Mappe schliesst sich automatisch 10 Sekunden nach Verlassen des Editiermodus ohne irgendwelche Meldungen.
Das ist alles. Zu deinem 'Irrsinns-Code' des 2ten Vorschlags äussere ich mich nicht weiter, weil ich nicht verstehe, was du damit zeigen willst. Lies nochmals die Hilfe zur OnTime-Methode und beachte, dass zu einem 'OnTime-Start' (Schedule=True) immer auch ein 'OnTime-Ende' ) (Schedule=False) gehört!
Gruess Hansueli

 Bild

Beiträge aus den Excel-Beispielen zum Thema "Idle_Timer bei aktiver Zelle"