Sign in to follow this  
Followers 0
tdw

Which "blocking" functions are safe to use in GUIRegisterMsg handler? Eg TrackPopupMenu?

6 posts in this topic

I'm looking for information about what is safe to put in a message handler registered with GUIRegisterMsg(), because the help file contains the warning: "blocking of running user functions which executes window messages with commands such as "Msgbox()" can lead to unexpected behavior, the return to the system should be as fast as possible !!!", but doesn't exactly say what "blocking" is or what the "unexpected behaviour" is. (And "unexpected" is not necessarily bad or buggy if you know what it is so it isn't "unexpected" any more!)

The program I am writing has a ReBar containing a Toolbar with buttons, some of which drop-down menus. The buttons/menu commands cause my script to interact with another application eg sending keys, waiting for a dialog to appear, filling in info in the dialog, etc. Thus there are lots of potentially "blocking" functions I want to call in my WM_NOTIFY handler, such as _GUICtrlMenu_TrackPopupMenu() and WinWait(), and I'm wondering which are safe, and when I need to use the dummy control technique to transfer control back to AutoIt's main loop.

I've been searching AutoIt's documentation, and find:

  • HotKeySet() refers toMsgBox() and FileSelectFolder() as "blocking" functions
  • GUIRegisterMsg() refers toMsgbox() (as above), and
  • AdLibRegister refers to Wait() and InputBox(). [bTW, not sure what Wait() is: doesn't seem to appear in AutoIt help file - perhaps WinWait()?]
but given the differences between the lists, I suspect none of them is the definitive list of blocking functions.

Thinking a bit more, it seems to me that there are three kinds of functions that might be described as "blocking":

  • AutoIt functions like WinWait(), which (I believe) continue to run AutoIt's main loop but normally cause execution of script statements to stop for a while.
  • Windows (and perhaps AutoIt) functions that contain a nested Windows message loop ("message pump"), eg Win32's MessageBox() and TrackPopupMenu()
  • Windows functions that can suspend execution of the calling thread eg Sleep(), blocking I/O functions, and GetMessage() in a nested message loop.

Are all of these unsafe in a GUIRegisterMsg() handler, or are any OK? I notice that example code in these forums uses TrackPopupMenu in a message handler - but perhaps that strictly isn't safe?

Thinking about what might happen in each case:

1. (AutoIt functions like WinWait): *IF* the GUIRegisterMsg handler is being run by a recursive invocation of AutoIt's usual main loop, then - apart from normal sequential execution being suspended, the only problem I see is that the handling of further Windows messages might cause deep recursion of AutoIt's main loop (and message loop), and potentially the handler could be executed re-entrantly (which could cause coding headaches). Come to think of it... is there anything that stops GUIRegisterMsg handlers being executed reentrantly anyway by two windows messages that arrive in quick succession?

2. Nested message loops: I would expect this to cause a pause in the things that AutoIt usually does in its main loop in addition to message pumping, eg AdLib functions, checking for pause/quit from the tray icon, etc -- but is it any different when nested message loops occurs in a GUIRegisterMsg handler compared to at other times eg normal menu handling or calling MessageBox() from main line code (see eg example code on DllCall in help file)?

3. Functions causing the calling thread to be suspended: I expect the same effect as in any Windows program, ie program becomes unresponsive and inactive until execution resumed.

In summary:

  • Functions like TrackPopupMenu are "blocking" by some definitions, but seem to be regarded as OK in GUIRegisterMsg handlers -- is this right or am I skating on thin ice and writing fragile code - risking something "unexpected"?
  • I accidentally called WinWait() from a GUIRegisterMsg handler, and nothing seemed to go wrong -- was I just lucky, or is my analysis above about why it might have worked correct?
  • Is reentrance of GUIRegisterMsg handlers possible? (Because if so, I need to be very careful about writing any global data from one.)
I look forward to the commentary and advice of AutoIt experts!

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Too much explanation... really too much... i can´t answer your question but you can do the calls outside of the Registered function... setting a variable and checking the variable in the main loop.. let me show you.how to....

#include <WinAPI.au3>
#include <WindowsConstants.au3>
global $check = True
global $GlobalLParam
$hGui = GuiCreate("Outside the Function by monoscout999")
GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GuiSetState()
 
Do
    If $check then _MouseGetHover($GlobalLParam)
Until GuiGetMsg() = -3
 
Func WM_PAINT($hWndGUI, $MsgID, $WParam, $LParam)
    $Check = not $check
    Return "GUI_RUNDEFMSG"
EndFunc
 
Func _MouseGetHover($lLParam)
    GuiSetBkColor("0x"&hex(random(0,255),2)&hex(random(0,255),2)&hex(random(0,255),2))
EndFunc

What i know about the messages is that some messages need to return something, this may cause unexpected results.

EDIT: Did you have REAL need to work inside that function?

Edited by monoscout999

Share this post


Link to post
Share on other sites

As the documentation states, blocking a GUIRegisterMsg function can lead to unexpected results. I take that to mean the consequences are undefined. As such, you're just as likely to have success one day, and turn your computer into a molten pile the next. If you see examples in the help file where there is blocking, you should report it in the "Report Help File Issues Here" thread in this forum.

Take monoscout's advice, or use another method like GuiCtrlSendToDummy (if you have a GUI) from within the message so you can return to the main script quickly.

Share this post


Link to post
Share on other sites

Thank you wraithdu and monoscout999 for your suggestions.

If you see examples in the help file where there is blocking, you should report it in the "Report Help File Issues Here" thread in this forum.

That's easy! The example code on the help page for GUIRegisterMsg() {where it says commands such as "Msgbox()" can lead to unexpected behavior) uses --- you guessed it --- Msgbox()! And presumably the example code works...

Another example: On the help file page for _GUICtrlMenu_TrackPopupMenu() [which I believe to be a blocking function], the example shows the use of _GUICtrlMenu_TrackPopupMenu() within --- you guessed it --- a GUIRegisterMsg() handler! In fact, if you search the help file for example code containing "_GUICtrlMenu_TrackPopupMenu", you find that in every case this blocking function is called from within a GUIRegisterMsg handler, except one where is called in a Windows message handler created by _WinAPI_SetWindowLong(), which (I suspect) is also some kind of abnormal execution environment.

I totally agree with monoscout999 and wraithdu that ignoring warnings about "unexpected behaviour" is asking for trouble so it would be safer to contort my program's logic to avoid (eg) calling TrackPopupMenu from within a GUIRegisterMsg handler. On the other hand, it was much easier to copy from the examples, and when there are so many examples in the AutoIt help file where the warning seems to be disregarded, I wonder what exactly the danger is? Wraithdu is certainly right to advise that I regard "unexpected" as "undefined" even if it seems to work, but perhaps (does anyone know?) the "unexpected" behaviour is actually something quite benign, as long as one is aware and expects it. The writer the the help page for GUIRegisterMsg didn't let us in on what s/he thought we might find "unexpected"! (Cue the Spanish Inquisition... oops, no, this isn't a Python forum :-)

Sorry to go on about this, but I like to keep my code clean and simple (so I can understand it :-), so if the example code is acceptable, and the warning a bit stern, I'd be happy not to have to butcher my apparently working code.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Too much explanation... really too much... i can´t answer your question but you can do the calls outside of the Registered function... setting a variable and checking the variable in the main loop.. let me show you.how to....

#include <WinAPI.au3>
#include <WindowsConstants.au3>
global $check = True
global $GlobalLParam
$hGui = GuiCreate("Outside the Function by monoscout999")
GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GuiSetState()
 
Do
    If $check then _MouseGetHover($GlobalLParam)
Until GuiGetMsg() = -3
 
Func WM_PAINT($hWndGUI, $MsgID, $WParam, $LParam)
    $Check = not $check
    Return "GUI_RUNDEFMSG"
EndFunc
 
Func _MouseGetHover($lLParam)
    GuiSetBkColor("0x"&hex(random(0,255),2)&hex(random(0,255),2)&hex(random(0,255),2))
EndFunc

What i know about the messages is that some messages need to return something, this may cause unexpected results.

EDIT: Did you have REAL need to work inside that function?

Here is another similar way but using custom messages instead of global variables

#include <WinAPI.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
 
$hGui = GuiCreate("Outside the Function by monoscout999")
$dummy_id = GUICtrlCreateDummy()
GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GuiSetState()
 
While 1
    Switch GuiGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $dummy_id
            _MouseGetHover()
    EndSwitch
WEnd
 
Func WM_PAINT($hWndGUI, $MsgID, $WParam, $LParam)
    GUICtrlSendToDummy($dummy_id)
    Return "GUI_RUNDEFMSG"
EndFunc
 
Func _MouseGetHover()
    GuiSetBkColor("0x"&hex(random(0,255),2)&hex(random(0,255),2)&hex(random(0,255),2))
EndFunc

EDIT:

This example with WM_PAINT is not good because from WM_PAINT is called GuiSetBkColor() which can invoke WM_PAINT - so it can be recursive.

But my example clearly explain how to use custom messages by GUICtrlSendToDummy() from GUIRegisterMsg so it's non-blocking way.

Edited by Zedna

Share this post


Link to post
Share on other sites

That's easy! The example code on the help page for GUIRegisterMsg() {where it says commands such as "Msgbox()" can lead to unexpected behavior) uses --- you guessed it --- Msgbox()! And presumably the example code works...

I think that it depends on what message you register by GUIRegisterMsg(). Some messages are safe to slow down (or even block?)

and other are very sensitive to that. I have got experience from my scripts that WM_NOTIFY with some NM_XXX (ListView notifications - it was probably something related LV sorting) is sensitive - listview starts to behave unexpected way (bad header redraw etc.).

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