Jump to content
tcurran

UDF for detecting whether AutoIt can cut-paste from a window

Recommended Posts

tcurran

Here's a short UDF that will, at least in most cases, detect whether a window can be copied from or pasted to programmatically--for example, by Send()ing ctl-c, ctl-v. This is often disabled when programs (like your AutoIt script) run at a lower UAC integrity level than the application they are trying to operate on.

#include <WinAPI.au3>

Func _WindowIsPasteable($handle) ;accepts window handle; returns true or false whether a window will accept Ctl-C, Ctl-V
    Local $bCanPaste = True
    Local $hTestWindowPID = 0
    Local $hTestWindowTID = _WinAPI_GetWindowThreadProcessId($handle, $hTestWindowPID)
    _WinAPI_AttachThreadInput(_WinAPI_GetCurrentThreadId(), $hTestWindowTID, True);attach to window we want to paste into
    $bCanPaste = _WinAPI_GetFocus() ;Test whether window is paste-able--returns False if it is not
    _WinAPI_AttachThreadInput(_WinAPI_GetCurrentThreadId, $hTestWindowTID, False);detach from window thread
    Return $bCanPaste
EndFunc

Pass it a window handle; it returns true or false whether a window will accept programmatic pasting. The function may not work on the CMD window, since it handles the clipboard uniquely.

This function works by attaching to the program thread of the window whose handle it receives, then attempting to perform a GetFocus on that thread. In most cases, the attempt will fail if the window will not accept programmatic copy-paste.

Edited by tcurran

Share this post


Link to post
Share on other sites
qwert

Thanks for this.  I hadn't considered such a method.  But I do have a question:

Quote

the attempt will fail if the window will not accept programmatic copy-paste

Can you point to documentation that explains this in more detail?  Are there cases where a browser window, for example, would return False (='no paste')?

Share this post


Link to post
Share on other sites
tcurran

qwert--

Those are excellent questions. This approach was suggested to me by "Joe" the developer of ArsClip. I adapted his approach to AutoIT, tested it in my particular application (it worked!!) and posted it here.

Your question about browser windows is particularly trenchant, but--since I haven't tested it--I have no answer. Please post back here if you learn whether it does or doesn't work.

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

  • Similar Content

    • AnonymousX
      By AnonymousX
      Hello,
      I'm trying to write a script that moves copies excel cells into an array. I'll than manipulate the values and send array into another program. 
      I don't want range to be specific to a workbook, or sheet, or set of cells.
      I want user to be able to highlight desired cells and to copy either normally ("Ctrl+C") or by a hotkey ("Alt+C"). 
      Could someone help me with this?
      Thank you,
      I've tried to write the framework: (edited)
      #include <MsgBoxConstants.au3> #include <Array.au3> #include <Excel.au3> HotKeySet("!v", "Pastedata") While True Sleep(1000) WEnd func Makearray() local $bArray ;User has cells already copied ;Convert clipboard into an array ;I don;t know how excel stores data to clipboard so don;t know how to bring it into array _Arraydisplay($bArray) MsgBox(0,0,$bArray) return $bArray endfunc func Pastedata() Local $aArray MsgBox(0,0,"wait",1) ;make array based on assumption user has already copied a range to clipboard $aArray = Makearray() ;paste code ;don;t worry about this I got the rest endfunc  
    • dadalt95
      By dadalt95
      Hi!
      I want to get the signal in this website:
      https://binary-signal.com/pt/chart/eurusd
      I have tried using _IEBodyReadText  and some _StringBetween. What happens is that the text are being update every tick and _IEBodyReadText doesn't.
      To perform the update I used  _IEAction($oIE, "refresh") but it's not good because the website block me after some time due too many requests..
      Is there any other way to get this text every tick?
      PS: The text I want to get is WAIT, CALL or PUT.
       
      Here is the code:
      global $oIE = _IECreate ('https://binary-signal.com/pt/chart/eurusd', 0, 1 , 1 , 0) Local $sText = _IEBodyReadText($oIE) $result = _StringBetween ( $sText , 'PUTEUR/USD on Binary-signal.com', 'sinal está PRONTA') ;MsgBox ( 0, "asf", $result[0]) $espera=StringInStr($result[0], "WAIT") $compra=StringInStr($result[0], "CALL") $venda=StringInStr($result[0], "PUT") ;MsgBox($MB_SYSTEMMODAL, "", $espera) $n=0 $c=0 Captar() Func Captar() ;_IENavigate($oIE, "https://binary-signal.com/pt/chart/eurusd") ;MsgBox($MB_SYSTEMMODAL, "", $n) Local $sText = _IEBodyReadText($oIE) $result = _StringBetween ( $sText , 'PUTEUR/USD on Binary-signal.com', 'sinal está PRONTA') If (Not $compra=0) And $n=0 Then MsgBox($MB_SYSTEMMODAL, "", "COMPRE") $n=1 $c=$c+1 ;_IEAction($oIE, "refresh") Sleep(60000) Captar() ElseIf (Not $venda=0) And $n=0 Then MsgBox($MB_SYSTEMMODAL, "", "VENDA") $c=$c+1 $n=1 ;_IEAction($oIE, "refresh") ;MsgBox($MB_SYSTEMMODAL, "", $n) Sleep(60000) Captar() ElseIf (Not $venda=0) And $n=1 Then ;MsgBox($MB_SYSTEMMODAL, "", "Esperando próxima rodada") $n=1 ;MsgBox($MB_SYSTEMMODAL, "", $n) ;_IEAction($oIE, "refresh") Sleep(60000) Captar() ElseIf (Not $venda=0) And $n=1 Then ;MsgBox($MB_SYSTEMMODAL, "", "Esperando próxima rodada") $n=1 ;MsgBox($MB_SYSTEMMODAL, "", $n) ;_IEAction($oIE, "refresh") Sleep(60000) Captar() Else ;MsgBox("", "", "ESPERE") $n=0 Sleep(1000) ;_IEAction($oIE, "refresh") Local $sText = _IEBodyReadText($oIE) $result = _StringBetween ( $sText , 'PUTEUR/USD on Binary-signal.com', 'sinal está PRONTA') Captar() EndIf EndFunc  
    • griefman
      By griefman
      Hi everyone,
      i am writing to you after a very long struggle i had while trying to figure out how to send a simple click inside a virtual machine running in vmware workstation 14.
      i have an autoit script running on my host machine watching for the UAC prompt to be displayed in a running vm. Both the host and the guest OS are Windows 10. This script worked perfectly with virtual box. It recognized the UAC prompt and clicked inside and the UAC was accepted. Since i switched to VMware Workstation 14, the script no longer clicks inside the VM successfully. It acts as if it clicks, but it doesn't. 
      I tried sending key combinations instead of a click, so that the VM can grab the input, but it also did not work. Every attempt that i made to send clicks or keys from the host inside the VM did not work. I tried using:
      MouseClick
      ControlClick
      MouseMove
      _WinAPI_Mouse_Event
      _WinAPI_Keybd_Event
       
      I also noticed that while the cursor moves to the target which has to be cilcked when my vmware worstation window is not focused, it even doesn't do that when i WinActivate the vmware workstation window first.
       
      Did anyone experience such an issue, or maybe could give me a hint, what else i could use to send a key combination or a mouse click in a vmware workstation 14 pro guest window?
       
      here is my code, which works with virtualbox:
       
      #AutoIt3Wrapper_Icon=".\uac.ico" #include <ImageSearchSubrogated.au3> FileInstall(".\ImageSearchDLL.dll", ".\ImageSearchDLL.dll", 0) FileInstall(".\UAC_ginloSetup.bmp", ".\UAC_ginloSetup.bmp", 0) FileInstall(".\UAC_Yes.bmp", ".\UAC_Yes.bmp", 0) ; set global variables for the coordinates, which should be delivered global $x1 = 0, $y1 = 0 global $x2 = 0, $y2 = 0 global $counter1 = 0 global $counter2 = 0 global $sleep = 10000 global $smallSleep = 5000 ; execute the script in a loop, so that it will hopefully recover from some unexpected errors While $counter1 < 1 checkForImage() WEnd #cs ------------ Functions #ce ------------ Func checkForImage() While $counter2 < 1 ; search for the UAC in the entire screen - 2 screens supported local $searchUac = _ImageSearchArea('UAC_ginloSetup.bmp', 1, -2568, -8, 5136, 1440, $x1, $y1, 0) If $searchUac = 1 Then ; if the UAC was found search for the Yes button in a an area 200 x 200 from the middle of the found UAC image local $searchYes = _ImageSearchArea('UAC_Yes.bmp', 1, $x1, $y1, $x1 + 200, $y1 + 200, $x2, $y2, 0) If $searchYes = 1 Then ; if the Yes button was found click it and pause the script for $sleep seconds MouseClick("left", $x2, $y2, 1,0) Sleep($sleep) Else ; if the Yes button was not found retry from the beginning in $smallSleep seconds MsgBox(0, "UAC found error", "UAC was found but the 'Yes' button was not found. Script will retry in " & $smallSleep & " seconds.", $smallSleep) EndIf ; another way to accept the UAC - via shortcut ;Send("{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}") ;Send("!y") Else ; if UAC was not found try again in $sleep seconds Sleep($sleep) EndIf WEnd ; if some error occured which expired the loop, pause the script for $sleep seconds MsgBox(0, "Error", "Some Error expired the timer and the script could not recover. The script will restart in " & $sleep & " seconds.", $sleep) EndFunc  
    • AndyS19
      By AndyS19
      I want to copy just the selected text in an input control and put it to the clipboard, but GuiCtrlRead() always reads all of the text in the control.
      In this test code, when I highlight a  portion of the left control's text and press ^C, I want to copy just that text to the clipboard; but when I highlight a  portion of the right control's text and press ^C, I want to copy all of its text to the clipboard.
      #include <Debug.au3> _DebugSetup(@ScriptName & "_debug.txt", False, 2, "") _DebugOut("=============== " & @MON & "/" & @MDAY & "/" & @YEAR & " " & @HOUR & ":" & @MIN & ":" & @SEC & " ====================") #include <GUIConstants.au3> #include <WinAPI.au3> #include <Array.au3> Opt("GUICloseOnESC", 1) ; ESC closes GUI? (0 = no, 1 = yes) Opt("GUIOnEventMode", 1) ; Set OnEvent mode Opt('MustDeclareVars', 1) OnAutoItExitRegister("Event_GUIClose") Opt("GUIEventOptions", 1) ;0=default, 1=just notification, 2=GuiCtrlRead tab index Opt("WinTitleMatchMode", -2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase Global $hWnd_MainWin, $iID_Left, $iID_Right _Main() Func _Main() $hWnd_MainWin = GUICreate("test7", 200, 300) $iID_Left = GUICtrlCreateInput("AAA BBB CCC (get Selected text)", 10, 30, 200, 25) GUICtrlSetOnEvent($iID_Left, "handle_left_btn") $iID_Right = GUICtrlCreateInput("DDD EEE FFF (get All text)", 10, 60, 200, 25) GUICtrlSetOnEvent($iID_Right, "handle_right_btn") Local $aAccelKeys[1][2] = [["^c", $hWnd_MainWin]] GUISetAccelerators($aAccelKeys) GUISetOnEvent($GUI_EVENT_CLOSE, 'Event_GUIClose') GUISetState() ; Make everything visible While 1 Sleep(127) WEnd EndFunc ;==>_Main Func handle_CTRL_C_key() ConsoleWrite("+++: handle_CTRL_C_key() entered" & @CRLF) Local $hCtrl, $ctrlID, $control_classname, $text $control_classname = ControlGetFocus($hWnd_MainWin) $hCtrl = ControlGetHandle($hWnd_MainWin, "", $control_classname) $ctrlID = _WinAPI_GetDlgCtrlID($hCtrl) If ($ctrlID = $iID_Left) Then $text = GUICtrlRead($ctrlID) ClipPut($text) ConsoleWrite("+++: Copied selected text:" & @CRLF & "==>" & $text & "<==" & @CRLF) ElseIf ($ctrlID = $iID_Right) Then $text = GUICtrlRead($ctrlID) ClipPut($text) ConsoleWrite("+++: Copied all text:" & @CRLF & "==>" & $text & "<==" & @CRLF) EndIf EndFunc ;==>handle_CTRL_C_key Func Event_GUIClose() Exit (99) EndFunc ;==>Event_GUIClose Func handle_left_btn() ConsoleWrite("+++: handle_left_btn() entered" & @CRLF) EndFunc ;==>handle_left_btn Func handle_right_btn() ConsoleWrite("+++: handle_right_btn() entered" & @CRLF) EndFunc ;==>handle_right_btn
       
×