Hat schon mal jemand in Access 2003 eine Art Inaktivitätsüberwachung
realisiert???
Ziel ist es, die Aktivität des Nutzers zu Überwachen und ihn nach X
Minuten nichtstun automatisch auszuloggen und den Login-Bildschirm
anzuzeigen?
In C++ hab ich so etwas ähnliches mal realisiert indem ich die
Datenbankzugriff überwacht habe, welche alle über mein Datenbank-Objekt
liefen und dann immer den Auslog-Timer zurückgesetzt. In Access ist das
leider wesentlich schiweriger, da die Aktivitäten ja nicht über ein
Objekt laufen.
Habe im Moment keine richtige Ahnung wo ich da ansetzen könnte, wenn ich
nicht in jede prozedur/Funktion einen Aufruf setzen möchte!
Lutz
Meinst Du wirklich ausloggen, bzw. abmelden und nicht sperren? Das OS
kann das schon, IMHO kannst Du auf die Funktionen zurück greifen.
Servus
Winfried
--
Connect2WSUS: http://www.grurili.de/tools/Connect2WSUS.exe
Community Forums NNTP Bridge: http://communitybridge.codeplex.com/
Access-FAQ: http://www.donkarl.com/AccessFAQ.htm
Access-Stammtisch: http://www.access-muenchen.de
Da hab ich mich wohl unklar ausgedrückt.
Ich meinte innerhalb meiner Anwendung ausloggen und danach das
Login-Formular meiner Anwendung anzeigen.
An dem Rechner arbeiten mehrere Leute unter demselben Windows-Account.
Lutz Uhlmann schrieb:
> Ich meinte innerhalb meiner Anwendung ausloggen und danach das
> Login-Formular meiner Anwendung anzeigen.
> An dem Rechner arbeiten mehrere Leute unter demselben Windows-Account.
Ab wann ist ein User für dich inaktiv?
Ist das von Tastaturklicks oder Mausbewegungen abhängig oder hängt das
davon ab, ob die Anwendung den Fokus hat?
mfg
Josef
Tastaturklicks und Mausbewegungen würde ich ignorieren, Inaktivität
heißt kein Lesen und Schreiben von Daten.
Weiß nicht ob mir der Fokus hilft. Es kann durchaus sein, daß die
Anwendung als Einzige offen ist und den ganzen Tag im Vordergrund liegt.
Ich stelle mir das so vor, daß in einem versteckten Formular ein Zähler
per Timer hochzählt und beim Erreichen von X wird das Ausloggen angestoßen.
Jetzt brauch ich nur noch einen Weg den Zähler bei Aktivitäten
zuverlässig zurückzusetzen.
Wenn das besser zu machen ist, kann der Zähler natürlich auch durch jede
Mausbewegung oder Tastenklick zurückgesetzt werden.
Lutz Uhlmann schrieb:
> Tastaturklicks und Mausbewegungen würde ich ignorieren, Inaktivität
> heißt kein Lesen und Schreiben von Daten.
Wie willst du prüfen, ob jemand die Daten liest?
... Bewegung der Augen überwachen? :-)))
> Wenn das besser zu machen ist, kann der Zähler natürlich auch durch jede
> Mausbewegung oder Tastenklick zurückgesetzt werden.
Das wäre zwar etwas Programmier-Aufwand, aber diese Ereignisse
könntest du ja in jedem Formular abfangen. (Gekapselt in einer kleinen
Hilfsklasse sollte das einigermaßen brauchbar werden.)
Vermutlich würde das auch über subclassing laufen. Subclassing von
Window-Messages ist aber in VBA nicht besonders stabil.
mfg
Josef
Lutz Uhlmann wrote:
> Am 10.03.2011 11:19, schrieb Josef Poetzl:
> Tastaturklicks und Mausbewegungen würde ich ignorieren, Inaktivität
> heißt kein Lesen und Schreiben von Daten.
Du könntest z.B. das DateLastAccessed oder DateLastModified des File Objects
des FileSystemObjects dafür verwenden.
Hier ein Beispiel (evt. auf den Namen der Backend wechseln, falls in FE/BE
aufgeteilt):
Dim objFSO As Object
Dim objFile As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile(CurrentDb.Name)
If DateDiff("s", CDate(objFile.DateLastAccessed), Now()) > 60 Then
MsgBox "Jetzt wär's Zeit den Logon Dialog anzuzeigen."
End If
Set objFile = Nothing
Set objFSO = Nothing
Allerdings werden da vermutlich nur Schreiboperationen dazu führen, diesen
Wert des MDB Files zu ändern.
Gruss
Henry
Lutz Uhlmann wrote:
> Wenn das besser zu machen ist, kann der Zähler natürlich auch durch jede
> Mausbewegung oder Tastenklick zurückgesetzt werden.
Wieviele Formulare sind es denn, da allenfalls den Focus haben? Du müsstest
nämlich für jedes Formular den MouseMove, MouseDown und KeyDown Event
auswerten und dann eine globale DatumZeit Variable zurücksetzen. Wäre so
schon machbar. Access hat unglücklicherweise keine gloablen Eregnisse,
sondern nur solche, die an Forms und Controls gebunden sind.
Gruss
Henry
Lesen im Sinne von Abrufen.
Bei meiner C++-Variante war das einfach, da dort jeder Datenabruf und
jedes Schreiben von Daten über mein Datenbank-Objekt lief. Gekapselt in
einer Funktion wurde da immer der Zähler zurückgesetzt.
Bei Access ist das ja alles schon integriert ... da kommt man wohl nicht
ran.
Wo müßte man da überhaupt einhaken? Currentdb, Gebundene Formulare ...
worüber läuft da eigentlich der Datenfluss? DbEngine???
>> Wenn das besser zu machen ist, kann der Zähler natürlich auch durch jede
>> Mausbewegung oder Tastenklick zurückgesetzt werden.
>
> Das wäre zwar etwas Programmier-Aufwand, aber diese Ereignisse
> könntest du ja in jedem Formular abfangen. (Gekapselt in einer kleinen
> Hilfsklasse sollte das einigermaßen brauchbar werden.)
In der Richtung hab ich leider noch wenig gemacht.
Kennst du Code-Beispiele?
Lutz
Lutz Uhlmann schrieb:
> Bei meiner C++-Variante war das einfach, da dort jeder Datenabruf und
> jedes Schreiben von Daten über mein Datenbank-Objekt lief. Gekapselt in
> einer Funktion wurde da immer der Zähler zurückgesetzt.
>
> Bei Access ist das ja alles schon integriert ... da kommt man wohl nicht
> ran.
> Wo müßte man da überhaupt einhaken? Currentdb, Gebundene Formulare ...
> worüber läuft da eigentlich der Datenfluss? DbEngine???
Das kommt darauf an, was du im Formular verwendest.
Wenn du die Access-Standards verwendest, läuft es im Prinzip über
DbEngine - das hilft dir aber leider auch nichts, da du in diesen
Zugriff trotzdem eingreifen kannst.
Eine (ungetestete) Idee:
Was wäre, wenn du in alle Datenquellen der Formular ein berechnetes
Feld im Select-Teil bzw. ein unsichtbares Steuerelement in allen
Detailbereichen einen Funktionsaufruf unterbringst?
Dann sollte die Funktion eigentlich bei jedem DS-Wechsel gestartet
werden und du könntest in dieser Funktion deinen Zähler zurücksetzen.
Ich würde allerdings eher zur Beobachtung der Mausbewegung bzw.
Tastenklicks neigen, damit der User die Chance hat, etwas mehr als ein
paar Minuten einen Datensatz ungestört zu lesen (falls das in der
Anwendung vorkommen könnte).
mfg
Josef
Also wenn ich das richtig sehe, geht der Weg im Moment nur darüber alle
Formulare anzufassen (was leider nicht wenige sind!).
Gibt es nicht irgendwie die Möglichkeit einen Mouse- oder Tastatur-hook
zu nutzen???
Wenn du mich schon ansprichst, obwohl ich bisher nicht dabei war... ;-)
dann schick ich dir halt auch was:
Vielleicht reicht dir ja sowas schlichtes wie in der KB:
http://support.microsoft.com/kb/210297
Die prüfen einfach, wie lange das aktuelle Formular und
Steuerelement unverändert ist.
--
Servus
Karl
*********
Access-FAQ: http://www.donkarl.com
Da fällt mir gerade etwas ein ...
Es gibt doch sicher API-Funktionen zur Abfrage der Mausposition?
Da es ziemlich unwahrscheinlich ist, daß ein Nutzer die Maus wieder auf
dem selben Pixel "parkt" könnte man doch regelmäßig diese Position
abfragen und deren Veränderung als Aktivität werten. Dies funktioniert
natürlich nur wenn die Anwendung den Fokus hat. Hat sie ihn nicht sollte
sie prinzipiell als inaktiv angesehen werden.
Hab dich mit Henry verwechselt ... hier sieht aber auch eine NG-Ikone
wie die andere aus ;)
> Vielleicht reicht dir ja sowas schlichtes wie in der KB:
> http://support.microsoft.com/kb/210297
>
> Die prüfen einfach, wie lange das aktuelle Formular und
> Steuerelement unverändert ist.
Danke, schau ich mir mal an ...
Joo und fesch sind wir auch beide:
http://www.donkarl.com/AEK/AEK10Bilder/CIMG5385.JPG
Lutz Uhlmann wrote:
> Ziel ist es, die Aktivität des Nutzers zu Überwachen und ihn nach X
> Minuten nichtstun automatisch auszuloggen und den Login-Bildschirm
> anzuzeigen?
Ich bin jetzt nicht in die Details des Threads eingestiegen, sondern möchte
es mir einfach machen, und möchte Dir lediglich ein paar Links zurücklassen,
die sich mit dem Thema "kick em off" befassen. Vielleicht ist ja ein für
Dich brauchbarer Ansatz dabei.
KickEm
http://www.datastrat.com/Download2.html
ForceUserOut
http://www.rogersaccesslibrary.com/forum/forum_posts.asp?TID=151
LogUsersOffNonUse
http://www.rogersaccesslibrary.com/forum/forum_posts.asp?TID=327
LogUsersOff
http://www.rogersaccesslibrary.com/forum/forum_posts.asp?TID=328
Auto-Logout
http://www.amazecreations.com/datafast/Download.aspx
Benutzer aus der Datenbank herauswerfen
http://www.dbwiki.de/wiki.php?title=Access_Beispieldatenbanken
--
Gruss
Jens
Danke, aber ich trage nie eine Sonnenbrille, obwohl es hier angebrachter
wᅵre als im nebelig trᅵben Wien ;-)
Gruss
Henry
Lutz Uhlmann wrote:
> Es gibt doch sicher API-Funktionen zur Abfrage der Mausposition?
> Da es ziemlich unwahrscheinlich ist, daß ein Nutzer die Maus wieder auf
> dem selben Pixel "parkt" könnte man doch regelmäßig diese Position
> abfragen und deren Veränderung als Aktivität werten. Dies funktioniert
> natürlich nur wenn die Anwendung den Fokus hat. Hat sie ihn nicht sollte
> sie prinzipiell als inaktiv angesehen werden.
Es ist zwar unwahrscheinlich, aber wenn ich Text schreibe, z.B. ein
Programm, kann es durchaus sein, dass ich die Maus länger nicht anfasse.
Dafür gib's Cursor Tasten und Tabulatoren. Falls Du dieses auswerten willst,
musst Du gleichzeitig auch noch die Tastatur auswerten, auch für diese gibt
es einen Hook per API. Könnte dann aber sein, dass Dein Programm von
Virenwächtern abgewiesen wird, weil das für die Tools vorgesehen ist, die
wir hier lieber nicht auf der Maschine haben, weil diese z.B. Passworte
ausschnüffeln.
Gruss
Henry
Danke für die Links!
> LogUsersOffNonUse
> http://www.rogersaccesslibrary.com/forum/forum_posts.asp?TID=327
Der klingt erstmal interessant, da er anscheinend auch mein Problem mit
der Aktivität des Nutzers berücksichtigt.
> Auto-Logout
> http://www.amazecreations.com/datafast/Download.aspx
>
>
> Benutzer aus der Datenbank herauswerfen
> http://www.dbwiki.de/wiki.php?title=Access_Beispieldatenbanken
Die letzten beiden scheinen nicht mehr zu exisitieren.
Wahrscheinlich ist Karls Tipp ganz brauchbar ActiveForm und
ActiveControl zu überwachen. Um deinen Einwand abzudecken müßte ich
wahrscheinlich noch eine evtl vorhandene Text-Eigenschaft des
ActiveControls überwachen.
Lutz
Jau, das ist wirklich eine gute Idee. Solange der Benutzer nicht Tabellen,
Abfragen oder Berichte vor sich hat, wird das auch problemlos funktionieren.
Und in einer vernünftigen Anwendung hat der Benutzer in Tabellen und
Abfragen sowieso nichts verloren. Würde also noch irgendwas für Berichte
notwendig sein.
Ansonsten eine kleine Erweiterung der Funktion und auch ActiveReport und
ActiveDatasheet mit einbeziehen.
Gruss
Henry
In unserer Anwendung arbeiten die Nutzer prinzipiell nur über Formularen.
Einzige Ausnahmen wären wie gesagt Berichte und bei manchen Auswertungen
werden noch Abfragen direkt angezeigt (readonly).
Da könnte man ja deine beiden Vorschläge mit einbeziehen.
Klingt für mich bisher am Vernünftigsten!!!
Frage nebenher: Wenn gerade eine Messagebox offen ist.
ActiveForm müsste weiter das die MsgBox aufrufende Form bleiben?
Die MsgBox blockiert nicht meinen Timer des unsichtbaren Formulars?
Wie kann ich die MsgBox schliessen? Über SendKeys???
Wieso testest Du das nicht selber? kannst ja dann schauen, was passiert.
Falls Dein Code im versteckten Formular nicht läuft, weil die MsgBox
angezeigt wird, wird die MsgBox kaum über SendKeys beendet werden können.
Zudem kannst Du SendKeys streichen, ist am sterben.
Falls das ein Problem sein könnte, müsstest Du die (oder alle) MsgBoxen als
TimedMsgBox auslegen.
Public Function timedMsgBox( _
Text As String, _
Optional Seconds As Long = 0, _
Optional Title As String = vbNullString, _
Optional Options As VbMsgBoxStyle) As Long
Dim wsh As Object
Set wsh = CreateObject("WScript.Shell")
timedMsgBox = wsh.PopUp(Text, _
Seconds, _
Title, _
Options)
Set wsh = Nothing
End Function
HTH
Henry
Da mir das spontan beim Schreiben des Beitrages einfiel.
Hab es deswegen vorher nicht selber getestet.
Werd es mal probieren!
> Falls das ein Problem sein könnte, müsstest Du die (oder alle) MsgBoxen
> als TimedMsgBox auslegen.
>
> Public Function timedMsgBox()
> ...
> End Function
Welches Ergebnis liefert so eine MsgBox dann?
Das Ergebnis vom DefaultButton?
Lutz Uhlmann wrote:
> Da mir das spontan beim Schreiben des Beitrages einfiel.
> Hab es deswegen vorher nicht selber getestet.
> Werd es mal probieren!
>> Public Function timedMsgBox()
>> ...
>> End Function
>
> Welches Ergebnis liefert so eine MsgBox dann?
> Das Ergebnis vom DefaultButton?
Ist Dir diese Frage wieder spontan eingefallen ;-)?
Der Timeout gibt -1 zurück, was Du dann entsprechend auswerten kannst. Du
könntest da ja auch z.B. in einem Loop die MsgBox immer wieder öffnen, aber
dazwischen DoEvents() ausführen, damit allenfalls der Logon Dialog
zwischengeschaltet werden kann.
Details in der Windows Script Dokumentation bei Mircosoft:
http://msdn.microsoft.com/en-us/library/x83z1d9f(VS.85).aspx
Gruss
Henry
Lutz Uhlmann wrote:
> Die letzten beiden scheinen nicht mehr zu exisitieren.
Dann schick mir doch mal eine Mail mit einer Adresse, auf die ich antworten
kann....
frmTimeout - wird an entsprechender Stelle aufgerufen
DoCmd.openform "frmTimeout", acNormal, , , acFormEdit, acHidden
Das Formular hat eine Datenquelle mit der Timeoutzeit, damit diese
einstellbar ist.
SELECT Timeout FROM LK_TIMEOUT WHERE ID=1;
Leere Werte für Form und Control werden nicht wie in der Vorlage
ignoriert, da sie durchaus vorkommen können.
Ich prüfe jetzt auch den evtl vorhandenen Text-Wert eines Controls um
längere Tipporgien nicht als Inaktivität zu brandmarken.
Der Formularcode sieht folgendermassen aus:
---------------------------------------------------------------
Option Compare Database
Option Explicit
Private m_PrevFormName As String
Private m_PrevControlName As String
Private m_PrevControlValue As String
Private m_ExpiredTime As Long
' IDLEMINUTES determines how much idle time to wait for before
' running the IdleTimeDetected subroutine.
Private Const IDLEMINUTES As Long = 1
Private Const VALTIMERINTERVAL As Long = 1000
Private Sub Form_Load()
Me.TimerInterval = 0
m_PrevFormName = ""
m_PrevControlName = ""
m_PrevControlValue = ""
m_ExpiredTime = 0
Me.TimerInterval = VALTIMERINTERVAL
End Sub
Private Sub Form_Timer()
On Error Resume Next
Dim nIdleMinutes As Long
Dim sActiveFormName As String
Dim sActiveControlName As String
Dim sActiveControlValue As String
Dim nExpiredMinutes As Long
Me.TimerInterval = 0
nIdleMinutes = Nz(Me.Timeout, IDLEMINUTES)
If nIdleMinutes = 0 Then
m_ExpiredTime = 0
Me.TimerInterval = VALTIMERINTERVAL
Exit Sub
End If
' Get the active form and control name.
sActiveFormName = Screen.ActiveForm.Name
If Err Then
sActiveFormName = "No Active Form"
Err = 0
End If
sActiveControlName = Screen.ActiveControl.Name
If Err Then
sActiveControlName = "No Active Control"
Err = 0
End If
sActiveControlValue = Screen.ActiveControl.text
If Err Then
sActiveControlValue = ""
Err = 0
End If
' Record the current active names and reset m_ExpiredTime if:
' 1. They have not been recorded yet (code is running
' for the first time).
' 2. The previous names are different than the current ones
' (the user has done something different during the timer
' interval).
If (sActiveFormName <> m_PrevFormName) _
Or (sActiveControlName <> m_PrevControlName) Then
m_PrevFormName = sActiveFormName
m_PrevControlName = sActiveControlName
m_PrevControlValue = ""
m_ExpiredTime = 0
Else
If sActiveControlValue <> m_PrevControlValue Then
m_PrevFormName = sActiveFormName
m_PrevControlName = sActiveControlName
m_PrevControlValue = sActiveControlValue
m_ExpiredTime = 0
Else
' otherwise the user was idle during the time interval, so
' increment the total expired time.
m_ExpiredTime = m_ExpiredTime + VALTIMERINTERVAL
End If
End If
Debug.Print "TIMEOUT " & format(m_ExpiredTime, "00000000") & _
": " & m_PrevFormName & " - " & m_PrevControlName & _
" (" & m_PrevControlValue & ")"
' Does the total expired time exceed the IDLEMINUTES?
nExpiredMinutes = (m_ExpiredTime / 1000) \ 60
If nExpiredMinutes >= nIdleMinutes Then
' ...if so, then reset the expired time to zero...
m_ExpiredTime = 0
' ...and call the IdleTimeDetected subroutine.
IdleTimeDetected nExpiredMinutes
End If
Me.TimerInterval = VALTIMERINTERVAL
End Sub
Sub IdleTimeDetected(nExpiredMinutes)
Dim Msg As String
Msg = "No user activity detected in the last "
Msg = Msg & nExpiredMinutes & " minute(s)!"
MsgBox Msg, 48
End Sub
---------------------------------------------------------------
Funktioniert soweit ganz gut und genügt meinen Ansprüchen.
Danke für eure Hilfe!
Lutz