Jump to content
Sign in to follow this  
UEZ

Unexpected behavior

Recommended Posts

UEZ

Hi,

I'm surprised about the behavior of controlsend to the edit control when using subclassing:

#include <constants.au3>
#include <windowsconstants.au3>
#include <gdiplus.au3>
#include <guiconstantsex.au3>


_GDIPlus_Startup()
Global Const $hGUI = GUICreate("Test", 602, 198, 192, 124)
Global Const $idEdit = GUICtrlCreateEdit("", 0, 0, 601, 145)
GUICtrlSetFont($idEdit, 10, 400, 0, "Lucida Console")
Global Const $hEdit = GUICtrlGetHandle($idEdit)
Global Const $idButton1 = GUICtrlCreateButton("Send 2 Edit", 8, 160, 75, 25)
Global Const $idButton2 = GUICtrlCreateButton("Exit", 520, 160, 75, 25)

Global Const $hBitmap = CreateCaretBitmap()
Global Const $iBlinkTime_save = DllCall('user32.dll', 'int', 'GetCaretBlinkTime')
Global Const $iBlinkTime = Int($iBlinkTime_save[0] * 0.9)

Global Const $hCaretProc = DllCallbackRegister("CaretProc", "ptr", "hwnd;uint;long;ptr")
Global Const $hOldCaretProc = _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, DllCallbackGetPtr($hCaretProc))

GUISetState(@SW_SHOW)

Global $hEditWndProc = DllCallbackRegister("EditWndProc", "long", "hwnd;uint;wparam;lparam")
Global $hOldEditProc = _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, DllCallbackGetPtr($hEditWndProc))


While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE, $idButton2
            DllCall('user32.dll', 'int', 'SetCaretBlinkTime', 'uint', $iBlinkTime_save[0])
            _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, $hOldCaretProc)
            DllCallbackFree($hCaretProc)
            _WinAPI_DeleteObject($hBitmap)
            _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, $hOldEditProc)
            DllCallbackFree($hEditWndProc)
            _GDIPlus_Shutdown()
            Exit
        Case $idButton1
            ControlFocus($hGUI, "", $idEdit)
            ControlSend($hGUI, "", $idEdit, "This is a TEST" & @LF)
    EndSwitch
WEnd

Func EditWndProc($hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_KEYDOWN
            ConsoleWrite("A key was pressed" & @LF)
    EndSwitch
    Return _WinAPI_CallWindowProc($hOldEditProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>EditWndProc

Func CaretProc($hWnd, $iMsg, $wParam, $lParam)
    Local $iRet = _WinAPI_CallWindowProc($hOldCaretProc, $hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_SETFOCUS
            DllCall('user32.dll', 'int', 'CreateCaret', 'hwnd', $hWnd, 'ptr', $hBitmap, 'int', 0, 'int', 0)
            DllCall('user32.dll', 'int', 'ShowCaret', 'hwnd', $hWnd)
            DllCall('user32.dll', 'int', 'SetCaretBlinkTime', 'uint', $iBlinkTime)
        Case $WM_KILLFOCUS
            DllCall('user32.dll', 'int', 'HideCaret', 'hwnd', $hWnd)
            DllCall('user32.dll', 'int', 'DestroyCaret')
            DllCall('user32.dll', 'int', 'SetCaretBlinkTime', 'uint', $iBlinkTime_save[0])
    EndSwitch
    Return $iRet
EndFunc

Func CreateCaretBitmap($iW = 9, $iH = 14, $iColor = 0xFFC0C0C0)
    Local Const $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iW, "int", $iH, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0)
    Local Const $hBitmap = $aResult[6]
    Local Const $hCtx = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local Const $hBrush = _GDIPlus_BrushCreateSolid($iColor)
    _GDIPlus_GraphicsFillRect($hCtx, 0, $iH - 3, $iW, $iH, $hBrush)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hCtx)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    Return $hHBitmap
EndFunc

When you press the "Send 2 Edit" the string "This is a TEST" & @LF will be sent to the edit control but reversed!

When you e.g. disable the 1st DllCallbackRegister() then it is working as expected.

Any explanation for this behavior?

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Zedna

Here is minimized reproducer code:

#include <constants.au3>
#include <windowsconstants.au3>
#include <guiconstantsex.au3>
#include <winapi.au3>

Global $hGUI = GUICreate("Test", 602, 198, 192, 124)
Global $idEdit = GUICtrlCreateEdit("", 0, 0, 601, 145)
Global $hEdit = GUICtrlGetHandle($idEdit)
Global $idButton1 = GUICtrlCreateButton("Send 2 Edit", 8, 160, 75, 25)
Global $idButton2 = GUICtrlCreateButton("Exit", 520, 160, 75, 25)
GUISetState(@SW_SHOW)

Global $hCaretProc = DllCallbackRegister("CaretProc", "lresult", "hwnd;uint;wparam;lparam")
Global $hOldCaretProc = _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, DllCallbackGetPtr($hCaretProc))

Global $hEditWndProc = DllCallbackRegister("EditWndProc", "lresult", "hwnd;uint;wparam;lparam")
Global $hOldEditProc = _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, DllCallbackGetPtr($hEditWndProc))

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE, $idButton2
            _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, $hOldEditProc)
            DllCallbackFree($hEditWndProc)
            _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, $hOldCaretProc)
            DllCallbackFree($hCaretProc)
            Exit
        Case $idButton1
            ControlFocus($hGUI, "", $idEdit)
            ControlSend($hGUI, "", $idEdit, "This is a TEST" & @LF)
    EndSwitch
WEnd

Func EditWndProc($hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_KEYDOWN
            ConsoleWrite("A key was pressed" & @LF)
    EndSwitch
    Return _WinAPI_CallWindowProc($hOldEditProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc

Func CaretProc($hWnd, $iMsg, $wParam, $lParam)
    Local $iRet = _WinAPI_CallWindowProc($hOldCaretProc, $hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_SETFOCUS
            ConsoleWrite("WM_SETFOCUS" & @LF)
        Case $WM_KILLFOCUS
            ConsoleWrite("WM_KILLFOCUS" & @LF)
    EndSwitch
    Return $iRet
EndFunc

EDIT: link to MSDN about Window procedures

http://msdn.microsoft.com/en-us/library/windows/desktop/ms632593%28v=vs.85%29.aspx

EDIT2: there was wrong order of DllCallbackFree at exit which resulted in crash at exit, fixed

EDIT3: fixed wrong return type and params in DllCallbackRegister() but problem remains

Edited by Zedna

Share this post


Link to post
Share on other sites
Yashied
UEZ

@Yashied: yes of course but I don't know why I had chosen this way and I discovered this unexpected behavior.

I just want to know what is wrong here.

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Yashied

Share this post


Link to post
Share on other sites
trancexx

Uhm... what?

Is there something wrong with DllCallbackRegister?


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites
Zedna

I think two Callbacks are not needed in this example, here it is optimized with one callback and the same functionality:

#include <constants.au3>
#include <windowsconstants.au3>
#include <guiconstantsex.au3>
#include <winapi.au3>

Global $hGUI = GUICreate("Test", 602, 198, 192, 124)
Global $idEdit = GUICtrlCreateEdit("", 0, 0, 601, 145)
Global $hEdit = GUICtrlGetHandle($idEdit)
Global $idButton1 = GUICtrlCreateButton("Send 2 Edit", 8, 160, 75, 25)
Global $idButton2 = GUICtrlCreateButton("Exit", 520, 160, 75, 25)
GUISetState(@SW_SHOW)

Global $hEditWndProc = DllCallbackRegister("EditWndProc", "lresult", "hwnd;uint;wparam;lparam")
Global $hOldEditProc = _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, DllCallbackGetPtr($hEditWndProc))

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE, $idButton2
            _WinAPI_SetWindowLong($hEdit, $GWL_WNDPROC, $hOldEditProc)
            DllCallbackFree($hEditWndProc)
            Exit
        Case $idButton1
            ControlFocus($hGUI, "", $idEdit)
            ControlSend($hGUI, "", $idEdit, "This is a TEST" & @LF)
    EndSwitch
WEnd

Func EditWndProc($hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_KEYDOWN
            ConsoleWrite("A key was pressed" & @LF)
    EndSwitch
    Local $iRet = _WinAPI_CallWindowProc($hOldEditProc, $hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_SETFOCUS
            ConsoleWrite("WM_SETFOCUS" & @LF)
        Case $WM_KILLFOCUS
            ConsoleWrite("WM_KILLFOCUS" & @LF)
    EndSwitch
    Return $iRet
EndFunc

Share this post


Link to post
Share on other sites
UEZ

@Zedna: you know where I had this problem and I update the code already. ;) But I just wanted to know why this happens. Is it a bug? Or just wrong usage of subclassing?

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Yashied

Share this post


Link to post
Share on other sites
trancexx

Show sensibly written example that doesn't work as expected.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites
Yashied

Example 1

Try to close the script from the tray.

;Author: rover 07/04/09
;MSDN reference:
;Shell_NotifyIcon Function
;http://msdn.microsoft.com/en-us/library/bb762159(VS.85).aspx

#include <Constants.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

Global $hProcNew = 0, $hProcOld = 0

Global Const $NIN_BALLOONSHOW = $WM_USER + 2
Global Const $NIN_BALLOONHIDE = $WM_USER + 3
Global Const $NIN_BALLOONUSERCLICK = $WM_USER + 5
Global Const $NIN_BALLOONTIMEOUT = $WM_USER + 4

TrayTip('Tip', 'This is a tray tip, click here.', 10, 1)

;get handle to AutoIt v3 hidden gui
$hAutoIt = WinGetHandle(AutoItWinGetTitle())
_SubclassWin($hAutoIt, $hProcNew, $hProcOld)

While 1
    Sleep(100)
WEnd

;NOTE: _WinAPI_SetWindowLong() in WinAPI.au3 consistently returns 'The specified procedure could not be found' error 127
;error is due to the call being SetWindowLong instead of SetWindowLongW,
;using SetWindowLongW the error message is 'The operation completed successfully.
Func _SubclassWin($hWnd, ByRef $hProcNew, ByRef $hProcOld)
    If $hProcNew <> 0 Or $hProcOld <> 0 Then Return SetError(1, 0, 0)

    $hProcNew = DllCallbackRegister("WM_TRAYNOTIFY", "int", "hwnd;uint;wparam;lparam")
    If @error Or $hProcNew = 0 Then Return SetError(2, 0, 0)

    $hProcOld = DllCall("User32.dll", "int", "SetWindowLongW", "hwnd", $hWnd, "int", $GWL_WNDPROC, "ptr", DllCallbackGetPtr($hProcNew))

    If @error Or $hProcOld[0] = 0 Then
        $hProcOld = 0
        Return SetError(3, 0, 0)
    EndIf

    $hProcOld = $hProcOld[0]
    Return SetError(0, 0, 1)
EndFunc   ;==>_SubclassWin

Func _RestoreWndProc($hWnd, ByRef $hProcNew, ByRef $hProcOld)
    If $hProcOld <> 0 Then _WinAPI_SetWindowLong($hWnd, $GWL_WNDPROC, $hProcOld)
    If $hProcNew <> 0 Then DllCallbackFree($hProcNew)

    $hProcNew = 0
    $hProcOld = 0
EndFunc   ;==>_RestoreWndProc

Func WM_TRAYNOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_USER + 1 ;AutoIt callback message value for tray icon (1025), can be retrieved with ReadProcessMemory and TRAYDATA struct
            Switch $lParam
                Case $NIN_BALLOONSHOW
                    ConsoleWrite('Balloon tip show.' & @CR)
                Case $NIN_BALLOONHIDE
                    ConsoleWrite('Balloon tip hide.' & @CR)
                Case $NIN_BALLOONUSERCLICK
                    ConsoleWrite('Balloon tip click.' & @CR)
                Case $NIN_BALLOONTIMEOUT
                    ConsoleWrite('Balloon tip close/timeout.' & @CR)
                    Exit
            EndSwitch
    EndSwitch

    ; pass the unhandled messages to default WindowProc
    Return _WinAPI_CallWindowProc($hProcOld, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>WM_TRAYNOTIFY

Func OnAutoItExit()
    _RestoreWndProc($hAutoIt, $hProcNew, $hProcOld)
EndFunc   ;==>OnAutoItExit

Example 2

Try to click on any item in the ListView when the window is inactive. Moreover, the script hangs after a few resizing of the column.

post.

Edited by Yashied

Share this post


Link to post
Share on other sites
trancexx

Does wraithdu's script from your other thread works for you?


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites
Yashied
trancexx

Bugs? Do you know what bug is?

Little more seriousness please.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites
Yashied

Share this post


Link to post
Share on other sites
trancexx

If you want me to ridicule you in public then please by all means continue.

You are not some random member here.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites
Zedna

Here is original UDF which was later incorporated (moved) into AutoIt sources:

Callback - no external library (dll) required - by piccaso

As far as I know some functionality is not possible by native AutoIt's implementation.

So you may try these examples with this old UDF.

Edited by Zedna

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  

  • Similar Content

    • SkysLastChance
      By SkysLastChance
      I must be missing something. I have had this problem multiple times. Why does F6 key not send 6 times?  
      Not working 
      ControlSend("[CLASS:#32770]", "", "", ("{F6 6}")) Working
      ControlSend("[CLASS:#32770]", "", "", ("{F6}")) ControlSend("[CLASS:#32770]", "", "", ("{F6}")) ControlSend("[CLASS:#32770]", "", "", ("{F6}")) ControlSend("[CLASS:#32770]", "", "", ("{F6}")) ControlSend("[CLASS:#32770]", "", "", ("{F6}")) ControlSend("[CLASS:#32770]", "", "", ("{F6}"))  
    • faustf
      By faustf
      hi guys
      i have a script  like this,  in windows 7 work perfect , in windows 10 not  work  , some one can explain me  why ??'
      #include <Array.au3> #include <MsgBoxConstants.au3> Global $aGPathFoto= FileReadToArray (@ScriptDir & "\TEMP\PathFoto.txt") Local $ctrl = 0 While 1 Local $hWnd = WinWait("[CLASS:#32770]", "", 10) If WinExists("[CLASS:#32770]") Then If $ctrl < 2 Then ControlSend($hWnd, "Choose File to Upload", "[CLASS:Edit; INSTANCE:1]", $aGPathFoto[0]&"{Enter}") Exit $ctrl += 1 Else ExitLoop EndIf EndIf WEnd $aGpathfoto = C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg
    • SkysLastChance
      By SkysLastChance
      Run("notepad.exe") GLOBAL $One = ('Line1' & _ 'Line2' & _ 'Line3' & _ 'Line4' & _ 'Line5') ClipPut($One) $Notepad = WinWait("[CLASS:Notepad]", "", 10) ControlSend("Untitled - Notepad", "", "", ("^v")) Instead of having this paste as Line1Line2Line3Line4Line5
      How can I make it paste it into notepad as (without double spacing.)
      Line1
      Line2
      Line3
      Line4
      Line5
    • lganta
      By lganta
      Hello!
      I created some scripts for a simple farming bot a few years ago and they rely on ControlSend.
      A year ago I quit that game and then installed Windows 10 (was using windows 7).
      Recently I installed that game and tried running them again and they seem to work (I have some messages displayed on the screen with the state of the bot ), except for the ControlSend part (which obviously is crucial).
      I started debugging the scripts so I created a basic script that makes use of Send. I tested this with Notepad in focus and works just fine and then with my game window in focus and it didn't work (it's supposed to write that text in an input box from the game).
      #include <MsgBoxConstants.au3> Sleep(3000); Send("some text"); MsgBox($MB_OK, "Notification", "Control was sent!");  
      Is there a way for the creators of the game to create some kind of security system against this? Or something happens because I updated to Windows 10?
      Is there something I'm missing?
      Thank you!
    • rawkhopper
      By rawkhopper
      Hello everyone,
      I have a script that is automating a piece of sluggish software.  I want to automate it with a bit of caution and I am not sure the best way to do it.  ControlSend works great most of the time.  If I have it enter 10 into a text box every once in a while it will enter 1 or 11 and then hit enter.
      To overcome this I use MouseClick to select the text I just entered and then see if it matches the string it was supposed to put in before it hits enter.  This seems to work but what I love about ControlSend is there is less room for human interaction messing it up.  
      Yes I could block input but I prefer not to do that (permissions).
      Is there a better way of doing this?  Any Help would be much appreciated.
      Anyway here is the snippet of the script in question:
      Func KVSend () WinActivate ( "Window", "" ) Local $WindowPos = WinGetPos("Window", "") If $kV < 30 Then WinActivate ( "Window", "" ) ControlClick ("Window", "", 1001) ;Click in Accel Voltage box Sleep (100) ControlSend ("Window", "", 1001, $kV) ; \ kV Sleep (100) MouseMove($WindowPos[0]+130,$WindowPos[1]+75,1) MouseClick($MOUSE_CLICK_LEFT) MouseClick($MOUSE_CLICK_LEFT) Send ("^c") Local $clip = ClipGet () If $clip = $kV Then ControlSend ("Window", "", 1001, "{ENTER}") ;Hit ENTER if value is correct Sleep (100) ControlClick ("Window", "", 1518) ;Lens Clear Else Send ("{BACKSPACE}") KVSend() ; If value is incorrect try again EndIf EndIf  
×