Jump to content

Recommended Posts

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites

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
Link to post
Share on other sites

@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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites
Link to post
Share on other sites

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
Link to post
Share on other sites

@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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites
Link to post
Share on other sites

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
Link to post
Share on other sites
Link to post
Share on other sites

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
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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Bhooshan
      I need to mute an ongoing call on Microsoft teams without activating the window. Teams allows us to mute using shortcut key Ctrl+Shift+m but only when the window is active.
      # Used set option as ongoing call can be with any person which leads to change in Title Name.
      AutoItSetOption ( "WinTitleMatchMode", 2 ) 
      # I am not clear with the control ID which will be good to use here and also the key combination of ^M       
      ControlSend ( "Microsoft Teams", "", "[CLASS:Intermediate D3D Window; INSTANCE:1]", "{ctrl down}")
       
      Can anyone help...!!! 
       

    • By Htps
      1. How do I make a multiple minimized windows at once believe I am holding down a key for like 5 seconds?
      I know I can send minimized windows a key press with ControlSend.
      What hat would be the way to simulate a 'humanly' held down key to a few minimized windows? 
       
      2. How come: if I compare a handle's hexa value and the actual handler, I get false
      For example: when the Notepad's handler value is 0x00000000000CFFFF, I always get the message box.
       
      if(NOT(0x00000000000C0664 == WinGetHandle("Untitled - Notepad"))) Then MsgBox(0,"swi","0x00000000000CFFFF" & @CRLF & "lmao" & @CRLF & WinGetHandle("Untitled - Notepad")) EndIf  
      Why does that happen? also I can't use hexadecimal value as a handler when I use the ControlSend function.
    • 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}"))  
    • 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
    • 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
×
×
  • Create New...