Jump to content

Thread message queue


j0kky
 Share

Recommended Posts

Hi guys,

I need to send a message (WM_APP message) to my thread and return immediatly, I tried to do it using PostMessage (a no-blocking function) with hWnd param = Null (it posts the message to the thread message queue).

I tried to get the message from the queue using PeekMessage (another function that returns immediatly) but it can't try the message.

I'm able to post and retrieve a message from a window message queue (using GUIRegisterMsg, it would be useful to know its source code) but it would be better if I could use the thread message queue.

I really don't understand why PeekMessage doesn't retrieve the message posted.

$iMsg = 0x8000
$tagPOINT = "struct; long x; long y; endstruct"
$tagMSG = "hwnd Hwnd;uint message;wparam wParam;lparam lParam;dword time;" & $tagPOINT
$tMSG = DllStructCreate($tagMSG)
$pMSG = DllStructGetPtr($tMSG)
$hwnd = GUICreate("GUI")
$aResult = DllCall("user32.dll", "bool", "PostMessage", "hwnd", Null, "uint", $iMsg, "wparam", "some", "lparam", "thing")
;$aResult[0] = 1 -----> the message is posted to the thread message queue
$aResult = DllCall("user32.dll", "bool", "PeekMessage", "ptr", $pMSG, "hwnd", Null, "uint", $iMsg, "uint", $iMsg, "uint", 1)
;@error = 0 -----> DllCall doesn't fail
;$aResult[0] = 0 ----> PeekMessage doesn't retrieve the message
If $aResult[0] <> 0 Then
    ConsoleWrite(DllStructGetData($tMSG, "wParam") & @CRLF)
    Exit
Else
    For $i = 1 To 4
        Beep(800, 250)
    Next
EndIf
Edited by j0kky
Link to comment
Share on other sites

Hi guys, I think I've solved my issue. The answer is not simple and really not clear.

I think in Autoit executables there is some functionality that removes istantly the message from message queue.

The only way to get the messages with PeekMessage is intercepting them in the same millisecond they are sent.

I searched on the forum for a way to run successfully PeekMessage but NOBODY in these years do it!!!!

So I've decided to do it by myself: there is the first script that launches the second script (with its thread ID as parameter) and enters in a PeekMessage loop, the second script just send the message to the first one.

First script:

Global Const $iMsg = 0x8000
Global Const $tagPOINT = "struct; long x; long y; endstruct"
Global Const $tagMSG = "hwnd Hwnd;uint message;wparam wParam;lparam lParam;dword time;" & $tagPOINT
Global $tMSG = DllStructCreate($tagMSG)
Local $aResult = DllCall("kernel32.dll", "dword", "GetCurrentThreadId")
$threadId = $aResult[0]
Run("AutoIt3.exe d.au3 " & $threadId)

For $i = 1 To 10000
    Local $aResult = DllCall("user32.dll", "bool", "PeekMessage", "ptr", DllStructGetPtr($tMSG), "hwnd", -1, "uint", $iMsg, "uint", $iMsg, "uint", 1)
    If $aResult[0] <> 0 Then
        ConsoleWrite(@ScriptName & " " & DllStructGetData($tMSG, "wparam") & " " & @MIN & ":" & @SEC & ":" & @MSEC & @CRLF)
        Beep(800, 100)
    EndIf
Next

Second script:

Global $threadId = Int($CmdLine[1])
$hfile = FileOpen("log.txt", 2)
Global Const $iMsg = 0x8000


$aResult = DllCall("user32.dll", "bool", "PostThreadMessage", "dword", $threadId, "uint", $iMsg, "wparam", 567, "lparam", "thing")
FileWrite($hfile, @ScriptName & " " & $aResult[0] & " " & @MIN & ":" & @SEC & ":" & @MSEC & @CRLF)
FileClose($hfile)
ShellExecute("log.txt")

In this way the first script can receive and process the message.

Otherwise, if I try to send the message by the same script, the PeekMessage loop is not already active and you can't intercept the message.

And what about if you need to get a message sent by the same thread?

It can be done in an unorthodox way: we need to install an hook procedure via SetWindowsHookEx.

#include <WinAPI.au3>
Global Const $iMsg = 0x8000
Global Const $tPOINT = "struct; long x; long y; endstruct"
Global Const $tagMSG = "hwnd Hwnd;uint message;wparam wParam;lparam lParam;dword time;" & $tPOINT
Global $tMSG = DllStructCreate($tagMSG)
Global $threadId = _WinAPI_GetCurrentThreadId()
Local $hCallback = DllCallbackRegister("_func", "LRESULT", "int;wparam;lparam")
Global $hHook = _WinAPI_SetWindowsHookEx($WH_GETMESSAGE, DllCallbackGetPtr($hCallback), Null, $threadId)

DllCall("user32.dll", "bool", "PostThreadMessage", "dword", $threadId, "uint", $iMsg, "wparam", 567, "lparam", 430)

For $i = 1 To 10000
    $aResult = DllCall("user32.dll", "bool", "PeekMessage", "ptr", DllStructGetPtr($tMSG), "hwnd", -1, "uint", $iMsg, "uint", $iMsg, "uint", 1)
    If $aResult[0] <> 0 Then
        ConsoleWrite(@ScriptName & " " & DllStructGetData($tMSG, "wparam") & " " & @MIN & ":" & @SEC & ":" & @MSEC & @CRLF)
        Beep(800, 100)
    EndIf
Next

Func _func($nCode, $wParam, $lParam)
    If $nCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Local $ftMSG = DllStructCreate($tagMSG, $lParam )
    Local $hwparam = DllStructGetData($ftMSG, "lParam" )
    ConsoleWrite("Hwnd = " & DllStructGetData($ftMSG, "Hwnd") & @CRLF & _
    "Message = " & Hex(DllStructGetData($ftMSG, "message"), 4) & @CRLF & _
    "wParam = " & DllStructGetData($ftMSG, "wParam") & @CRLF & _
    "lParam = " & DllStructGetData($ftMSG, "lParam") & @CRLF)
    Return 0
EndFunc

I'm very curious to know if I'm right about the default Autoit executables behaviour on message queue and if there is some way to stop it.

Maybe someone of Autoit developers will address me on the right way...

Edited by j0kky
Link to comment
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
 Share

×
×
  • Create New...