Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

MessageFunc() [Obsolete]


  • Please log in to reply
17 replies to this topic
SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
MessageFunc() has been superseded by SetTimerF() - infogulch


MessageFunc() is obsolete

[color=#AA1122]; Alert : Experimental Code !!![/color]

#SingleInstance, Force
Gui +LastFound
hwnd := WinExist(), Params := "somestuff"
MessageFunc( "MySpecialFunction", hwnd, &Params, 50 )
MsgBox Regular Thread
Return

MessageFunc( Func, hWnd, wParam=0, Delay=0 ) {          ;  SetTimer for Function - By SKAN
 Static S                                ;  www.autohotkey.com/forum/viewtopic.php?t=63863
 If VarSetCapacity( S )                  ;                                  CD:19-Oct-2010
   DllCall( "ExitThread", UInt, DllCall( "Sleep", UInt,NumGet( S ) )
 + DllCall( "PostMessage", UInt,NumGet(S,4), UInt,NumGet(S,8), UInt,NumGet(S,12), UInt,0 )
 + DllCall( "GlobalFree", UInt,NumGet(S,16) ) ; Release Registered Callback
 + VarSetCapacity(S,0)                        ; Free Static variable
 + ( OnMessage( NumGet( S,8 ),"" ) < 1 ) )    ; Set Message Monitor OFF
 If ! IsFunc( Func )
    Return 0
 Msg := DllCall( "RegisterWindowMessage", Str,Func ),   OnMessage( Msg, Func )
 CBA := RegisterCallback( A_ThisFunc, "Fast", 4, &S )
 VarSetCapacity( S,64 ),  NumPut( Delay , S, 0 ), NumPut( hwnd  , S, 4 )
 NumPut( Msg   , S, 8 ),  NumPut( wParam, S,12 ), NumPut( CBA   , S,16 )
Return 1, DllCall( "CreateThread", UInt,0, UInt,0, UInt,CBA, UInt,0, UInt,0, UInt,0 )
}

MySpecialFunction( wParam ) {
 MsgBox,0, %A_ThisFunc%(), Pointer to Parameters:  %wParam%
}


MasterFocus
  • Moderators
  • 4323 posts
  • Last active: Jan 28 2016 01:38 AM
  • Joined: 08 Apr 2009
I changed MySpecialFunction to this:
MySpecialFunction( [color=cornflowerblue]wParam[/color] ) {
 [color=red]GLOBAL HWND[/color] ; already set
 [color=darkred]ToolTip[/color], %A_ThisFunc%()[color=violet]`n[/color]%A_Now%[color=violet]`n[/color]Pointer to Parameters:  %wParam%
 [color=darkred]MessageFunc( A_ThisFunc, [/color][color=red]HWND[/color][color=darkred], [/color][color=cornflowerblue]wParam[/color][color=darkred], 1000 )[/color]
}
After that, when I right-clicked the script's tray icon, the tooltip did not refresh.
Just reporting. :)

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Antonio França -- git.io -- github.com -- ahk4.net -- sites.google.com -- ahkscript.org

Member of the AHK community since 08/Apr/2009. Moderator since mid-2012.


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
If you execute script on any OS-level thread other than the main one, be prepared for instability. AutoHotkey is not designed to be multi-threaded. :(

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Just reporting. :)


You are a life-saver!.. Many thanks MasterFocus :)
The quirk has nothing to do with multi-threading. It is a benign thread. I will explain it later.


Lexikos, please help me.

I just dont understand how OnMessage() works.

If a monitored message that is numerically less than 0x312 arrives while the script is absolutely uninterruptible -- such as while a menu is displayed, a KeyDelay/MouseDelay is in progress, or the clipboard is being opened -- the message's function will not be called and the message will be treated as unmonitored.

By contrast, a monitored message of 0x312 or higher will be buffered during these uninterruptible periods; that is, its function will be called when the script becomes interruptible.


RegisterWindowMessage() uses a range of 0xC000 through 0xFFFF ( higher than WM_USER ). Why is it not being buffered when the thread is uninterruptable?

Here follows a demo:

Script 1
msgNum := DllCall( "RegisterWindowMessage", Str,"MySpecialFunction" )

^F2::
hWnd := WinExist( "AHK Unique Window Name ahk_class AutoHotkeyGUI" )
PostMessage, %MsgNum%, %A_TickCount%,0,, ahk_id %hWnd%
SoundBeep
Return

Script 2
GUI +AlwaysOnTop
Gui, Show, w240 h100, AHK Unique Window Name

msgNum := DllCall( "RegisterWindowMessage", Str,"MySpecialFunction" )
OnMessage( Msgnum, "MySpecialFunction" )
Return

MySpecialFunction( wParam ) {
 TrayTip, Test, %A_ThisFunc%()`nUInt Recieved:  %wParam%
}

Script 2 does not seem to buffer the window message received from Script 1, when traymenu is opened.

I would highly appreciate any clarification.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
There might be something related here . It might have to do with WM_ENTERMENULOOP message. See Chris's response and my final note.
Posted Image

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

There might be something related here .


Thanks for the useful link, but is does not answer my problem since you were dealing with system messages.
Why are user messages not buffered when the doc claims it will be?.

Edit:

WM_ENTERMENULOOP() trick does not affect Traymenu.. It is stubborn. :(

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
[color=green]// This function directly launches new threads rather than posting them as something like
// AHK_GUI_ACTION [/color][color=darkred](which would allow them to be queued by means of MSG_FILTER_MAX)[/color][color=green] because a message
// monitor function in the script can return "true" to exempt the message from further processing.
// Consequently, the MSG_FILTER_MAX queuing effect will only occur for monitored messages that are
// numerically greater than WM_HOTKEY. [/color][color=darkred]Other messages will not be subject to the filter and thus
// will arrive here even when the script is currently uninterruptible, in which case it seems best
// to discard the message because the current design doesn't allow for interruptions.[/color]
I think the problem in this case is that when you open the tray menu, it enters a modal menu loop. Since AutoHotkey's main message loop isn't running, it can't apply the message filter which allows those messages to remain queued. The modal menu loop dispatches messages to AutoHotkey's main window procedure, which in turn calls MsgMonitor(), which discards the message as explained above.

I suggest you try overriding right-click of the tray menu to show the tray menu via the Menu command. Perhaps that will make a difference. (But it might not work when the script is uninterruptible...)
OnMessage(0x404, "AHK_NOTIFYICON")
...
AHK_NOTIFYICON(wParam, lParam)
{
    if (lParam = 0x205) ; WM_RBUTTONUP
    {
        Menu, Tray, Show
        return 0
    }
}
Untested.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Thanks for the clarification Lexikos. :)

The documentation needs correction, then. I took it at face value and wrote a mammoth 600L library wrapper where all subroutines are Functions and are triggered with PostMessage(). Now, I have to resort to the ugly SetTimer,SubRoutine, -1.

I would not say OnMessage() / PostMessage() is better.. It is also ugly workaround as it would make the calling script Persistent.

So, is there any alternative mechanism to trigger an another function while allowing the calling function to return ?
for eg: To trigger another Function() from WM_NOTIFY()

I see that callback routines are not affected when Traymenu is open.
Any scope for messing with Registered callbacks through API ?

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

I suggest you try overriding right-click of the tray menu to show the tray menu via the Menu command. Perhaps that will make a difference. (But it might not work when the script is uninterruptible...)

OnMessage(0x404, "AHK_NOTIFYICON")
...
AHK_NOTIFYICON(wParam, lParam)
{
    if (lParam = 0x205) ; WM_RBUTTONUP
    {
        Menu, Tray, Show
        return 0
    }
}
Untested.


Oops! I missed that part. You edited, I guess..
Many thanks for the snippet.. I will try it.

Edit:

I see that callback routines are not affected when Traymenu is open.
Any scope for messing with Registered callbacks through API ?


SendMessageCallback() looks promising :O

Edit:

SetTimer() :shock:

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

SetTimer() :shock:

That will probably work as long as the script/process is checking for messages. (The tray menu's message loop should suffice.) It should bypass the script's thread interruptibility checks.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

So, is there any alternative mechanism to trigger an another function while allowing the calling function to return ?
for eg: To trigger another Function() from WM_NOTIFY()

One of the problems with SetTimer is that it will launch function in another AHK thread so function called can not return value. Although it might not be needed in your case I often encounter those problems. For instance, control may chose to ignore event if you returned false. If you call user function from event handler that should let user decide, then you can't call it via SetTimer. (I had that in almost all 3thd party control modules - RaGrid, HiEdit, RichEdit etc...). The fact is, OnMessage system is not designed on good grounds (probably because absence of real multi-threading) and advanced uses are problematic (sometimes even basic uses).

Btw, what is the difference in your case between SetTimer command and API function ?
Posted Image

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

One of the problems with SetTimer is that it will launch function in another AHK thread so function called can not return value.

To use a return value the calling function would have to wait, which would more or less defeat the point of using a timer in the first place. The part of SKAN's request that says "while allowing the calling function to return" implies he isn't interested in the return value. Btw, SetTimer() won't launch another AHK thread if you use the "Fast" callback option.

For instance, control may chose to ignore event if you returned false. If you call user function from event handler that should let user decide, then you can't call it via SetTimer.

Why would you even consider calling it via SetTimer in that case?

The fact is, OnMessage system is not designed on good grounds (probably because absence of real multi-threading) and advanced uses are problematic (sometimes even basic uses).

OnMessage is no more limiting than the underlying window messaging architecture. Even with multi-threading, each window can only receive messages via the message loop of the thread which created it. I think you're wrongly blaming OnMessage for the lack of multi-threading capabilities.

Btw, what is the difference in your case between SetTimer command and API function ?

AutoHotkey has a single OS-level timer to maintain all script timers. Script timers can't launch when a higher priority/uninterruptible thread is running, whereas OS-level timers created with SetTimer() can launch since callbacks aren't subject to priority checks.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

Why would you even consider calling it via SetTimer in that case?

I don't. I state in some of my modules to return from handler as fast as possible. Some tests show me that if you for instance take longer time to calculate script may freeze (or do some other stuff, like showing input gui). Up to day, I didn't find any solution for this freezing problem. For instance, see Remarks section in Toolbar_Addfunction (starting with "To avoid lost messages and/or script lockup...")

Even with multi-threading, each window can only receive messages via the message loop of the thread which created it.

Altho you say that, I encounter script freezing in many cases of subclassing and in some cases of OnMessage unlike in other languages. I thought that it would be possible to use AttachThreadInput() to specify Gui message loop in another thread. However, it seems that this method is problematic due to the Windows design issues (many of which are undocumented and reported on forums).

Thx for other info.
Posted Image

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Altho you say that, I encounter script freezing in many cases of subclassing and in some cases of OnMessage unlike in other languages.

That's irrelevant. I suppose it's the result of AutoHotkey trying to make up for the lack of multi-threading, running its message loop automatically at regular intervals behind the scenes. In other languages, the message loop is an explicit thing or at least executed at well-defined points (e.g. DoEvents in VB). Critical ∞/SetBatchLines -1 is supposed to prevent that behind-the-scenes stuff, but I'm not convinced it's 100% reliable.

I thought that it would be possible to use AttachThreadInput() to specify Gui message loop in another thread.

I suppose you mistook "the input processing mechanism" to mean the application's message loop. It doesn't.

You edited, I guess..

Btw, you guessed right.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

I think you're wrongly blaming OnMessage for the lack of multi-threading capabilities.


I suppose it's the result of AutoHotkey trying to make up for the lack of multi-threading, running its message loop automatically at regular intervals behind the scenes.


Maybe I can't define the problem as good as you can, but we both seem to agree that lack of multithreading is problematic.

Do you have any ideas of fixing this issue ?
Posted Image