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 comment
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 comment
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 comment
Share on other sites

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

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

Link to comment
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 comment
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
 Share

×
×
  • Create New...