Jump to content

Subclassing bug


FireFox
 Share

Recommended Posts

Hi,
 
I have an issue with the subclassing, it seems like the internal code is stuck in an infinite loop when the Exit statement is called.
 
I have removed as much lines of code as I could to make a reproducer but more the lines I removed and more the bug does not always occur.
 
So everything in the following script is needed for the bug to happend.
 
-If the GUI is deleted before the Exit statement there is no bug
 
Steps for the reproducer :
-Activate another window
-Click on the button "2"
-Click on the gui close button
 
And the script should be stuck (CPU to 25)

Here it is :

#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <GUIScrollBars.au3> ;_GUIScrollBars_ScrollWindow & Constants
#include <WinAPI.au3> ;_WinAPI_SetWindowLong
 
Opt("GUIOnEventMode", 1)
 
Global $__hMs_BtnProc = DllCallbackRegister("__BtnProc", "int", "hwnd;uint;wparam;lparam")
Global $__MSB_pBtnProc = DllCallbackGetPtr($__hMs_BtnProc), $__MSB_pPrevBtnProc = 0
 
Local $hGUI = GUICreate("MyGUI")
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
 
$btn1 = GUICtrlCreateButton("1", 250, 0, 80, 22)
$__MSB_pPrevBtnProc = _WinAPI_SetWindowLong(GUICtrlGetHandle($btn1), $GWL_WNDPROC, $__MSB_pBtnProc)
 
$btn2 = GUICtrlCreateButton("2", 250, 50, 80, 22)
_WinAPI_SetWindowLong(GUICtrlGetHandle($btn2), $GWL_WNDPROC, $__MSB_pBtnProc)
 
$hGUIChild = GUICreate("", 200, 200, 0, 0, $WS_CHILD, -1, $hGUI)
GUISetBkColor(0xFF0000)
 
GUISetState(@SW_SHOWNOACTIVATE, $hGUIChild)
GUISetState(@SW_SHOW, $hGUI)
 
While 1
    Sleep(10)
WEnd
 
Func _Exit()
    ;GUIDelete($hGUI)
    Exit
EndFunc   ;==>_Exit
 
Func __BtnProc($hWnd, $uMsg, $wParam, $lParam)
    Switch $uMsg
        Case $WM_LBUTTONDOWN
            _GUIScrollBars_ScrollWindow($hGUIChild, 0, -20)
    EndSwitch
 
    Return _WinAPI_CallWindowProc($__MSB_pPrevBtnProc, $hWnd, $uMsg, $wParam, $lParam)
EndFunc   ;==>__BtnProc

_

Also, please have a look to >this post. The issue is showed only by dragging a column header which is better for debuging.

Br, FireFox.

Edited by FireFox
Link to comment
Share on other sites

Allways free the DLLCallBack.

Func _Exit()
    DllCallbackFree($__hMs_BtnProc)
    Exit
EndFunc   ;==>_Exit

Edit: Sometimes works, sometimes not :(

No idea

Edited by funkey

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

To be honest, I didn't gave it a deep look, and to be more honest, I didn't noticed any bug, but I guess you may like to give it a try as well:

#include <WindowsConstants.au3>

Global $hCallback = DllCallbackRegister("SubclassProc", "LRESULT", "HWND;UINT;WPARAM;LPARAM;UINT_PTR;DWORD_PTR")

GUICreate("Subclassing", 640, 480)

Global $btn1 = GUICtrlCreateButton("Button", 25, 25, 100, 25)
SetWindowSubclass(GUICtrlGetHandle($btn1), $hCallback, $btn1, 0)

Global $btn2 = GUICtrlCreateButton("Button", 25, 75, 100, 25)
SetWindowSubclass(GUICtrlGetHandle($btn2), $hCallback, $btn2, 0)

GUISetState()

Do
Until (GUIGetMsg() = -3)

Func SubclassProc($hWnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
    Switch ($uMsg)
        Case $WM_LBUTTONDOWN
            ConsoleWrite("Control id: " & $uIdSubclass & @CRLF)
            ConsoleWrite("Message Id: " & "WM_LBUTTONDOWN" & @CRLF)

        Case $WM_LBUTTONUP
            ConsoleWrite("Control id: " & $uIdSubclass & @CRLF)
            ConsoleWrite("Message Id: " & "WM_LBUTTONUP" & @CRLF)

    EndSwitch

    Return DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
EndFunc

Func SetWindowSubclass($hWnd, ByRef $pfnSubclass, $uIdSubclass, $dwRefData)
    Return DllCall("comctl32.dll", "BOOL", "SetWindowSubclass", _
            "HWND", $hWnd, _
            "ptr", DllCallbackGetPtr($pfnSubclass), _
            "UINT_PTR", $uIdSubclass, _
            "DWORD_PTR", $dwRefData)[0]
EndFunc

Func DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
    Return DllCall("comctl32.dll", "LRESULT", "DefSubclassProc", _
            "HWND", $hWnd, _
            "UINT", $uMsg, _
            "WPARAM", $wParam, _
            "LPARAM", $lParam)[0]
EndFunc
Link to comment
Share on other sites

  • 3 weeks later...

Try this (for 3.3.10 only):

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <HeaderConstants.au3>
#include <WinAPI.au3>

; The 0-based column to be disabled
Global $iFix_Col
Global $hOld_WndProc
; Get new WndProc hamdle and pointer
Global $hNew_WndProc = DllCallbackRegister("_New_LVHdr_Proc", "lresult", "hwnd;uint;wparam;lparam")
Global $pNew_WndProc = DllCallbackGetPtr($hNew_WndProc)
; To save old WndProc handle
Global $hOld_WndProc

_Main()

Func _Main()
    Local Const $hGUI = GUICreate("ListView Fix Column Width", 400, 300)
    
    Local Const $cListView = GUICtrlCreateListView("Column 0|Column 1|Column 2|Column 3", 10, 10, 380, 220)
    GUICtrlCreateListViewItem("0|1|2|3", $cListView)

    Global $hLVHdr = _GUICtrlListView_GetHeader($cListView)
    
    $cButton = GUICtrlCreateButton("Test", 10, 250, 80, 30)

    GUISetState()

    ; Prevent resizing of column 1
    $iFix_Col = 1

    ; Prevent drag resize
    GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")

    ; SubClass LV Header
    $hOld_WndProc = _WinAPI_SetWindowLong($hLVHdr, $GWL_WNDPROC, $pNew_WndProc)
    ConsoleWrite("Old proc: 0x" & Hex($hOld_WndProc, 8) & @CRLF)

    ; Loop until user exits
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                Exit
            Case $cButton
                ConsoleWrite("Pressed" & @CRLF)
        EndSwitch
    WEnd

    GUIDelete($hGUI)
EndFunc   ;==>_Main

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

    ; Get details of message
    Local $tNMHEADER = DllStructCreate($tagNMHEADER, $lParam)
    ; Look for header resize code
    $iCode = DllStructGetData($tNMHEADER, "Code")
    Switch $iCode
        Case $HDN_BEGINTRACKW
            ; Now get column being resized
            Local $iCol = DllStructGetData($tNMHEADER, "Item")
            If $iCol = $iFix_Col Then
                ; Prevent resizing
                Return True
            Else
                ; Allow resizing
                Return False
            EndIf
    EndSwitch

EndFunc

Func _New_LVHdr_Proc($hWnd, $iMsg, $wParam, $lParam)

    Switch $iMsg
        Case $WM_SETCURSOR
            Return TRUE
    EndSwitch

    ; Now call previous WndProc and complete the chain
    ;Return _WinAPI_CallWindowProc($hOld_WndProc, $hWnd, $iMsg, $wParam, $lParam)
    Return CallWindowProc($hOld_WndProc, $hWnd, $iMsg, $wParam, $lParam)

EndFunc   ;==>_No_LVHdr_Resize

Func CallWindowProc($lpPrevWndFunc, $hWnd, $Msg, $wParam, $lParam)
  Return DllCall("user32.dll", "lresult", "CallWindowProc", "ptr", $lpPrevWndFunc, "hwnd", $hWnd, "uint", $Msg, "wparam", $wParam, "lparam", $lParam)[0]
EndFunc
Nice example Melba23.

I have not tested the other example by FireFox. I have tried, but the errors seem to be pretty random, and it makes it hard to draw any conclusions. Maybe I'm not testing properly. FireFox, can you do a test?

Edited by LarsJ
Link to comment
Share on other sites

LarsJ,

The bug seems to be fixed, so it's directly related to the _WinAPI_CallWindowProc function.

If the DllCall result is not directly returned there's the issue, it may come from the variable declaration.

I'll make a track ticket.

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...