tdw Posted September 2, 2011 Share Posted September 2, 2011 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" functionsGUIRegisterMsg() refers toMsgbox() (as above), andAdLibRegister 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! Link to comment Share on other sites More sharing options...
monoscout999 Posted September 2, 2011 Share Posted September 2, 2011 (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 September 2, 2011 by monoscout999 Link to comment Share on other sites More sharing options...
wraithdu Posted September 2, 2011 Share Posted September 2, 2011 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. Link to comment Share on other sites More sharing options...
tdw Posted September 4, 2011 Author Share Posted September 4, 2011 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. Link to comment Share on other sites More sharing options...
Zedna Posted September 4, 2011 Share Posted September 4, 2011 (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 September 4, 2011 by Zedna Resources UDF ResourcesEx UDF AutoIt Forum Search Link to comment Share on other sites More sharing options...
Zedna Posted September 4, 2011 Share Posted September 4, 2011 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.). Resources UDF ResourcesEx UDF AutoIt Forum Search Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now