Jump to content

Recommended Posts

Posted (edited)

Because the native Msgbox is in blocking mode, which can cause exceptions in some applications, this thread call function was created to use non-blocking mode or other optimized applications like TCPRECV, allowing many Autoit users to optimize their applications according to their own needs.

 

#include-once
#include <Memory.au3>
#include <WinAPISys.au3>

; =======================================================================================================================
; Function ....:  Thread_Call
; Description ..: Use OPCODE to create threads.
; Parameters ...: $opcode - The FASM code.
;                 $control_wait - Control the thread blocking or non-blocking mode.
;                 $timeout - Control the thread blocking timeout setting(ms).
;                 $thread_wait_show - Control the thread blocking finish status display or not. 
; Return values : Success - Reply to the value returned by this function.(Need move function return data to $Recvice_retcode)
;                 Failure - Process crash ,need check the opcode.
; =======================================================================================================================
Func Thread_Call($opcode , $control_wait = 1 , $timeout = 2000 ,  $thread_wait_show = 0)
Local $pExecutableCode = _MemVirtualAlloc(0, BinaryLen($opcode), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
Local $tCodeBuffer = DllStructCreate("byte a["&BinaryLen($opcode)&"]", $pExecutableCode)
DllStructSetData($tCodeBuffer, 1, $opcode)
Local $Check_return = 0
Local $Recvice_retcode = DllStructCreate("int a[1];")
Local $aRet = DllCall("kernel32.dll", "handle", "CreateThread", "ptr", 0, "dword_ptr", 0, "ptr", $pExecutableCode, "ptr", DllStructGetPtr($Recvice_retcode), "dword", 0, "dword*", 0)
    If @error Then
        msgbox(0,1,"CreateThread error:" & @error & @CRLF)
    ElseIf $aRet[0] = 0 Then
        msgbox(0,2,"CreateThread error:" & "Null" & @CRLF)
    Else
        Local $hThread = $aRet[0]
        if $control_wait = 1 Then
            $aRet = DllCall("kernel32.dll", "dword", "WaitForSingleObject", "handle", $hThread, "dword", $timeout)
            If @error Then
                MsgBox(0,3,"WaitForSingleObject error: " & @error & @CRLF)
            Else
                Switch $aRet[0]
                    Case -1, 0xFFFFFFFF
                        $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
                        if $thread_wait_show = 1 then
                            msgbox(0,4,"WAIT_FAILED")
                        EndIf
                    Case 0x00000102
                        $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
                        if $thread_wait_show = 1 then
                            msgbox(0,5,"WAIT_TIMEOUT")
                        EndIf
                    Case 0x00000080
                        $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
                        if $thread_wait_show = 1 then
                            msgbox(0,"a","WAIT_ABANDONED")
                        EndIf
                    Case 0x00000000
                        $Check_return = 1
                        if $thread_wait_show = 1 then
                            MsgBox(0,"s","Wait success")
                        EndIf
                    Case Else
                        if $thread_wait_show = 1 then
                            msgbox(0,"b","Unknow = "& $aRet[0])
                        EndIf
                    EndSwitch
            EndIf
        EndIf
    EndIf
        if $control_wait = 1 Then
            _MemGlobalFree($pExecutableCode)
            $tCodeBuffer = 0
            _WinAPI_CloseHandle($hThread)
        EndIf
                    if $Check_return == 1 and $Check_return <> Null then
                        Return $Recvice_retcode.a
                    EndIf
EndFunc


The selected Msgbox button returns the value.

 

#include-once
#include <Thread_call_UDF.au3>

Local $result
For $i = 1 to 10
$result = Msgbox_new(2, "Title", "Number = "&$i, 1, -1)
Sleep(1)
MsgBox(0,"",$result)
Next






Func Msgbox_new($style=0, $title="", $message="", $control_wait = 1 , $timeout = 2000 ,  $thread_wait_show = 0)
Local $MessageAddress = DllCall("Kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("user32.dll"), "str", "MessageBoxW")
$MessageAddress = $MessageAddress[0]
Global $ptr_in_a = DllStructCreate("wchar a[65535];")
Global $ptr_in_b = DllStructCreate("wchar a[65535];")
$ptr_in_a.a = $message
$ptr_in_b.a = $title
Local $opcode = binary("0x" & _
"8B7D08" & _
"68" & Hex(BinaryMid($style,1,4)) & _
"68" & Hex(BinaryMid(DllStructGetPtr($ptr_in_b),1,4)) & _
"68" & Hex(BinaryMid(DllStructGetPtr($ptr_in_a),1,4)) & _
"6800000000" & _
"B8" & Hex(BinaryMid($MessageAddress, 1, 4)) & _
"FFD0" & _
"8907" & _
"C3")
Local $result = Thread_Call($opcode , $control_wait , $timeout ,  $thread_wait_show )
Return $result
EndFunc

Example_no wait_loop.au3 Example_no wait_no loop.au3 Example_wait_loop_timeout 2 Sec.au3 Example_wait_no loop_no timeout.au3 Thread_call_UDF.au3

Example_wait_no loop_no timeout_display result.au3

Edited by konya
Posted

Would you please be so kind and add a short description? So everyone knows what this function/UDF is intended to do and when to use.
This is true for your example scripts as well ;) 

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Posted

Alright after some more testing, I can say that this is pretty cool. Although I would love to see x64 support.

You can see all of the threads contained in the single AutoIt process which is neat:

Spoiler

threads.png

 

Posted (edited)
48 minutes ago, WildByDesign said:

Although I would love to see x64 support.

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=y ; or n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

; ===================== UDF =====================

#include-once
#include <Memory.au3>
#include <WinAPISys.au3>
#include <WinAPIHObj.au3>

Func Thread_Call($opcode, $control_wait = 1, $timeout = 2000, $thread_wait_show = 0)
    Local $pExecutableCode = _MemVirtualAlloc(0, BinaryLen($opcode), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
    Local $tCodeBuffer = DllStructCreate("byte a[" & BinaryLen($opcode) & "]", $pExecutableCode)
    DllStructSetData($tCodeBuffer, 1, $opcode)
    Local $Check_return = 0
    Local $Recvice_retcode = DllStructCreate("int a[1];")
    Local $aRet = DllCall("kernel32.dll", "handle", "CreateThread", "ptr", 0, "ulong_ptr", 0, "ptr", $pExecutableCode, "ptr", DllStructGetPtr($Recvice_retcode), "dword", 0, "dword*", 0)
    If @error Then
        MsgBox(0, 1, "CreateThread error:" & @error & @CRLF)
    ElseIf $aRet[0] = 0 Then
        MsgBox(0, 2, "CreateThread error:" & "Null" & @CRLF)
    Else
        Local $hThread = $aRet[0]
        If $control_wait = 1 Then
            $aRet = DllCall("kernel32.dll", "dword", "WaitForSingleObject", "handle", $hThread, "dword", $timeout)
            If @error Then
                MsgBox(0, 3, "WaitForSingleObject error: " & @error & @CRLF)
            Else
                Switch $aRet[0]
                    Case -1, 0xFFFFFFFF
                        $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
                        If $thread_wait_show = 1 Then
                            MsgBox(0, 4, "WAIT_FAILED")
                        EndIf
                    Case 0x00000102
                        $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
                        If $thread_wait_show = 1 Then
                            MsgBox(0, 5, "WAIT_TIMEOUT")
                        EndIf
                    Case 0x00000080
                        $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
                        If $thread_wait_show = 1 Then
                            MsgBox(0, "a", "WAIT_ABANDONED")
                        EndIf
                    Case 0x00000000
                        $Check_return = 1
                        If $thread_wait_show = 1 Then
                            MsgBox(0, "s", "Wait success")
                        EndIf
                    Case Else
                        If $thread_wait_show = 1 Then
                            MsgBox(0, "b", "Unknow = " & $aRet[0])
                        EndIf
                EndSwitch
            EndIf
        EndIf
    EndIf
    If $control_wait = 1 Then
        _MemVirtualFree($pExecutableCode, 0, $MEM_RELEASE)
        $tCodeBuffer = 0
        _WinAPI_CloseHandle($hThread)
    Else
        ; Close thread handle in non-blocking mode to avoid handle leaks
        If $aRet[0] <> 0 Then _WinAPI_CloseHandle($aRet[0])
    EndIf
    If $Check_return == 1 Then
        Return DllStructGetData($Recvice_retcode, 1)
    EndIf
EndFunc   ;==>Thread_Call

; ===================== UDF =====================
; ===================== EXAMPLE =====================

;~ #include <Thread_call_UDF.au3>

Func Msgbox_new($style = 0, $title = "", $message = "", $control_wait = 1, $timeout = 2000, $thread_wait_show = 0)
    Local $MessageAddress = DllCall("Kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("user32.dll"), "str", "MessageBoxW")
    $MessageAddress = $MessageAddress[0]

    Global $ptr_in_a = DllStructCreate("wchar a[65535];")
    Global $ptr_in_b = DllStructCreate("wchar a[65535];")
    $ptr_in_a.a = $message
    $ptr_in_b.a = $title

    Local $opcode = ""

    If @AutoItX64 Then
        ; --- x64 Machine Code ---
        $opcode = Binary("0x" & _
                "4883EC28" & _                                                       ; sub rsp, 0x28 (allocate 32b shadow space + 8b alignment)
                "31C9" & _                                                           ; xor ecx, ecx (RCX = 0 / hWnd)
                "48BA" & Hex(BinaryMid(Binary(DllStructGetPtr($ptr_in_a)), 1, 8)) & _ ; mov rdx, lpText
                "49B8" & Hex(BinaryMid(Binary(DllStructGetPtr($ptr_in_b)), 1, 8)) & _ ; mov r8, lpCaption
                "41B9" & Hex(BinaryMid(Binary($style), 1, 4)) & _                     ; mov r9d, uType
                "48B8" & Hex(BinaryMid(Binary($MessageAddress), 1, 8)) & _           ; mov rax, MessageBoxW address
                "FFD0" & _                                                           ; call rax
                "4883C428" & _                                                       ; add rsp, 0x28 (restore stack frame)
                "C3")                                                                ; ret
    Else
        ; --- x86 Machine Code (Your Original Snippet) ---
        $opcode = Binary("0x" & _
                "68" & Hex(BinaryMid(Binary($style), 1, 4)) & _                      ; push uType
                "68" & Hex(BinaryMid(Binary(DllStructGetPtr($ptr_in_b)), 1, 4)) & _ ; push lpCaption
                "68" & Hex(BinaryMid(Binary(DllStructGetPtr($ptr_in_a)), 1, 4)) & _ ; push lpText
                "6800000000" & _                                                     ; push 0 (hWnd)
                "B8" & Hex(BinaryMid(Binary($MessageAddress), 1, 4)) & _           ; mov eax, MessageBoxW address
                "FFD0" & _                                                           ; call eax
                "C3")                                                                ; ret
    EndIf

    Local $result = Thread_Call($opcode, $control_wait, $timeout, $thread_wait_show)
    Return $result
EndFunc   ;==>Msgbox_new

; ..your EXAMPLE of any of them 4

For $i = 1 To 10
    Msgbox_new(0, "Title", "Number = " & $i, 0)
    Sleep(1)
Next
Msgbox_new(0, "Title", "Number = 101", 1, -1)

 

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

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
×
×
  • Create New...