Sign in to follow this  
Followers 0
j0kky

Thread message queue

3 posts in this topic

#1 ·  Posted (edited)

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

Share this post


Link to post
Share on other sites



#3 ·  Posted (edited)

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

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

  • Similar Content

    • r0ash
      By r0ash
      Hey guys, MattDiesel over Stackoverflow mentioned this beautiful piece of code 
      #include <WindowsConstants.au3> #include <WinAPI.au3> Local $IDM_FONT = 33 Local $hWindow = WinGetHandle("Untitled - Notepad") _WinAPI_PostMessage($hWindow, $WM_COMMAND, $IDM_FONT, 0) Local $hFontWin = WinWait("Font") $select = ControlCommand($hFontWin, "", "ComboBox1", "GetCurrentSelection", "") WinClose($hFontWin) MsgBox(0,"", $select) I realized that _WinAPI_PostMessage can trigger menu click event, even if Notepad is minimized.
      How do we know what is the decimal value of *any menu item or sub-menu item*? How we know "Format > Font" menu-item is 33 as wParam to _WinAPI_PostMessage()? Have a look at snapshot.
      Regards.