Sign in to follow this  
Followers 0
MFatica

Trouble with Loops and GuiGetMsg()

17 posts in this topic

Hello all. I'm having troubles with loops and GuiGetMsg()

This is basically my code structure:

$file = FileOpen("file.txt", 1)

func guiLoop()
While 1
    $msg = GUIGetMsg()
    Select
        case $msg = $GUI_EVENT_CLOSE
            ExitLoop
        case $msg = $startButton
            read()
        case $msg = $stopButton
            stop()
        EndSelect
WEnd
GUIDelete()
endfunc

func write()
FileWrite($readLine)
read()
endfunc

func stop()
 FileClose($file)
 guiLoop()
endfunc

func read()
 Sleep(1000)
 if $message = "" then
   read()
 else
     if $lastmessage = $message then
       write() ;write calls read() after writing
    else
       read()
    endif
endfunc

Basically when the read() function is called, it enters in an infinite loop to continuously read, which is what I want. However, the problem is that no other buttons work once it enters this loop. What do I have to do so it will allow me to press the Stop button while it is looping in read()?

Share this post


Link to post
Share on other sites



MFatica,

I am afraid your code is a real mess - recursive function calls all over it. :) (Recursive means that a function calls itself - not a good idea unless you really know what you are doing!)

I have tried to simplify it but without rather more explanation of what you are trying to do, it is difficult to offer much more advice.

What you have here is a simple loop that calls a single function when the $startButton is pressed. This function enters its own loop, doing the "read" bit, and also looks for the $stopButton being pressed. When the $stopButton is pressed, it closes the file and returns to the original loop.

$file = FileOpen("file.txt", 1)

While 1
    ; See if anything is pressed
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $startButton
            Action()
        Case $stopButton
            FileClose($file) ; No need for a separate function
            ; But what do we do now?  Exit??????????
    EndSelect
WEnd

Func Action()
    ; Start the infinite loop
    While 1
        ; Where does $message come from??
        If $message = "" Then
            Sleep(100) ; Not strictly necessary now we have a GUIGetMsg in the loop
        ElseIf $lastmessage = $message Then  ; Where does $lastmessage get set??
            FileWrite($file, $readLine) ; Check the syntax of this command !!!
        EndIf
        
        If GUIGetMsg() = $stopButton Then ExitLoop ; If stop pressed, exit infinite loop
    WEnd
    ; We are out of the loop, so close the file
    FileClose($file)
    ; We return to the main loop automatically
    
EndFunc

Please ask if anything is unclear or if I have completely misunderstood what the code is trying to do.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

I believe you have misunderstood my program. It is supposed to be recursive, as it is meant to be continually reading World of Warcraft's chat log from memory.

The infinite loop isn't the problem. I want it there. The problem is that I cannot exit the infinite loop with the Stop Logging button.

Here is the full code:

#include <GUIConstantsEx.au3>
#Include <NomadMemory.au3>

;Vars
dim $dll
dim $HPROCESS
dim $CHAT_BEGIN
dim $CHAT_NUM
dim $chatLog
dim $message
dim $messageArray
dim $version
dim $winTitle
dim $i
dim $lastMessage
dim $chatManagerWindow
dim $partyFile
dim $whisperFile
dim $currentList[60]
dim $lastList[60]
$loggingLeft = -15
$loggingTop = 0
$deleteLeft = 100
$deleteTop = 0
$firstRun = 0

;Memory Priv / Open
SetPrivilege("SeDebugPrivilege", 1)
$dll = DllOpen("user32.dll")
$wowTitle = IniRead("config.ini", "Title", "WowTitle", "World of Warcraft")
$HPROCESS = _MemoryOpen(WinGetProcess($wowTitle))
Opt("GUICoordMode", 1)

;GUI Stuff
$version = 0.1
$winTitle = ("Chat Log Manager v" & $version)
$chatManagerWindow = GUICreate($winTitle, 250, 150)
GUICtrlCreateLabel("Reading from window: " & $wowTitle, 25, 120, 250, 15)
;Buttons
$startLogging = GUICtrlCreateButton("Start Logging", ($loggingLeft + 35), ($loggingTop + 33), 90, 23)
$stopLogging = GUICtrlCreateButton("Stop Logging", ($loggingLeft + 35), ($loggingTop + 58), 90, 23)
$reloadConfig = GUICtrlCreateButton("Reload Config", ($loggingLeft + 35), ($loggingTop + 83), 90, 23)
$deleteParty = GUICtrlCreateButton("Delete Party", ($deleteLeft + 35), ($deleteTop + 33), 90, 23)
$deleteWhisper = GUICtrlCreateButton("Delete Whisper", ($deleteLeft + 35), ($deleteTop + 58), 90, 23)
$deleteBoth = GUICtrlCreateButton("Delete Both", ($deleteLeft + 35), ($deleteTop + 83), 90, 23)
;Labels
GUICtrlCreateLabel("Logging", $loggingLeft + 60, ($loggingTop + 15), 40, 15)
GUICtrlCreateLabel("Delete", $deleteLeft + 60, ($deleteTop + 15), 40, 15)
;Graphic
$logBox = GUICtrlCreateGraphic($loggingLeft, $loggingTop)
GUICtrlSetGraphic($logBox, $GUI_GR_RECT, 30, 30, 100, 80)
$delBox = GUICtrlCreateGraphic($deleteLeft, $deleteTop)
GUICtrlSetGraphic($delBox, $GUI_GR_RECT, 30, 30, 100, 80)
;Show
GUISetState(@SW_SHOW)
;Offets
$CHAT_BEGIN = 0x010E2BCC
$NEXT_CHAT = 0x17C0
$CHAT_NUM = 1

func guiLoop()
While 1
    $msg = GUIGetMsg()
    Select
        case $msg = $GUI_EVENT_CLOSE
            ExitLoop
        case $msg = $startLogging
            readMem()
        case $msg = $stopLogging
            closeFile()
        EndSelect
WEnd
GUIDelete()
endfunc

func close()
    exit
EndFunc

func loadConfig()
    If ($firstRun = 0) Then
        $firstRun = 1
        $partyFile = IniRead("config.ini", "Files", "PartyLog", "Party Log.txt")
        $chatLog = FileOpen($partyFile, 1)
        MsgBox(0, "", $chatLog)
        $whisperFile = IniRead("config.ini", "Files", "WhisperLog", "Whisper Log.txt")
    Else
        $partyFile = IniRead("config.ini", "Files", "PartyLog", "Party Log.txt")
        $chatLog = FileOpen($partyFile, 1)
        $whisperFile = IniRead("config.ini", "Files", "WhisperLog", "Whisper Log.txt")
    Endif
EndFunc

func readMem()
    Sleep(1000)
    $lastMessage = $message
    $message = _MemoryRead(($CHAT_BEGIN + ($CHAT_NUM * $NEXT_CHAT)), $HPROCESS, 'char[256]')
    if $message = "" Then
        readMem()
    else
        if ($lastMessage = $message) then
        $messageArray = StringSplit($message, ",")
        writeLine()
        Else
            readMem()
        endif
    endif
EndFunc

func closeFile()
    FileClose($chatLog)
    MsgBox(0, "", $chatLog)
    guiLoop()
EndFunc

func writeLine()
if $messageArray[0] = 0 Then
    readMem()
else
    $i = 1
    While ($i < ($messageArray[0] + 1))
        FileWrite($chatLog, $messageArray[$i])
        $i = ($i + 1)
    WEnd
    FileWrite($chatLog, @CRLF)
    if $CHAT_NUM >= 60 Then
        $chat_num = 1
        else
    $CHAT_NUM = ($CHAT_NUM + 1)
    endif
    readMem()
endif
EndFunc

loadConfig()
guiLoop()

Share this post


Link to post
Share on other sites

MFatica,

It is supposed to be recursive, as it is meant to be continually reading World of Warcraft's chat log from memory.

You are confusing infinite and recursive.

Infinite means it repeats without end - recursive is when a function calls itself again before it ends. The first is not a problem - except when you want to stop it - the second can very quickly lead to system crashes and should be avoided unless you really know what you are doing. :)

What you need to read the game chat log is an infinite loop - a loop that keeps going forever - and that is what I have given you. During this loop the script also checks for the $stopButton so you can exit the loop when you need to.

I hope that clears up any confusion.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Ok this is what I have now. But still, when I press the stop button nothing happens. Here is the function:

$startLogging = GUICtrlCreateButton("Start Logging", ($loggingLeft + 35), ($loggingTop + 33), 90, 23)
$stopLogging = GUICtrlCreateButton("Stop Logging", ($loggingLeft + 35), ($loggingTop + 58), 90, 23)
$file = FileOpen("file.txt", 1)


While 1
    $msg = GUIGetMsg()
    Select
        case $msg = $GUI_EVENT_CLOSE
            ExitLoop
        case $msg = $startLogging
            readMem()
WEnd
GUIDelete()

func readMem()
    While 1
    Sleep(1000)
    $lastMessage = $message
    $message = _MemoryRead(($CHAT_BEGIN + ($CHAT_NUM * $NEXT_CHAT)), $HPROCESS, 'char[256]')
    if $message = "" Then
    else
        if ($lastMessage = $message) then
        $messageArray = StringSplit($message, ",")
        writeLine()
        endif
    endif
    If GUIGetMsg() = $stopLogging Then ExitLoop
    Wend
    MsgBox(0, "", "Out of loop.")
    FileClose($file)
EndFunc

Share this post


Link to post
Share on other sites

MFatica,

This code works fine for me - I did have to add an EndSelect though! :). I have commented out the non-essential stuff:

#include <GUIConstantsEx.au3>

$hGUI = GUICreate("Test", 500, 500)

$startLogging = GUICtrlCreateButton("Start Logging", 10, 10, 80, 30);, ($loggingLeft + 35), ($loggingTop + 33), 90, 23)
$stopLogging = GUICtrlCreateButton("Stop Logging",10, 100, 80, 30); ($loggingLeft + 35), ($loggingTop + 58), 90, 23)

GUISetState()

;$file = FileOpen("file.txt", 1)

While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
            ExitLoop
        Case $msg = $startLogging
            readMem()
    EndSelect
WEnd
GUIDelete()

Func readMem()
    MsgBox(0, "", "Into loop.")
    While 1
        ;Sleep(1000)  ; Not needed because you us GUIGetMsg in the loop
        ;$lastMessage = $message
        ;$message = _MemoryRead(($CHAT_BEGIN + ($CHAT_NUM * $NEXT_CHAT)), $HPROCESS, 'char[256]')
        If $message <> "" Then
        ;   If ($lastMessage = $message) Then
        ;       $messageArray = StringSplit($message, ",")
        ;       writeLine()
        ;   EndIf
        EndIf
        If GUIGetMsg() = $stopLogging Then ExitLoop
    WEnd
    MsgBox(0, "", "Out of loop.")
    ;FileClose($file)
EndFunc   ;==>readMem

Question - what does writeLine() do?

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Seems I did forget an EndSelect when I posted it here.

Here is the writeLine() function:

func writeLine()
if $messageArray[0] = 0 Then
    return
else
    $i = 1
    While ($i < ($messageArray[0] + 1))
        FileWrite($file, $messageArray[$i])
        $i = ($i + 1)
    WEnd
    FileWrite($file, @CRLF)
    if $CHAT_NUM >= 60 Then
        $chat_num = 1
    else
    $CHAT_NUM = ($CHAT_NUM + 1)
    endif
endif
EndFunc
Edited by MFatica

Share this post


Link to post
Share on other sites

MFatica,

I just wanted to check that it was not heading off somewhere different. :)

Have you got it working now?

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

No I haven't =/ It still does not register me pressing the stop button. I added a Message Box to display what GUIGetMsg() returned. For the first loop it returns -8 but each loop after that it returns -11.

Share this post


Link to post
Share on other sites

MFatica,

Does the code I posted at #6 above work for you?

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Yes, the code you posted did work.

Edit: I removed the Sleep(1000) and it worked. However I don't want it to be in a such a tight loop =\ Is there any workaround to still have the sleep?

Edited by MFatica

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

MFatica,

The Sleep(1000) makes the code unresponsive. It does nothing during that second - not even look for the stop button, which is why you could not get it to work.

If you only want to look for new log entries at regular but fairly long (in computer terms!) intervals, I would suggest using 2 loops like this:

#include <GUIConstantsEx.au3>

$hGUI = GUICreate("Test", 500, 500)

$startLogging = GUICtrlCreateButton("Start Logging", 10, 10, 80, 30);, ($loggingLeft + 35), ($loggingTop + 33), 90, 23)
$stopLogging = GUICtrlCreateButton("Stop Logging",10, 100, 80, 30); ($loggingLeft + 35), ($loggingTop + 58), 90, 23)

GUISetState()

;$file = FileOpen("file.txt", 1)

While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
            ExitLoop
        Case $msg = $startLogging
            readMem()
    EndSelect
WEnd
GUIDelete()

Func readMem()
    ConsoleWrite("Into log read loop" & @CRLF)
    While 1

        $iBegin = TimerInit()
        ; Start a loop to use up time, but keep looking for the stop button
        ConsoleWrite("Into idle loop" & @CRLF)
        While TimerDiff($iBegin) < 2000  ; <<<<<<<<<<<<<<<<<<<< adjust time as you wish
            If GUIGetMsg() = $stopLogging Then ExitLoop 2 ; Need to exit both loops
        WEnd

        ; look for new log entries here
        ConsoleWrite("Looking at log" & @CRLF)

    WEnd
    ConsoleWrite("Out of loop" & @CRLF)
    ;FileClose($file)
EndFunc   ;==>readMem

You can adjust the timing of the loop as you wish and the script stays responsive all the time. You also do not eat up too much CPU because the loop contains a GUIGetMsg which automatically idles during each pass.

I hope this solves your problem.

M23

Edited by Melba23

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

You also do not eat up too much CPU because the loop contains a GUIGetMsg which automatically idles ~250ms each pass.

Seems more like ~10ms to me (3.3.0.0 and 3.3.1.1).

While 1
    $Timer = TimerInit()
    $Crap = GUIGetMsg()
    ConsoleWrite(TimerDiff($Timer) & " ms" & @CRLF)
WEnd

What version are you using?

Share this post


Link to post
Share on other sites

AdmiralAlkex,

You are undoubtedly correct. I admit to not checking directly - I just used a figure I remembered (or thought I did! :) ) from somewhere else on the forums. I have amended the post above.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

@Melba23

Well yeah I just had to try it when you said the time was about 250ms, that just sounded a tad too much. Having to wait a quarter of a second for a responce is far more than what is generally accepted.

I know I would be crazy if I had to wait that long every time I pressed on something :)

Share this post


Link to post
Share on other sites

I was recently trying to do something similar, and encountered the same type of issue. Here is a solution that another user was kind enough to post for me.

#include <GUIConstantsEx.au3>

Opt("GUIOnEventMode", 1)

$Form1_1 = GUICreate("My Form", 343, 195, 192, 124)

GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClk")

$Label1 = GUICtrlCreateLabel("Ready to Loop", 64, 16, 198, 20)

GUICtrlSetFont(-1, 10, 400, 0, "Goudy Old Style")

GUICtrlSetColor(-1, 0x808000)

$Button1 = GUICtrlCreateButton( "Button1", 216, 104, 75, 25)

$Button2 = GUICtrlCreateButton( "Button2", 216, 144, 75, 25)

GUICtrlSetOnEvent($Button1,"Button1")

GUICtrlSetOnEvent($button2,"Button2")

GUICtrlSetState($button2, $GUI_DISABLE)

GUISetState(@SW_SHOW)

$button1Loop = False

While 1

sleep(100)

if $button1Loop Then

Button1Loop()

EndIf

WEnd

Func Button1()

GUICtrlSetState($button2, $GUI_ENABLE)

GUICtrlSetState($button1, $GUI_DISABLE)

$button1Loop = True

EndFunc

Func Button1Loop()

GUICtrlSetData($label1, "Looping: " &TimerInit())

EndFunc

Func Button2()

$button1Loop = False

GUICtrlSetState($button1, $GUI_ENABLE)

GUICtrlSetState($button2, $GUI_DISABLE)

GUICtrlSetData($label1, "All Done")

EndFunc

Func CLOSEClk()

Exit

EndFunc

Basically you have the function button1loop that starts when button1 is pressed. Pressing button2 will exit the loop. I found it worked for me, hopefully you will also find it useful.

Guy.

Share this post


Link to post
Share on other sites

MFatica,

The Sleep(1000) makes the code unresponsive.

Thank you, that solved it.

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