Sign in to follow this  
Followers 0
Icarus

Cumulative Window lists (no duplicates)

16 posts in this topic

Hi,

I am using Winlist () to capture window titles, and then screen dump known error messages.

This is working fine. What I need to do, though, is also make a cumulative list of Window Titles, with a time / date stamp.

I can do this in shell script. I need an efficient routine in AutoIt to replace, and I'm really struggling.. Please can someone assist?

This is my shell script that needs a better Autoit routine:

@echo off

set file=%1 ;this is a list of (duplicate) windows in a text file. Its the same as running Winlist () over and over and dumping to a text file.

set out=Windows.txt ;this is my cumulative list

for /f "tokens=*" %%a in ('sort %file%') do type %out%|find "%%a" || echo %date%;%time%;%%a>>%out%

The output looks like this:

22/10/2008;17:35:55.54;Complaint - Cust Serv. - Message (Rich Text)

22/10/2008;17:35:55.54;New Note

22/10/2008;17:35:55.54;Untitled - Note

22/10/2008;17:36:22.62;Tasks

22/10/2008;18:58:20.65;Please wait...

Its very inefficient to type the whole file out again and again looking for known windows, and then echoing those not (using the double || lines) found.

Your help and time is very much apprecaited.

Share this post


Link to post
Share on other sites



#include <file.au3>

$log = @ScriptDir & "\my.log"

$array = WinList()

For $X = 1 to $array[0][0]
_FileWriteLog($log,$array[$X][0])
Next

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

try this

$WinList = WinList()
$WindowsLog = @ScriptDir & "\Windows.txt"

For $i = 1 to $WinList[0][0]
  If $WinList[$i][0] <> "" AND IsVisible($WinList[$i][1]) Then 
  FileWrite($WindowsLog,GetCurrent() & " " & $WinList[$i][0] & @CRLF)
  EndIf
Next

Func IsVisible($handle)
    If BitAnd( WinGetState($handle), 2 ) Then Return 1
    Return 0
EndFunc

Func GetCurrent()
    $Time = @HOUR & ":" & @MIN & ":" & @SEC
    $Date = @YDAY & ":" & @MON & ":" & @YEAR
    $Return = $Date & ";" & $Time & " "
    Return $Return
EndFunc
Edited by komalo

[font="Palatino Linotype"][size="3"]AutoIt Script Examples :[/size][/font][font="Palatino Linotype"][size="3"]_CaptureBehindWindowGlass CMD for Windows Vista/Seven[/size][/font][left][/left][font="Palatino Linotype"][size="3"]Non AutoIt Script programs : Border Skin - Aero Glass On XP[/size][/font]

Share this post


Link to post
Share on other sites

Thank you for the responses - I'll test them and let you know.

Much appreciated!!

Icarus

Share this post


Link to post
Share on other sites

try this

$WinList = WinList()
$WindowsLog = @ScriptDir & "\Windows.txt"

For $i = 1 to $WinList[0][0]
  If $WinList[$i][0] <> "" AND IsVisible($WinList[$i][1]) Then 
  FileWrite($WindowsLog,GetCurrent() & " " & $WinList[$i][0] & @CRLF)
  EndIf
Next

Func IsVisible($handle)
    If BitAnd( WinGetState($handle), 2 ) Then Return 1
    Return 0
EndFunc

Func GetCurrent()
    $Time = @HOUR & ":" & @MIN & ":" & @SEC
    $Date = @YDAY & ":" & @MON & ":" & @YEAR
    $Return = $Date & ";" & $Time & " "
    Return $Return
EndFunc

Komalo,

This is spot on, thank you, as I really need the date and time, just as you've done it.

The only problem I have now, is that when I run it again and again, I end up with Windows.txt getting bigger and bigger.

I need it to grow with each UNIQUE window title. If I read back the contents of Windows.txt, and compare it to the WINLIST () array, every line is unique because of the date and time stamp.

Is it possible to

1) Read the WINDOWS.TXT file and COMPARE this to the current window list (without the date / time stamp)

2) Output unique Window lists

Its getting at the Window title in the WINDOWS.TXT file that I can't do, as its bringing back the date / time stamp too.

Thanks so much. Its really really helpful.

Icarus.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Aim of project - To gradually build up a list of uinique window titles, including the date and time stamp when they first appear, and to optionally do something if one of the window titles matches a list of error words (in errors.txt) such as "not responding".

Here is my code so far:

Opt("TrayIconHide", 1)       ;0=show, 1=hide tray icon
#include <Array.au3>

Local $avArray[1]
;Open a file for writing:

$file = FileOpen("windows.txt", 2)
$file2 = FileOpen("errors.txt", 0)

; Check if file opened for reading OK
If $file2 = -1 Then
    ConsoleWrite ("Error", "Unable to open file.")
    Exit
EndIf
; Check if file opened for writing OK
If $file = -1 Then
    ConsoleWrite ("Error", "Unable to open file.")
    Exit
EndIf

; Read in lines of text until the EOF is reached
    While 1
        $line = FileReadLine($file2)
        If @error = -1 Then ExitLoop
    ; MsgBox(0, "Line read:", $errors)
    ;Get window list
        $var = WinList()
        For $i = 1 to $var[0][0]
        ; Only display visble windows that have a title
        If $var[$i][0] <> "" AND IsVisible($var[$i][1]) Then
            ;dump these window titles to a file (Windows.txt)
                $iIndex = _ArraySearch($avArray, $var[$i][0], 0, 0, 0, 1)
                If @error Then
                    _ArrayAdd($avArray, $var[$i][0])
                    FileWriteLine($file, $var[$i][0] & @CRLF)
                
                Else
                ;MsgBox(0, "Found", '"' & $sSearch & '" was found in the array at position ' & $iIndex & ".")
                EndIf

            
            ;if an error string is found, then do something here:
                $found=(StringRegExp($var[$i][0], $line))
                if ($found >0) Then
                ;ConsoleWrite ($var[$i][0] & @LF)
                EndIf
        EndIf
      
  Next  
  Wend


;_ArrayDisplay($avArray, "$avArray AFTER _ArrayAdd()")

FileClose($file)
FileClose($file2)
;Sleep(1000)





Func IsVisible($handle)
  If BitAnd( WinGetState($handle), 2 ) Then 
    Return 1
  Else
    Return 0
  EndIf

EndFunc
Edited by Icarus

Share this post


Link to post
Share on other sites

Also a WH_CBT hook will report window creations. It can be done in AutoIt natively or through my hook.dll.

Search the forum well for hooks... but try not to ask too many questions about hooks. Hooks are the technology behind some of the badder viruses. ... I mean more badder.

Lar.


f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Share this post


Link to post
Share on other sites

I like this version because it detects by handles, so it will log if the same window keeps popping up, but never logs multiple hits for the same instance of a window. I would use post-processing of the log to pull unique titles, but you could add a test to the loop very easily:

#include <File.au3>
#include <Array.au3>

HotKeySet("{ESC}", "_Quit")

; Initialize log file, make sure it's writeable
Global $sLogFile = "C:\Temp\WinLog.log"
Global $hLogFile = FileOpen($sLogFile, 1); Write, append
If $hLogFile = -1 Then
    MsgBox(16, "Error", "Failed to open file for write:  " & $sLogFile)
    Exit
EndIf
FileWriteLine($hLogFile, @YEAR & "-" & @MON & "-" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & _
        " : Started window monitor script."); Timestamp matches _FileWriteLog format
FileClose($hLogFile)

; Initialize tracking arrays
Global $avWinListPrevious[1][2] = [[0, ""]], $avWinListCurrent

; Monitor unique window handles
While 1
    $avWinListCurrent = WinList()
    For $n = $avWinListCurrent[0][0] To 1 Step -1
    ; Check has title and visible
        If ($avWinListCurrent[$n][0] <> "") And BitAND(WinGetState($avWinListCurrent[$n][1]), 2) Then
        ; Check for already seen
            $fFound = False
            For $i = 1 To $avWinListPrevious[0][0]
                If $avWinListCurrent[$n][1] = $avWinListPrevious[$i][1] Then
                    $fFound = True
                    ExitLoop
                EndIf
            Next
            
        ; New window found
            If Not $fFound Then
                _FileWriteLog($sLogFile, "New window detected: hWnd: " & $avWinListCurrent[$n][1] & _
                        " Title: " & $avWinListCurrent[$n][0])
            EndIf
        Else
            _ArrayDelete($avWinListCurrent, $n)
        EndIf
    Next
    $avWinListCurrent[0][0] = UBound($avWinListCurrent) - 1
    $avWinListPrevious = $avWinListCurrent
    Sleep(500)
WEnd

Func _Quit()
    Exit
EndFunc  ;==>_Quit

:mellow:


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Hooks are the technology behind some of the badder viruses.

Hooks and bladder viruses; it all sounds so painful... oh, wait...

:mellow:

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Aim of project

1 - gradually build up a list of uinique window titles, including the date and time stamp when they first appear

2 - optionally do something if one of the window titles matches a list of error words (in errors.txt)

here it is with shellhooking ( this is a big modification of ShellHookWindow )

#NoTrayIcon
#include <Misc.au3>
#include <WinAPI.au3>

Global Const $HSHELL_WINDOWCREATED = 1
Global $WinLog = @ScriptDir & "\Windows Log.txt"
Global $Error = @ScriptDir & "\Error.txt"
If FileExists($WinLog) Then FileDelete($WinLog)
$WinError = FileRead($Error)

HotKeySet("{ESC}","Close")

$hGui = GUICreate("", 0, 0, 0, 0)
GUIRegisterMsg(_WinAPI_RegisterWindowMessage("SHELLHOOK"), "HShellWndProc")
ShellHookWindow($hGui, 1)
WriteToLog("Monitering Started")

While 1
    Sleep(1000)
WEnd

Func Close()
    ShellHookWindow($hGui, 0)
    WriteToLog("Monitering Ended")
    Exit
EndFunc

Func HShellWndProc($hWnd, $Msg, $wParam, $lParam)
    Switch $wParam
        Case $HSHELL_WINDOWCREATED
            WriteToLog(" New Window: " & $lParam & " (" & WinGetTitle($lParam) & ")")
    EndSwitch
EndFunc

Func WriteToLog($sText)
    If ComareError($sText) Then MsgBox("","Exists in Error", "The " & $sText & " is Detected At Error Text")
    FileWriteLine($WinLog,GetCurrent() & $sText)
EndFunc

Func ComareError($sText)
    If StringInStr($sText,$WinError) Then Return True
    Return False
EndFunc

Func ShellHookWindow($hWnd, $bFlag)
    Local $sFunc = 'DeregisterShellHookWindow'
    If $bFlag Then $sFunc = 'RegisterShellHookWindow'
    Local $aRet = DllCall('user32.dll', 'int', $sFunc, 'hwnd', $hWnd)
    WriteToLog($sFunc & ' = ' & $aRet[0])
    Return $aRet[0]
EndFunc

Func GetCurrent()
    $Time = @HOUR & ":" & @MIN & ":" & @SEC
    $Date = @MDAY & "-" & @MON & "-" & @YEAR
    $Return = $Date & " " & $Time & " "
    Return $Return
EndFunc

[font="Palatino Linotype"][size="3"]AutoIt Script Examples :[/size][/font][font="Palatino Linotype"][size="3"]_CaptureBehindWindowGlass CMD for Windows Vista/Seven[/size][/font][left][/left][font="Palatino Linotype"][size="3"]Non AutoIt Script programs : Border Skin - Aero Glass On XP[/size][/font]

Share this post


Link to post
Share on other sites

Thankx to you all - Weaponx - nice, and simple - I can understand that. Cheers.

Komalo - Thanks for both your post too - especially the shell hook stuff. That was a little over my head, but I'm reading through it slowly to try and understand..

PsaltyDS - WOW! - Your code example is great. The handle grabbing is just what I was after, as now when a new handle is found, I can grab a screenshot using:

; Capture window

_ScreenCapture_CaptureWnd (@MyDocumentsDir & $avWinListCurrent[$n][0] & ".jpg", $avWinListCurrent[$n][1])

As this stands, my project is nearly there. It is capturing window titles, and logging them with date / time stamps. When a new window is found it takes a screenshot of that window.

The final piece of the jigsaw is to have it screen grab specific windows based on a list of key words.

I was thinking that I would pre-load an array of words like this:

Global $avErrorlist[1]=["error"]

And then do a comparison of the window title:

if $avWinListCurrent[$n][0] = $avErrorlist[1] then ;Capture window.

Since I want to compile this to a .exe for deployment, it probably not a good idea to have hard-coded error lists within the app.

Any suggestions of where to store / add these would be very welcome, or a better way to do the window comparison.

Finally, I'd like to ensure I can compare long text names with spaces too, eg : "Task Manager".

Once again, a HUGE thank you to the skills and coding examples shown here. You guys are amazing..

Icarus.

Share this post


Link to post
Share on other sites

...just realised that komalo has got some error checking in that code example - hadn't spotted that. Checking that out now..

cheers again...

Share this post


Link to post
Share on other sites

OK. Still struggling with finding the errors from the error file (error.txt) in the window lists.

It works if I put an EXACT copy of a window title in.

I've switched the parameters round to help highlight this:

Global $Error = @ScriptDir & "\Error.txt"
$WinError = FileRead($Error)

Func CompareError($sText)
    If StringInStr($WinError, $sText) Then Return True
    Return False
EndFunc

Do {any of the words in this text file : error.txt} match {any part of the current window title, $stext)

Please can I ask for a little more input?

Cheers....

Share this post


Link to post
Share on other sites

I've tried to break this down into just reading the list of error codes into the array, and passing it a dummy window handle ($sText):

Global $Error = @ScriptDir & "\Error.txt"
#Include <Array.au3>
#include <file.au3>
Dim $aRecords

;Read the file into an array
If Not _FileReadToArray($Error,$aRecords) Then
   MsgBox(4096,"Error", " Error reading log to Array     error:" & @error)
   Exit
EndIf

;Function to compare each word in Error.txt with the current window title and return TRUE if any match
Func CompareError($sText)
    For $x = 1 to $aRecords[0]
        ConsoleWrite ($aRecords[$x] & @LF)
        If StringInStr($aRecords[$x], $sText) Then Return True
        Return False
    Next
EndFunc

;Dummy window title
$sText="Windows Task Manager"
If CompareError($sText) then ConsoleWrite ("Matched" & $sText & @LF)

This code doesn't return anything, even when there is only one word, "Task", in error.txt

Icarus

Share this post


Link to post
Share on other sites

I've tried to break this down into just reading the list of error codes into the array, and passing it a dummy window handle ($sText):

; ...

;Function to compare each word in Error.txt with the current window title and return TRUE if any match
Func CompareError($sText)
    For $x = 1 to $aRecords[0]
        ConsoleWrite ($aRecords[$x] & @LF)
        If StringInStr($aRecords[$x], $sText) Then Return True
        Return False
    Next
EndFunc

;...

This code doesn't return anything, even when there is only one word, "Task", in error.txt

Icarus

You've got your parameters bassackwards:
StringInStr($sText, $aRecords[$x])

:mellow:


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Final thanks to everyone. I now have a small application that when running, sits in the background waiting for error messages (in error.txt).

When these are found, it takes a snapshot of the window for future investigation. It can be any words in error.txt ("error", "unable", "failed" etc.)

Many many thanks to all who helped.

Final code here for anyone who might find it helpful:

#include <File.au3>
#include <Array.au3>
#include <ScreenCapture.au3>

Global $Error = @ScriptDir & "\Error.txt"
$WinError = FileRead($Error)
Dim $aRecords

If Not _FileReadToArray($Error,$aRecords) Then
   MsgBox(4096,"Error", " Error reading log to Array     error:" & @error)
   Exit
EndIf

Opt("TrayIconHide", 1)       ;0=show, 1=hide tray icon
HotKeySet("^!q", "_Quit");Control+Alt+Q to exit the program

; Initialize log file, make sure it's writeable
Global $sLogFile = "C:\Temp\WinLog.log"
Global $hLogFile = FileOpen($sLogFile, 1); Write, append
If $hLogFile = -1 Then
    MsgBox(16, "Error", "Failed to open file for write:  " & $sLogFile)
    Exit
EndIf
FileWriteLine($hLogFile, @YEAR & "-" & @MON & "-" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & _
        " : Started window monitor script."); Timestamp matches _FileWriteLog format
FileClose($hLogFile)


; Initialize tracking arrays
Global $avWinListPrevious[1][2] = [[0, ""]], $avWinListCurrent
; Initialize error tracking array

; Monitor unique window handles
While 1
    $avWinListCurrent = WinList()
    For $n = $avWinListCurrent[0][0] To 1 Step -1
   ; Check has title and visible
        If ($avWinListCurrent[$n][0] <> "") And BitAND(WinGetState($avWinListCurrent[$n][1]), 2) Then
       ; Check for already seen
            $fFound = False
            For $i = 1 To $avWinListPrevious[0][0]
                If $avWinListCurrent[$n][1] = $avWinListPrevious[$i][1] Then
                    $fFound = True
                    ExitLoop
                EndIf
            Next
            
       ; New window found
            If Not $fFound Then
                _FileWriteLog($sLogFile, "New window detected: hWnd: " & $avWinListCurrent[$n][1] & _
                        " Title: " & $avWinListCurrent[$n][0])
                _FileWriteLog ($sLogfile,"Debug: " & $avWinListCurrent[$n][0])
            ; Check for error window titles, and if found, capture window
                If CompareError($avWinListCurrent[$n][0]) Then  _ScreenCapture_CaptureWnd (@MyDocumentsDir & $avWinListCurrent[$n][0] & ".jpg", $avWinListCurrent[$n][1])
                EndIf
        Else
            _ArrayDelete($avWinListCurrent, $n)
        EndIf
    Next
    $avWinListCurrent[0][0] = UBound($avWinListCurrent) - 1
    $avWinListPrevious = $avWinListCurrent
    Sleep(500)
WEnd

Func _Quit()
    Exit
EndFunc ;==>_Quit


Func CompareError($sText)
;Return False
    For $x = 1 to $aRecords[0]
;ConsoleWrite ($aRecords[$x] & @LF)
        If StringInStr($sText, $aRecords[$x]) Then Return True
    Next
    
EndFunc

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0