Trayicon Bereich updaten / refreshen

  • Hallo zusammen

    Im englischen Forum hatte ich diese Zeilen gefunden, und adaptiert/übernommen:

    [autoit]

    Local $iMode = Opt("WinTitleMatchMode", 4)
    Local $hControl = ControlGetHandle("[CLASS:Shell_TrayWnd]", "", "[CLASSNN:ToolbarWindow321]")
    Local $acSize = WinGetClientSize($hControl)
    For $x = 0 To $acSize[0] Step 5
    For $Y = 0 To $acSize[1] Step 5
    DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hControl, "int", 0x0200, "wparam", 0, "lparam", BitOR($Y * 0x10000, BitAND($x, 0xFFFF)))
    Next
    Next

    [/autoit]

    Quelle: http://www.autoitscript.com/forum/topic/10…__1#entry728342

    Das funktioniert insofern, das inaktive Prozesse im Systemtray ausgeblendet werden, bzw verschwinden. Wie es genau funktioniert, weiss ich allerdings nicht, die paar Zeilen scheinen jeden Systemtray durchzugehen?! Das übersteigt eindeutig meinen horizont..

    Leider scheint es nun vorzukommen, dass meine Exe hängen bleibt, dh es passiert einfach nichts mehr ;(

    Was ist an obenstehendem falsch? Wieso kann es hängen bleiben? Wie kann ich es so verpacken, dass es in einer Schlaufe aufgerufen wird, die nur 30 sek lang läuft, und sich dann beendet egal was innerhalb der Schlaufe passiert?

    Oder gibt es da noch einen anderen Ansatz?

    Ich hoffe ihr wisst rat!

    Surfy

    Einmal editiert, zuletzt von Surfy (1. Juli 2011 um 13:30)

  • das update der icons erfolgt per winaip sendmessage ... die ich bin jetzt auch keine experte, in den sendmessage-api-optionen, aber ich denke mal das die optionen schon stimmen.
    ich würde dir empfehlen deinen code zu posten, dann kann man andere fehlerquellen entdecken und auch am besten einen aufruf des updates alle 30 sekunden implementieren.

  • danke fürs Helfen!


    Das ist schon der ganze Script!

    Der Script bzw die Exe wurde von der Softwareverteilung gestartet, als kein User eingeloggt war.

    Vielleicht hat das etwas damit zu tun? Deine Idee hat was - nur würde mir ein einmaliger Aufruf völlig ausreichen:

    Dh eine Schlaufe die 30sek läuft, und dann unbeachtet dessen, wo die Schleife gerade steht, sich beenden kann.

    Eigentlich hilft der ganze Trayrefresh nur, wenn ein User aktiv eingeloggt ist. Wichtig ist also nur, dass die Exe nicht hängen bleibt, wenn kein User eingeloggt ist.

    Da die Softwareverteilung auch mit einem Runas arbeitet, würde man mit @UserName etc wohl in die irre geführt.


    Surfy

  • ich hoffe ich habe dich richtig verstanden ... versuch mal das hier:

    [autoit]


    Opt("TrayMenuMode",1)
    $exititem = TrayCreateItem("Beenden")
    TraySetState()
    Local $timer = 0
    While 1
    $tmsg = TrayGetMsg()
    Select
    Case $tmsg = $exititem
    Exit
    EndSelect
    Sleep(20)
    $timer +=1
    If $timer >= 1500 Then _refresh()
    if $timer > 1500 Then $timer = 0
    WEnd

    [/autoit][autoit][/autoit][autoit]

    Func _refresh()
    Local $x=0,$y=0
    Local $iMode = Opt("WinTitleMatchMode", 4)
    Local $hControl = ControlGetHandle("[CLASS:Shell_TrayWnd]", "", "[CLASSNN:ToolbarWindow321]")
    ;~ Local $acSize = ($hControl)
    ;~ For $x = 0 To $acSize[0] Step 5
    ;~ For $Y = 0 To $acSize[1] Step 5
    DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hControl, "int", 0x0200, "wparam", 0, "lparam", BitOR($Y * 0x10000, BitAND($x, 0xFFFF)))
    ;~ Next
    ;~ Next
    EndFunc

    [/autoit]

    teste mal ob das mit dem refresh noch hinhaut ... sollte alle 30 sekunden sein....
    das script ist oben in einer endlosschleife gelandet die ich rausgenommen habe ... mag sein das sie wieder rein muss, allerdings muss man eine schleife auch irgendwann verlassen ... da ich die parameter von sendmessage nicht auf dem schirm habe muss ich erstmal schauen.... wenns trotzdem klappt mit dem refresh, dann kurze nachrich hier posten.

    3 Mal editiert, zuletzt von WhiteLion (29. Juni 2011 um 13:21)

  • ähm, das kann so net funktionieren:

    [autoit]

    If $timer = 1500 Then _refresh()
    if $timer < 1500 Then $timer = 0

    [/autoit]

    wenn dann eher so:

    [autoit]

    If $timer >= 1500 Then _refresh()
    if $timer > 1500 Then $timer = 0

    [/autoit]
    UNPLEASANT SPOILER

    You just lost the game!

  • Ausserdem verstehe ich nicht warum du die beiden For Schleifen in der refresh Funktion jetzt auskommentiert hast. So kann das ja nicht mehr funktionieren, da immer nur die Position x=0 und y=0 aktualisiert wird, anstelle des ganzen Bildschirms. Ich weiss zwar nicht was das Script genau tut, aber so wie es ausschaut simuliert es irgendwie ein Mouseover über alle Bildschirmbereiche um inaktive Icons loszuwerden. Das kann aber wohl auch nur funktionieren wenn der User gerade aktiv ist, ist der Account gesperrt kommt es wohl zu dem angesprochenen Hänger.

    Ich würde das also so lösen:

    [autoit]


    $timer = timerinit()
    while 1
    if userconnected() And timerdiff($timer) >= 10000 then refresh() ; alle 10 sek einen refresh wenn der user verbunden ist
    wend

    [/autoit][autoit][/autoit][autoit]

    func userconnected()
    ; hier müsstest du nun prüfen wie der Status des benutzer accounts ist, also verbunden oder getrennt... frag mich jetzt nicht womit man das am besten macht, müsste ich auch erst googlen
    if $result = "verbunden" then ; beispielhaft...
    return True
    else
    return False
    endif
    endfunc

    [/autoit][autoit][/autoit][autoit]

    func refresh()
    $timer = timerinit() ; resetet Timer
    ; hier eben die dll call funktion von oben
    endfunc

    [/autoit]
  • Hui, danke für die rege Beteiligung!

    Hintergrund:

    Ich habe zwei Programme, die in dem Systemtray angezeigt werden, auf dieser Basis:

    [ offen ] Verhindern dass mehrere Programme ausgeführt werden

    Erst kommt ein Fenster, das während der Deinstallation von Office 2003 angezeigt wird, danach wird ein Fenster eingeblendet während der Installation von Office 2010.

    Leider bleiben dann beide im Systemtray "sichtbar" Programm1 ist schon beendet, wird aber noch eine ganze weile im Systray angezeigt. Das ist insbesondere dann blöd, wenn die Migration vorbei ist, und der User eigentlich arbeiten könnte.

    Ziel ist natürlich, den Rollout/die Migration nachts laufen zu lassen, mit etwas glück sehen nicht viele oder niemand mein Kunstwerk ;)

    Daher bin ich hier nun an Programm3 - welches den Systray refreshen soll - damit die inaktiven kreierten Programme daraus verschwinden.

    Dazu reicht ein einmaliger Aufruf der Funktion! Aber der darf nicht crashen...

    Mit crashen meine ich: Das exe bleibt stehen, der Prozess beendet nicht - und die Migration geht nicht voran..

    Misterspeeds vorschlag geht wohl in die richtige Richtung: Abfragen ob ein User eingeloggt ist, und NUR dann die function aufrufen. Problem bleibt da der Runas Prozess der Software verteilung - der vielleicht dann anstelle eines Users connected wird.

    Wie kann man einen eingeloggten User erkennen? Muss das so komplex passieren wie zB hier? [ gelöst ] Angemeldeten Benutzer ermitteln (vom System-Konto)

    Einmal editiert, zuletzt von Surfy (29. Juni 2011 um 14:35)

  • Nun stellt sich die Frage: gehe ich nach dem Prozess?

    [autoit]

    If ProcessExists("explorer.exe") Then

    [/autoit]

    oder WMI?

    [autoit]


    Local $sLoggedInUser = "", $sLoggedInDomain = "", $sResults = ""
    $objWMIService = ObjGet("winmgmts:" & "{impersonationLevel=impersonate}!\\localhost\root\cimv2")
    If IsObj($objWMIService) Then
    $colComputer = $objWMIService.ExecQuery("Select * from Win32_ComputerSystem")
    For $objComputer In $colComputer
    $sLoggedInUser = $objComputer.UserName
    Next
    If StringInStr($sLoggedInUser,"\") Then
    $iSplit = StringInStr($sLoggedInUser,"\")
    $sLoggedInDomain = StringTrimRight($sLoggedInUser,(StringLen($sLoggedInUser) - $iSplit)+1)
    $sLoggedInUser = StringTrimLeft($sLoggedInUser,$iSplit)
    EndIf
    ;If $sLoggedInDomain <> "" Then $sResults &= "Logged in domain: " &$sLoggedInDomain &@CRLF
    If $sLoggedInUser = "" Then $sLoggedInUser = "n.a"
    Else
    $sLoggedInUser = "n.a"
    EndIf
    MsgBox(4096, "Test", $sLoggedInUser & " " & $sLoggedInDomain , 10)

    [/autoit]

    Oder Frage in der Registry den DefaultUserName ab? *verwirrtschau*

    [autoit]

    $RegUser = RegRead("HKLM\Software\Microsoft\Windows NT\CurrentVersion\WinLogon", "DefaultUserName")

    [/autoit]

    Was ist das zuverlässigste?

  • Öhm mal ne ganz andere Frage. Ihr werdet die Office Neuinstallation ja wohl kaum mitten am Tag im laufenden Betrieb erledigen. Warum lässt du nach Abschluss der Installation nicht einfach alle workstations rebooten, wodurch diese Symbolleichen dann doch auch weg wären?

  • Macht es in deinem Fall vielleicht Sinn, dass nicht vom Programm bestimmen zu lassen, sondern das System diese Aufgabe erledigen zu lassen.
    Du könntest das Script ohne Schleife, nack wie dus oben hast, per CronJob(Linux)/Taskplaner(Windows) aufrufen lassen.
    Das hat den Vorteil, dass du den Aufruf an verschiedenste Ereignisse koppeln kannst. Zum Beispel starte nachdem Programm x beendet wurden.
    Oder ausführen wenn User sich einloggt und dannach alle x Minuten.
    Genauso kannst du aber auch Bedingungen Prüfen und die Ausführung des Scriptes danach verweigern. Zum Beispeil wenn der Benutzer nicht eingeloggt ist.

    Gruß
    stro

    Edit: misterspeed: Sitzung beenden und neustarten würde ja sogar schon reichen.

  • Ein Reboot ist nicht notwendig, es funktioniert auch so. Natürlich soll der Rollout über Nacht stattfinden, aber einige werden es sicher schaffen, den PC geloggt laufen zu lassen - um dann am nächsten Tag beglückt zu werden.


    [autoit]


    _refresh()
    Func _refresh()
    RUNWAIT (@COMSPEC & ' /c eventcreate /t information /so installer /id 100 /l application /d "Start of Trayrefresh triggered ',"",@SW_HIDE)
    Local $iMode = Opt("WinTitleMatchMode", 4)
    Local $hControl = ControlGetHandle("[CLASS:Shell_TrayWnd]", "", "[CLASSNN:ToolbarWindow321]")
    Local $acSize = WinGetClientSize($hControl)
    For $x = 0 To $acSize[0] Step 5
    For $Y = 0 To $acSize[1] Step 5
    DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hControl, "int", 0x0200, "wparam", 0, "lparam", BitOR($Y * 0x10000, BitAND($x, 0xFFFF)))
    Next
    Next
    RUNWAIT (@COMSPEC & ' /c eventcreate /t information /so installer /id 100 /l application /d "End of Trayrefresh triggered ',"",@SW_HIDE)
    EndFunc

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit]

    Ich habe jetzt eine ausgelagerte Exe mit obenstehendem Code gemacht, die ich mit "Run" aufrufe. So bleibt wenigstens meine Exe nicht stehen, und die Installation geht weiter. Aber die Prozesse bleiben stehen! Dh der zweite Eventcreate Aufruf wird nie getriggert ;(

    Mit doppelklick geht das aber..

    2 Mal editiert, zuletzt von Surfy (30. Juni 2011 um 08:26)

  • Inzwischen habe ich Google nochmals intensiv beharkt:

    Das ist das aktuellste was ich gefunden habe:

    http://www.autoitscript.com/forum/topic/94…-refresh-redux/ bis Vista

    http://www.autoitscript.com/forum/topic/103871-systray-udf/ inkl Win7

    Dann gibts auch noch

    http://www.autoitscript.com/forum/topic/13704-systray-udf/

    http://www.autoitscript.com/forum/topic/74…reshsystemtray/

    Was haltet ihr von Link 1?

    Einmal editiert, zuletzt von Surfy (30. Juni 2011 um 10:58)

  • Ich sehe langsam mein Problem: Meine Exe was den Systray refreshen soll - läuft unter dem Usercontext der Softwareverteilung, und kommt so nicht an den Systray des eingeloggten Users heran.

    Da hilft wohl nur ein 2ter Service einrichten, der den refresh macht... :cursing:

  • Also ganz ehrlich Surfy, ich versteh den Aufwand den du treibst nicht.
    Das ein Benutzer nach eine Programmmigration ausgeloggt wird halte ich in nicht kritischen Arbeitsbereichen für ziemlich normal.
    Wirf dem Benutzer nach der Installation oder ab einem gewissen Prozessfortschrit eine Nachricht auf den Bildschrim, dass er alle offenen Dateien speichern soll und in 5 Minuten ausgeloggt wird. Fertig ist die Kiste.
    Was hast du davon Stunden zu investieren wenn du damit den einzelnen nur Minuten sparst?
    Ich weiß ja nicht ob du vor hast Office 2010 im AKW aufzuspielen oder ob deine Benutzer 24/7 online sein müssen.
    Aber wenn du sagst, das es ohnehin nachts passieren soll und dann nur noch ein paar Nasen da sind ist das glaube ich durchaus vertretbar.
    Bisschen an deiner Frage vorbei, aber dass musste jetzt mal raus ;)

    Gruß
    stro

  • Zitat

    Ich weiß ja nicht ob du vor hast Office 2010 im AKW aufzuspielen oder ob deine Benutzer 24/7 online sein müssen.

    Jo, dass ist vielleicht bissl übertrieben, aber macht ja auch spass - hab schon wieder viel gelernt.

    Ich hab jetzt eigentlich alles soweit gepackt - hatte nicht dran gedacht, dass ich im Service noch eine Exe starten kann, die die Executable mit ProcessWaitClose überwacht, und anschliessend den Systray refresht :)

    Der Service läuft unter Systemcontext, die Exe die den Service überwacht auch. Das einzige Problem ist, dass es einen Error gibt, wenn ein User sich während der Installation anmeldet:

    Autoit Error:

    Line 22 (File "C:\Program Files\ProzessWatch\reloader.exe")

    Error: Subscript used with non-Array variables

    Das blöde: an Zeile 22 ist gar nichts infrage kommendes:

    Hier der Quellcode der reloader.exe

    [autoit]

    #Region ;**** Directives created by AutoIt3Wrapper_GUI ****
    #AutoIt3Wrapper_icon=xxx\_Icons\awt_SECURITY_WARNING_0.ico
    #AutoIt3Wrapper_UseUpx=n
    #AutoIt3Wrapper_Res_Comment=SystemTrayReloader
    #AutoIt3Wrapper_Res_Description=xx
    #AutoIt3Wrapper_Res_Fileversion=1.0.0.0
    #AutoIt3Wrapper_Res_LegalCopyright=xx
    #AutoIt3Wrapper_Res_Field=Made By|xx
    #AutoIt3Wrapper_Res_Field=Email| [email='xx@xx.com'][/email] 
    #AutoIt3Wrapper_Res_Field=Compile Date|%date% %time%
    #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
    #AutoIt3Wrapper_Run_After=copy "%in%" "..\..\Programs_Updates\AutoIt3Wrapper"
    #AutoIt3Wrapper_Run_After=copy "%out%" "..\..\Programs_Updates\AutoIt3Wrapper"
    #AutoIt3Wrapper_Run_After=copy "%in%" "c:\Program Files (x86)\autoit3\SciTE\AutoIt3Wrapper"
    #AutoIt3Wrapper_Run_After=aaCopy2Prod.exe "%scriptfile%.EXE" "%out%" "C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper" "%in%" %fileversion% %fileversionnew%
    #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

    [/autoit][autoit][/autoit][autoit]

    ;#AutoIt3Wrapper_Res_Field=AutoIt Version|%AutoItVer%
    ;#AutoIt3Wrapper_Res_Field=Credits|wraithdu - Updating the Resource UDFs allowing other sections to be included.
    #cs ----------------------------------------------------------------------------
    AutoIt Version: 3.3.6.1
    Author: xxx
    Script Function:
    Template AutoIt script.
    #ce ----------------------------------------------------------------------------

    [/autoit][autoit][/autoit][autoit]

    Opt("TrayIconHide", 1)
    ProcessWaitClose("ProZessWatch.exe")
    Local $iMode = Opt("WinTitleMatchMode", 4)
    Local $hControl = ControlGetHandle("[CLASS:Shell_TrayWnd]", "", "[CLASSNN:ToolbarWindow321]")
    Local $acSize = WinGetClientSize($hControl)
    For $x = 0 To $acSize[0] Step 5
    For $Y = 0 To $acSize[1] Step 5
    DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hControl, "int", 0x0200, "wparam", 0, "lparam", BitOR($Y * 0x10000, BitAND($x, 0xFFFF)))
    Next
    Next

    [/autoit]
  • Der Fehler wird wohl in Zeile 31 entstehen (kompilierte Scripte haben keine identischen Zeilenangaben zum Quellcode). Wenn niemand eineloggt ist gibt es vermutlich auch keine Bildschirmauflösung. Das ganze script funktioniert meiner Meinung nach nur wenn es im user context ausgeführt wird und der User auch eingeloggt ist. Prüfen kannst du das zum Beispiel so:

    [autoit]


    #include <file.au3>
    ;...
    Local $acSize = WinGetClientSize($hControl)
    if $acSize = 0 or @error then
    _FileWriteLog(@ScriptDir & "\my.log","Fehler bei der Ermittlung von wingetclientsize") ; achtung du brauchst natürlich Schreibrechte im Ordner
    exit
    else
    _FileWriteLog(@ScriptDir & "\my.log","wingetclientsize erfolgreich ermittelt")
    endif

    [/autoit]
  • Hi Surfy,
    hier die Funktion:
    So wie die ist habe ich Sie compiliert und ohne Probleme laufen lassen
    läuft auch auf Win7 64-bit ;)

    Spoiler anzeigen
    [autoit]


    _UpdateTray() ; das ist der Aufruf zu der Funktion.

    [/autoit] [autoit][/autoit] [autoit]

    Func _UpdateTray()
    Local $iMode = Opt("WinTitleMatchMode", 4)
    Local $hControl = ControlGetHandle("[CLASS:Shell_TrayWnd]", "", "[CLASSNN:ToolbarWindow321]")
    Local $acSize = WinGetClientSize($hControl)
    For $x = 0 To $acSize[0] Step 5
    For $Y = 0 To $acSize[1] Step 5
    DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hControl, "int", 0x0200, "wparam", 0, "lparam", BitOR($Y * 0x10000, BitAND($x, 0xFFFF)))
    Next
    Next
    Opt("WinTitleMatchMode", $iMode)
    EndFunc ;==>_UpdateTray

    [/autoit]

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    ein paar Infos ...

    Wer mehr als "nur" Hilfe benötigt, kann sich gern im Forum "Programmieranfragen" an uns wenden. Wir helfen in allen Fällen, die die Forenregeln zulassen.

    Für schnelle Hilfe benötigen wir ein ! lauffähiges ! Script, dass wir als Demonstration des Problems testen können. Wer von uns erwartet ein Teilscript erstmal lauffähig zu bekommen, der hat
    1. keine wirkliche Not
    2. keinen Respekt vor Menschen die ihm in ihrer Freizeit Ihre Hilfe anbieten
    3. oder ist einfach nur faul und meint wir coden das für ihn

    In solchen Fällen erlaube ich mir, die Anfrage einfach zu ignorieren. ;)

  • Herzlichen Dank an alle Beteiligten!

    Nun läufts wie geschmiert.

    Schnuffel, auch mit deiner Version ging es nicht, gleiche Fehlermeldung.

    Ich habe dann ein Include aus einem meiner geposteten Links verwendet:_RefreshTrayIcons.au3 Damit

    _RefreshTrayIcons.au3

    Einmal editiert, zuletzt von Surfy (1. Juli 2011 um 13:52)