dijir Posted March 28, 2011 Posted March 28, 2011 (edited) Hello, I'm trying to send keys in a program but I want to do this in new thread. While my application is sending keys, it freezes until finish to send all keys. I need to do the send() from a new thread then while the new created thread is sending keys, my application do other functions. I found some sources: This is the send() in SendInput API expandcollapse popupGlobal Const $KEYEVENTF_KEYUP = 2 Global Const $KEYEVENTF_UNICODE = 4 Global Const $INPUT_KEYBOARD = 1 Global Const $iInputSize = 28 Global Const $tagKEYBDINPUT = _ 'ushort wVk;' & _ 'ushort wScan;' & _ 'dword dwFlags;' & _ 'dword time;' & _ 'ulong_ptr dwExtraInfo' Global Const $tagINPUT = _ 'dword type;' & _ $tagKEYBDINPUT & _ ';dword pad;' & _ 'dword pad;' Global $hDll = DllOpen('user32.dll') Global $sString = "abcde abcde abcde abcde abcde " HotKeySet("{HOME}", "__send") While 1 WEnd func __send() _SendEx($sString) EndFunc DllClose($hDll) Exit Func _SendInputKB($iInputs, $pInputs, $iSize, $hDll = 'user32.dll') Local $aRet = DllCall($hDll, 'uint', 'SendInput', 'uint', $iInputs, 'ptr', $pInputs, 'int', $iSize) If @error Or Not $aRet[0] Then Return SetError(1, 0, False) Return SetError(0, 0, True) EndFunc Func _SendEx($sString) Local $tINPUTs, $pINPUTs, $iINPUTs Local $sStruct Local $iFlags, $iStrLen $iFlags = BitOR($KEYEVENTF_UNICODE, $KEYEVENTF_KEYUP) $iStrLen = StringLen($sString) $sStruct = '' For $i = 1 To $iStrLen * 2 $sStruct &= $tagINPUT Next $tINPUTs = DllStructCreate($sStruct) $pINPUTs = DllStructGetPtr($tINPUTs) $iINPUTs = $iStrLen * 2 For $i = 0 To $iStrLen-1 Local $Temp = AscW(StringMid($sString, $i+1, 1)) Local $iOffsetDown = $i * 8 Local $iOffsetUp = $i * 16 DllStructSetData($tINPUTs, $iOffsetDown+1, $INPUT_KEYBOARD) DllStructSetData($tINPUTs, $iOffsetDown+3, $Temp) DllStructSetData($tINPUTs, $iOffsetDown+4, $KEYEVENTF_UNICODE) DllStructSetData($tINPUTs, $iOffsetUp+9, $INPUT_KEYBOARD) DllStructSetData($tINPUTs, $iOffsetUp+11, $Temp) DllStructSetData($tINPUTs, $iOffsetUp+12, $iFlags) Next _SendInputKB($iINPUTs, $pINPUTs, $iInputSize, $hDll) EndFunc And this is the script to use APIs in new thread: expandcollapse popupGlobal Const $STATUS_PENDING = 0x103 Global Const $STILL_ACTIVE = $STATUS_PENDING ; ThreadID is @extended ;=============================================================================== ; ; Function Name: _Thread_Create ; Description:: Creates a thread ; Parameter(s): see MSDN (lpThreadId is removed) ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; @extended will be ThreadID ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_Create($lpThreadAttributes, $dwStackSize, $lpStartAddress, $lpParameter, $dwCreationFlags) Local $result = DllCall("kernel32.dll","ptr","CreateThread", "ptr", $lpThreadAttributes, "dword", $dwStackSize, "ptr", $lpStartAddress, "ptr", $lpParameter, "dword", $dwCreationFlags, "dword*", 0) Return SetError($result[0]=0,$result[6],$result[0]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_Terminate ; Description:: Terminates a thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_Terminate($hThread,$dwExitCode) Local $result = DllCall("Kernel32.dll","int","TerminateThread","ptr",$hThread,"dword",$dwExitCode) Return SetError($result[0]=0,0,$result[0]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_Exits ; Description:: Exits the current thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): none ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_Exit($dwExitCode) DllCall("Kernel32.dll","none","ExitThread","dword",$dwExitCode) EndFunc ;=============================================================================== ; ; Function Name: _Thread_GetExitCode ; Description:: retrieves ExitCode of a thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_GetExitCode($hThread) Local $result = DllCall("Kernel32.dll","int","GetExitCodeThread","ptr",$hThread,"dword*",0) Return SetError($result[0]=0,0,$result[2]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_GetID ; Description:: retrieves ThreadID of a thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_GetID($hThread) Local $result = DllCall("Kernel32.dll","dword","GetThreadId","ptr",$hThread) Return SetError($result[0]=0,0,$result[0]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_GetPriority ; Description:: retrieves priority of a thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_GetPriority($hThread) Local $result = DllCall("Kernel32.dll","int","GetThreadPriority","ptr",$hThread) Return SetError($result[0]=0,0,$result[0]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_SetPriority ; Description:: sets priority of a thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_SetPriority($hThread,$nPriority) Local $result = DllCall("Kernel32.dll","int","SetThreadPriority","ptr",$hThread,"int",$nPriority) Return SetError($result[0]=0,0,$result[0]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_Suspend ; Description:: suspends a thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_Suspend($hThread) Local $result = DllCall("Kernel32.dll","int","SuspendThread","ptr",$hThread) Return SetError($result[0]=-1,0,$result[0]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_Resume ; Description:: resumes a thread ; Parameter(s): see MSDN ; Requirement(s): minimum Win2000 ; Return Value(s): see MSDN ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_Resume($hThread) Local $result = DllCall("Kernel32.dll","int","ResumeThread","ptr",$hThread) Return SetError($result[0]=-1,0,$result[0]) EndFunc ;=============================================================================== ; ; Function Name: _Thread_Wait ; Description:: Waits for a thread to terminate ; Parameter(s): $hThread - Handle of thread ; $nTimeOut - [optional] Timeout (default: 0xFFFFFFFF => INFINTE) ; Requirement(s): minimum Win2000 ; Return Value(s): Success: true ; on TimeOut, @eeor will be set to -1 ; On error, @error will be set to 1 ; Author(s): Prog@ndy ; ;=============================================================================== ; Func _Thread_Wait($hThread,$nTimeout=0xFFFFFFFF) Local $result = DllCall("Kernel32.dll", "dword", "WaitForSingleObject", "ptr", $hThread, "int", $nTimeout) If @error Then Return SetError(2,0,0) Switch $result[0] Case -1, 0xFFFFFFFF Return SetError(1,0,0) Case 0x00000102 Return SetError(-1,0,1) Case Else Return 1 EndSwitch EndFunc #include <WinAPI.au3> $tagMSGBOXPARAMS = _ "UINT cbSize;" & _ "HWND hwndOwner;" & _ "ptr hInstance;" & _ "ptr lpszText;" & _ "ptr lpszCaption;" & _ "DWORD dwStyle;" & _ "ptr lpszIcon;" & _ "UINT_PTR dwContextHelpId;" & _ "ptr lpfnMsgBoxCallback;" & _ "DWORD dwLanguageId;" ; creates a struct for an Unicode-String Func _UnicodeStruct($text) ; Prog@ndy Local $s = DllStructCreate("wchar[" & StringLen($text)+1 & "]") DllStructSetData($s,1,$text) Return $s EndFunc ; retrieves Address of a function Func _Thread_GetProcAddress($hModule,$sProcname) ; Prog@ndy Local $result = DllCall("kernel32.dll","ptr","GetProcAddress","hwnd",$hModule,"str",$sProcname) Return $result[0] EndFunc ; Struct to send to the Thread ; in this case the MsgBox-Params $MSGBOXPARAMS = DllStructCreate($tagMSGBOXPARAMS) DllStructSetData($MSGBOXPARAMS,"cbSize",DllStructGetSize($MSGBOXPARAMS)) $stText = _UnicodeStruct("The messageBox in a separate thead!") DllStructSetData($MSGBOXPARAMS,"lpszText",DllStructGetPtr($stText)) $stCaption = _UnicodeStruct("Caption") DllStructSetData($MSGBOXPARAMS,"lpszCaption",DllStructGetPtr($stCaption)) DllStructSetData($MSGBOXPARAMS,"dwStyle",17) ; msgBox-style ; Use MessageBoxIndirect Unicode as ThreadProc ; normal MessageBox doesn't work, since CreateThread just has one possible parameter. Local $hThreadProc = _Thread_GetProcAddress(_WinAPI_GetModuleHandle("user32.dll"),"MessageBoxIndirectW") $hThread = _Thread_Create(0 ,0, $hThreadProc, DllStructGetPtr($MSGBOXPARAMS), 0) $ThreadID = @extended While MsgBox(69, "main", "Main script is not blocked" )=4 WEnd MsgBox(0, "Thread-Info", "Handle: " & $hThread & @CRLF & "Thread-ID: " & $ThreadID) _Thread_Wait($hThread) $code = _Thread_GetExitCode($hThread) MsgBox(0, 'Thread ended', "Threaded MsgBox returned: " & $code) Is it possible to send() from a new thread? I've tryied to write the first script (SendInput) in the second but don't work. Thank-you Edited March 29, 2011 by dijir
Richard Robertson Posted March 28, 2011 Posted March 28, 2011 AutoIt does not support multithreading.
dijir Posted March 28, 2011 Author Posted March 28, 2011 (edited) AutoIt does not support multithreading.Have you tested the second script? Edited March 28, 2011 by dijir
trancexx Posted March 28, 2011 Posted March 28, 2011 (edited) Have you tested the second script? Richard Robertson is correct about multithreading and AutoIt. I have no idea why he felt a need to say that, but he's correct. That doesn't mean you can't run some code in new thread. For example I could write something like this from your script: expandcollapse popup#include <WinAPI.au3> #include <Memory.au3> Func _SendInputKB_NewThread($iINPUTs, $pINPUTs, $iSize, $fFreeRes = False) If @AutoItX64 Then Return SetError(1, 0, 0) ; your code wouldn't work for x64 Local $aCall Local Static $pSpace, $pSendInput If $pSpace Then If $fFreeRes Then _MemVirtualFree($pSpace, 0, $MEM_RELEASE) $pSpace = 0 $pSendInput = 0 EndIf Else $aCall = DllCall("kernel32.dll", "ptr", "GetProcAddress", _ "handle", _WinAPI_GetModuleHandle("user32.dll"), _ "str", "SendInput") If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) $pSendInput = $aCall[0] $pSpace = _MemVirtualAlloc(0, 23, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) EndIf Local $tCodeBuffer = DllStructCreate("byte[23]", $pSpace) DllStructSetData($tCodeBuffer, 1, _ "0x" & _ "68" & Hex(BinaryMid($iSize, 1, 4)) & _ ; push cbSize "68" & Hex(BinaryMid($pINPUTs, 1, 4)) & _ ; push pInputs "68" & Hex(BinaryMid($iINPUTs, 1, 4)) & _ ; push nInputs "B8" & Hex(BinaryMid($pSendInput, 1, 4)) & _ ; mov eax, [SendInput] "FFD0" & _ ; call eax "C3" _ ) $aCall = DllCall("kernel32.dll", "handle", "CreateThread", _ "ptr", 0, _ "dword", 0, _ "ptr", $pSpace, _ "ptr", 0, _ "dword", 0, _ "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(8, 0, "") Return $aCall[0] ; Thread handle (to be able to close it at some point) EndFunc Edited March 28, 2011 by trancexx ♡♡♡ . eMyvnE
dijir Posted March 28, 2011 Author Posted March 28, 2011 (edited) Thank-you so much trancexx, that's exactly what I need.Another question, is it possible to use send() parameters with SendInput?I've checked with api monitor and found this script SendInput uses:Out:SendInput(nInputs: 0x4E,pInputs:0x00FF3008,cbSize: 0x1C) 0x0000004E 0x00410D4F autoit3.exe + 0x00010D4F 0x00000FA0 0x000003DC 0x00000000 EAX=0x00000004, EBX=0x008cf1f8, ECX=0x008cee08, EDX=0x7e37f140, ESI=0x7e360000, EDI=0x004a7f20, EFL=0x00000246, ESP=0x008cedfc, EBP=0x008cee3c EAX=0x0000004e, EBX=0x008cf1f8, ECX=0x008cedf4, EDX=0x7c90e514, ESI=0x7e360000, EDI=0x004a7f20, EFL=0x00000246, ESP=0x008cee08, EBP=0x008cee3c -1.#IND 14:25:47:435:291,4 301 - user32.dll - SendInputand function autoit send() uses:Out:First SendInput ---------------------------------------------------------------- SendInput(nInputs: 0x1,pInputs:0x008CF6E0,cbSize: 0x1C) 0x00000001 0x00437851 autoit3.exe + 0x00037851 0x00000F0C 0x000008F0 0x00000000 EAX=0x00000000, EBX=0x00000051, ECX=0x7e370010, EDX=0x008cf6e0, ESI=0x00000000, EDI=0x008cf874, EFL=0x00000246, ESP=0x008cf6d4, EBP=0x004a7fa8 EAX=0x00000001, EBX=0x00000051, ECX=0x008cf6cc, EDX=0x7c90e514, ESI=0x00000000, EDI=0x008cf874, EFL=0x00000246, ESP=0x008cf6e0, EBP=0x004a7fa8 -1.#IND 18:35:26:121:891,0 11 - user32.dll - SendInput Second SendInput: ---------------------------------------------------------------- SendInput(nInputs: 0x1,pInputs:0x008CF6E4,cbSize: 0x1C) 0x00000001 0x00437851 autoit3.exe + 0x00037851 0x00000F0C 0x000008F0 0x00000000 EAX=0x00000000, EBX=0x00000051, ECX=0x00000010, EDX=0x008cf6e4, ESI=0x00000071, EDI=0x008cf874, EFL=0x00000246, ESP=0x008cf6d8, EBP=0x004a7fa8 EAX=0x00000001, EBX=0x00000051, ECX=0x008cf6d0, EDX=0x7c90e514, ESI=0x00000071, EDI=0x008cf874, EFL=0x00000246, ESP=0x008cf6e4, EBP=0x004a7fa8 -1.#IND 18:35:26:120:242,2 17 - user32.dll - SendInputHow can I use parameters from SendInput send() to the script?Source:expandcollapse popup#include <WinAPI.au3> #include <Memory.au3> Global Const $KEYEVENTF_KEYUP = 2 Global Const $KEYEVENTF_UNICODE = 4 Global Const $INPUT_KEYBOARD = 1 Global Const $iInputSize = 28 Global Const $MEM_COMMIT=0x00001000 Global Const $PAGE_EXECUTE_READWRITE = 0x40 Global Const $tagKEYBDINPUT = _ 'ushort wVk;' & _ 'ushort wScan;' & _ 'dword dwFlags;' & _ 'dword time;' & _ 'ulong_ptr dwExtraInfo' Global Const $tagINPUT = _ 'dword type;' & _ $tagKEYBDINPUT & _ ';dword pad;' & _ 'dword pad;' Global $hDll = DllOpen('user32.dll') Global $sString = "abcde abcde abcde abcde abcde " HotKeySet("{HOME}", "__send") HotKeySet("{END}", "exiter") Run("notepad.exe") WinWait("Untitled - Notepad") WinActivate("Untitled - Notepad") $timer2='' While 1 $timer=TimerInit() if $timer2='' Then $timer2=TimerInit() EndIf if TimerDiff($timer2)>1000 Then _SendEx("00") $timer2='' EndIf WEnd DllClose($hDll) Exit func __send() _SendEx("AA") EndFunc func exiter() Exit EndFunc Func _SendInputKB_NewThread($iINPUTs, $pINPUTs, $iSize, $fFreeRes = False) If @AutoItX64 Then Return SetError(1, 0, 0) ; your code wouldn't work for x64 Local $aCall Local Static $pSpace, $pSendInput If $pSpace Then If $fFreeRes Then _MemVirtualFree($pSpace, 0, $MEM_RELEASE) $pSpace = 0 $pSendInput = 0 EndIf Else $aCall = DllCall("kernel32.dll", "ptr", "GetProcAddress", _ "handle", _WinAPI_GetModuleHandle("user32.dll"), _ "str", "SendInput") If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) $pSendInput = $aCall[0] $pSpace = _MemVirtualAlloc(0, 23, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) EndIf Local $tCodeBuffer = DllStructCreate("byte[23]", $pSpace) DllStructSetData($tCodeBuffer, 1, _ "0x" & _ "68" & Hex(BinaryMid($iSize, 1, 4)) & _ ; push cbSize "68" & Hex(BinaryMid($pINPUTs, 1, 4)) & _ ; push pInputs "68" & Hex(BinaryMid($iINPUTs, 1, 4)) & _ ; push nInputs "B8" & Hex(BinaryMid($pSendInput, 1, 4)) & _ ; mov eax, [SendInput] "FFD0" & _ ; call eax "C3" _ ) $aCall = DllCall("kernel32.dll", "handle", "CreateThread", _ "ptr", 0, _ "dword", 0, _ "ptr", $pSpace, _ "ptr", 0, _ "dword", 0, _ "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(8, 0, "") Return $aCall[0] ; Thread handle (to be able to close it at some point) EndFunc Func _SendInputKB($iInputs, $pInputs, $iSize, $hDll = 'user32.dll') Local $aRet = DllCall($hDll, 'uint', 'SendInput', 'uint', $iInputs, 'ptr', $pInputs, 'int', $iSize) If @error Or Not $aRet[0] Then Return SetError(1, 0, False) Return SetError(0, 0, True) EndFunc Func _SendEx($sString) Local $tINPUTs, $pINPUTs, $iINPUTs Local $sStruct Local $iFlags, $iStrLen $iFlags = BitOR($KEYEVENTF_UNICODE, $KEYEVENTF_KEYUP) $iStrLen = StringLen($sString) $sStruct = '' For $i = 1 To $iStrLen * 2 $sStruct &= $tagINPUT Next $tINPUTs = DllStructCreate($sStruct) $pINPUTs = DllStructGetPtr($tINPUTs) $iINPUTs = $iStrLen * 2 For $i = 0 To $iStrLen-1 Local $Temp = AscW(StringMid($sString, $i+1, 1)) Local $iOffsetDown = $i * 8 Local $iOffsetUp = $i * 16 DllStructSetData($tINPUTs, $iOffsetDown+1, $INPUT_KEYBOARD) DllStructSetData($tINPUTs, $iOffsetDown+3, $Temp) DllStructSetData($tINPUTs, $iOffsetDown+4, $KEYEVENTF_UNICODE) DllStructSetData($tINPUTs, $iOffsetUp+9, $INPUT_KEYBOARD) DllStructSetData($tINPUTs, $iOffsetUp+11, $Temp) DllStructSetData($tINPUTs, $iOffsetUp+12, $iFlags) Next _SendInputKB_NewThread($iINPUTs, $pINPUTs, $iInputSize, False) ;_SendInputKB($iINPUTs, $pINPUTs, $iInputSize, $hDll) EndFuncThanks Edited March 28, 2011 by dijir
dijir Posted March 30, 2011 Author Posted March 30, 2011 (edited) I found API that send async keys and solved my problem without need create new thread. Source: global const $KEYEVENTF_EXTENDEDKEY = 0x0001 global const $KEYEVENTF_KEYUP = 0x0002 HotKeySet("{HOME}", "press") HotKeySet("^{HOME}", "press2") HotKeySet("{END}", "exiter") $key_to_send='a' func press() $timer=TimerInit() DllCall('user32.dll', 'Int', 'keybd_event', 'byte', StringToBinary(StringUpper($key_to_send)), 'dword', '0x45' , 'dword', 0x0, 'int', 0) DllCall('user32.dll', 'Int', 'keybd_event', 'byte', StringToBinary(StringUpper($key_to_send)), 'dword', '0x45' , 'dword', $KEYEVENTF_KEYUP, 'int', 0) ConsoleWrite("Send "&$key_to_send&"("&StringToBinary(StringUpper($key_to_send))&") in "&Round(TimerDiff($timer), 2)&" ms"&@CRLF) EndFunc func press2() $timer=TimerInit() send($key_to_send) ConsoleWrite("Send "&$key_to_send&"("&StringToBinary(StringUpper($key_to_send))&") in "&Round(TimerDiff($timer), 2)&" ms"&@CRLF) EndFunc func exiter() exit EndFunc while 1 WEnd Thank-you again trancexx, I like your code Edited March 30, 2011 by dijir
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