sudeepjd Posted October 25, 2020 Posted October 25, 2020 I am building an application which needs a child panel in the GUI Control that needs to be scrolled as it contains controls that extend beyond the panel height. But I also need to have the users to be able to Tab through those controls. I don't seem to be able to to both working together. The Tabstops can be allowed on children by using $WS_EX_CONTROLPARENT and the Scrollbar creation using the GUIScrollBar.au3. If I set the $WS_EX_CONTROLPARENT it drags the entire child and does not allow the scroll, but if I remove it, the Scroll works but the tabstops don't. Please see the below sample application that can help reproduce this problem. expandcollapse popup#include <GUIConstants.au3> #include <GUIScrollbars.au3> #include <WindowsConstants.au3> Opt("GUIOnEventMode", 1) ; Change to OnEvent mode Global $width=500, $height=500, $titel="Tabtest in Childwindow" ; create the parentwindow $mainwindow = GUICreate($titel, $width, $height, -1, -1) GUISetBkColor(0x00ffff) ; show the parentwindow GUISetState(@SW_SHOW,$mainwindow) ; check on screen sleep(1000) ; create the childwindow with the scrollbars active ->TABSTOPS Dont work $childwindo1 = GUICreate("child", 220,$height, 10 ,0,$WS_CHILD, -1 ,$mainwindow) _GUIScrollBars_Init($childwindo1, 100, 100) GUISetBkColor(0xff0000, $childwindo1) GUISetState(@SW_SHOW, $childwindo1) $input_1 = GUICtrlCreateInput("Scroll Works",10,10) $input_2 = GUICtrlCreateInput("Tab Does Not",10,40) ; create the childwindow with the scrollbars active ->TABSTOPS Work, Scroll does not because window moves $childwindo2 = GUICreate("child", 220, $height, 240 ,0,$WS_CHILD, $WS_EX_CONTROLPARENT ,$mainwindow) _GUIScrollBars_Init($childwindo2, 100, 100) GUISetBkColor(0xff0000, $childwindo2) GUISetState(@SW_SHOW, $childwindo2) $input_3 = GUICtrlCreateInput("Tab Works",10,10) $input_4 = GUICtrlCreateInput("Scroll Does Not",10,40) GUIRegisterMsg($WM_VSCROLL, "WM_VSCROLL") ; register close GUISetOnEvent($GUI_EVENT_CLOSE, "close_it",$mainwindow) ;loop While 1 Sleep(100) ; Idle around WEnd Func close_it() ; exit application GUIDelete($mainwindow) exit EndFunc $childwindo = GUICreate("child",$width,$height,0,0,$WS_CHILD,-1,$mainwindow) GUISetBkColor(0xff0000) GUISetState(@SW_SHOW,$childwindo) Func WM_VSCROLL($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Local $iScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $iCharY, $iPosY Local $iMin, $iMax, $iPage, $iPos, $iTrackPos For $x = 0 To UBound($__g_aSB_WindowInfo) - 1 If $__g_aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $iCharY = $__g_aSB_WindowInfo[$iIndex][3] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 ; Get all the vertial scroll bar information Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT) $iMin = DllStructGetData($tSCROLLINFO, "nMin") $iMax = DllStructGetData($tSCROLLINFO, "nMax") $iPage = DllStructGetData($tSCROLLINFO, "nPage") ; Save the position for comparison later on $iPosY = DllStructGetData($tSCROLLINFO, "nPos") $iPos = $iPosY $iTrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $iScrollCode Case $SB_TOP ; user clicked the HOME keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMin) Case $SB_BOTTOM ; user clicked the END keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMax) Case $SB_LINEUP ; user clicked the top arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos - 1) Case $SB_LINEDOWN ; user clicked the bottom arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos + 1) Case $SB_PAGEUP ; user clicked the scroll bar shaft above the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos - $iPage) Case $SB_PAGEDOWN ; user clicked the scroll bar shaft below the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos + $iPage) Case $SB_THUMBTRACK ; user dragged the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iTrackPos) EndSwitch ; // Set the position and then retrieve it. Due to adjustments ; // by Windows it may not be the same as the value set. DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) ;// If the position has changed, scroll the window and update it $iPos = DllStructGetData($tSCROLLINFO, "nPos") If ($iPos <> $iPosY) Then _GUIScrollBars_ScrollWindow($hWnd, 0, $iCharY * ($iPosY - $iPos)) $iPosY = $iPos EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_VSCROLL Any help to get both working together is appreciated. Thanks, Sudeep.
Moderators Melba23 Posted October 25, 2020 Moderators Posted October 25, 2020 sudeepjd, This is a known problem within AutoIt - I ran into the same problem with my GUIFrame UDF. As you can read by following the various links there is not a lot to be done about it I am afraid. M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
sudeepjd Posted October 25, 2020 Author Posted October 25, 2020 (edited) Thanks Melba for your reply.. Appreciate it. If it is a known problem, then I cannot solve out of the box. I had to work around it.. What I did was to add in a {TAB} and +{TAB} Hotkey and wrote out a function to manually tab into the controls. This seems to solve my problem of scrolling and tabbing at the same time. Here is my pseudo fix, if anyone comes upon the same problem. expandcollapse popup#include <GUIConstants.au3> #include <GUIScrollbars.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> Opt("GUIOnEventMode", 1) ; Change to OnEvent mode HotKeySet("{TAB}", "tabFunc") ;<-- Hotkey for tabbing forward HotKeySet("+{TAB}", "tabFunc") ;<--Hotkey for tabbing backwards Global $width=500, $height=500, $titel="Tabtest in Childwindow" ; create the parentwindow $mainwindow = GUICreate($titel, $width, $height, -1, -1) GUISetBkColor(0x00ffff) ; show the parentwindow GUISetState(@SW_SHOW, $mainwindow) ; check on screen Sleep(1000) $input_1 = GUICtrlCreateInput("Outside Input", 10, 10, 100, 20) ; create the childwindow with the scrollbars active ->TABSTOPS Dont work $childwindo1 = GUICreate("child", 220,$height-50, 10 , 50, $WS_CHILD, -1 ,$mainwindow) _GUIScrollBars_Init($childwindo1, 100, 100) GUISetBkColor(0xff0000, $childwindo1) GUISetState(@SW_SHOW, $childwindo1) $input_2 = GUICtrlCreateInput("Scroll Works",10,10) $input_3 = GUICtrlCreateInput("Tab Does Not without tabFunc",10,40) ; create the childwindow with the scrollbars active ->TABSTOPS Work, Scroll does not because window moves $childwindo2 = GUICreate("child", 220, $height, 240 ,0,$WS_CHILD, $WS_EX_CONTROLPARENT ,$mainwindow) _GUIScrollBars_Init($childwindo2, 100, 100) GUISetBkColor(0xff0000, $childwindo2) GUISetState(@SW_SHOW, $childwindo2) $input_4 = GUICtrlCreateInput("Tab Works",10,10) $input_5 = GUICtrlCreateInput("Scroll Does Not",10,40) GUIRegisterMsg($WM_VSCROLL, "WM_VSCROLL") ; register close GUISetOnEvent($GUI_EVENT_CLOSE, "close_it",$mainwindow) ;loop While 1 Sleep(100) ; Idle around WEnd Func close_it() ; Exit application GUIDelete($mainwindow) Exit EndFunc $childwindo = GUICreate("child",$width,$height,0,0,$WS_CHILD,-1,$mainwindow) GUISetBkColor(0xff0000) GUISetState(@SW_SHOW,$childwindo) Func tabFunc() ;Get the Control in Focus $itemInFocusHndl = ControlGetHandle($mainwindow, "", ControlGetFocus($mainwindow)) $ctrlID = _WinAPI_GetWindowLong($itemInFocusHndl, $GWL_ID) ;Decide on which side to move Switch @HotKeyPressed Case "{TAB}" $ctrlID = $ctrlID+1 While _WinAPI_GetClassName(GUICtrlGetHandle($ctrlID)) = "Static" $ctrlID = $ctrlID+1 Wend Case "+{TAB}" $ctrlID = $ctrlID-1 While _WinAPI_GetClassName(GUICtrlGetHandle($ctrlID)) = "Static" $ctrlID = $ctrlID-1 Wend EndSwitch ;Shift the focus to the control accordingly. ControlFocus($mainwindow, "", GUICtrlGetHandle($ctrlID)) EndFunc Func WM_VSCROLL($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Local $iScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $iCharY, $iPosY Local $iMin, $iMax, $iPage, $iPos, $iTrackPos For $x = 0 To UBound($__g_aSB_WindowInfo) - 1 If $__g_aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $iCharY = $__g_aSB_WindowInfo[$iIndex][3] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 ; Get all the vertial scroll bar information Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT) $iMin = DllStructGetData($tSCROLLINFO, "nMin") $iMax = DllStructGetData($tSCROLLINFO, "nMax") $iPage = DllStructGetData($tSCROLLINFO, "nPage") ; Save the position for comparison later on $iPosY = DllStructGetData($tSCROLLINFO, "nPos") $iPos = $iPosY $iTrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $iScrollCode Case $SB_TOP ; user clicked the HOME keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMin) Case $SB_BOTTOM ; user clicked the END keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMax) Case $SB_LINEUP ; user clicked the top arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos - 1) Case $SB_LINEDOWN ; user clicked the bottom arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos + 1) Case $SB_PAGEUP ; user clicked the scroll bar shaft above the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos - $iPage) Case $SB_PAGEDOWN ; user clicked the scroll bar shaft below the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos + $iPage) Case $SB_THUMBTRACK ; user dragged the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iTrackPos) EndSwitch ; // Set the position and then retrieve it. Due to adjustments ; // by Windows it may not be the same as the value set. DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) ;// If the position has changed, scroll the window and update it $iPos = DllStructGetData($tSCROLLINFO, "nPos") If ($iPos <> $iPosY) Then _GUIScrollBars_ScrollWindow($hWnd, 0, $iCharY * ($iPosY - $iPos)) $iPosY = $iPos EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_VSCROLL Basically, pass the Tab through a functions that looks for the handle to the item in focus, gets the Control ID and increments or decrements it and then selects the next appropriate one. The only issue with doing this is that Tab and Shift+Tab is being captured by the application and any other windows are not able to use the Tab keys. Is there another way to capture the Tab and Shift+Tab without blocking the inputs to other windows applications? It tried GUIRegisterMsg($WM_KEYDOWN, 'WM_KEYDOWN') but it does not capture the TAB key needed for this, but seems to capture other keys. Func WM_KEYDOWN($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam ConsoleWrite(_WinAPI_GetKeyNameText($lParam) & @CRLF) Return $GUI_RUNDEFMSG EndFunc ;==>WM_KEYDOWN I can use _IsPressed() but I will have to call that in the While loop and it will eat up the CPU Cycles. @Melba23 Do you know any other methods I can check if the Tab and Shift+Tab get pressed? Thanks, Sudeep Edited October 25, 2020 by sudeepjd Updated to account for Static Controls
Nine Posted October 25, 2020 Posted October 25, 2020 (edited) You could use GUISetAccelerators function. Or you can register a LL KB callback function. Or you can use _WinAPI_SetWindowLong(GUICtrlGetHandle($idXXX), $GWL_WNDPROC, DllCallbackGetPtr($wProcHandle)) for each field that can be tabbed in. Edited October 25, 2020 by Nine sudeepjd 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
pixelsearch Posted October 25, 2020 Posted October 25, 2020 Hi sudeepjd I registered the WM_NCHITTEST message with interesting results, both child windows having the $WS_EX_CONTROLPARENT extended style. Now everything is scrollable & tabbable. You can even scroll the child Gui's (without moving them +++) by dragging the mouse anywhere inside the child GUI's, which could be interesting too. expandcollapse popup#include <GUIConstants.au3> #include <GUIScrollbars.au3> #include <WindowsConstants.au3> Opt("GUIOnEventMode", 1) ; Change to OnEvent mode Global $width=500, $height=500, $titel="Tabtest in Childwindow" ; create the parentwindow $mainwindow = GUICreate($titel, $width, $height, -1, -1) GUISetBkColor(0x00ffff) ; show the parentwindow GUISetState(@SW_SHOW,$mainwindow) ; check on screen ; sleep(1000) ; create the childwindow with the scrollbars active ->TABSTOPS Dont work $childwindo1 = GUICreate("child", 220, $height, 10, 10, $WS_CHILD, $WS_EX_CONTROLPARENT, $mainwindow) _GUIScrollBars_Init($childwindo1, 100, 100) GUISetBkColor(0xff0000, $childwindo1) GUISetState(@SW_SHOW, $childwindo1) $input_1 = GUICtrlCreateInput("Scroll Works",10,10) $input_2 = GUICtrlCreateInput("Tab too",10,40) $label_2a = GUICtrlCreateLabel("Low label 1", 10, $height + 100) ; create the childwindow with the scrollbars active ->TABSTOPS Work, Scroll does not because window moves $childwindo2 = GUICreate("child", 220, $height, 240, 10, $WS_CHILD, $WS_EX_CONTROLPARENT, $mainwindow) _GUIScrollBars_Init($childwindo2, 100, 100) GUISetBkColor(0xff0000, $childwindo2) GUISetState(@SW_SHOW, $childwindo2) $input_3 = GUICtrlCreateInput("Tab Works",10,10) $input_4 = GUICtrlCreateInput("Scroll too",10,40) $label_4a = GUICtrlCreateLabel("Low label 2", 10, $height + 100) GUIRegisterMsg($WM_VSCROLL, "WM_VSCROLL") GUIRegisterMsg($WM_NCHITTEST, "WM_NCHITTEST") ; register close GUISetOnEvent($GUI_EVENT_CLOSE, "close_it",$mainwindow) ;loop While 1 Sleep(100) ; Idle around WEnd ;=============================================== Func close_it() ; exit application GUIDelete($mainwindow) exit EndFunc ;=============================================== Func WM_VSCROLL($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Local $iScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $iCharY, $iPosY Local $iMin, $iMax, $iPage, $iPos, $iTrackPos For $x = 0 To UBound($__g_aSB_WindowInfo) - 1 If $__g_aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $iCharY = $__g_aSB_WindowInfo[$iIndex][3] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 ; Get all the vertial scroll bar information Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT) $iMin = DllStructGetData($tSCROLLINFO, "nMin") $iMax = DllStructGetData($tSCROLLINFO, "nMax") $iPage = DllStructGetData($tSCROLLINFO, "nPage") ; Save the position for comparison later on $iPosY = DllStructGetData($tSCROLLINFO, "nPos") $iPos = $iPosY $iTrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $iScrollCode Case $SB_TOP ; user clicked the HOME keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMin) Case $SB_BOTTOM ; user clicked the END keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMax) Case $SB_LINEUP ; user clicked the top arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos - 1) Case $SB_LINEDOWN ; user clicked the bottom arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos + 1) Case $SB_PAGEUP ; user clicked the scroll bar shaft above the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos - $iPage) Case $SB_PAGEDOWN ; user clicked the scroll bar shaft below the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos + $iPage) Case $SB_THUMBTRACK ; user dragged the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iTrackPos) EndSwitch ; // Set the position and then retrieve it. Due to adjustments ; // by Windows it may not be the same as the value set. DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) ;// If the position has changed, scroll the window and update it $iPos = DllStructGetData($tSCROLLINFO, "nPos") If ($iPos <> $iPosY) Then _GUIScrollBars_ScrollWindow($hWnd, 0, $iCharY * ($iPosY - $iPos)) $iPosY = $iPos EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_VSCROLL ;=============================================== Func WM_NCHITTEST($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam If $hWnd = $childwindo1 Or $hWnd = $childwindo2 Then Return $HTVSCROLL EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_NCHITTEST Musashi, Nine, mLipok and 1 other 2 2 "I think you are searching a bug where there is no bug... don't listen to bad advice."
sudeepjd Posted October 25, 2020 Author Posted October 25, 2020 @Nine Yes.. GUISetAccelerators can be used, and it needs to be linked to a dummy control, but should work. Too many controls to tab through for the _WinAPI_SetWindowLong, was thinking about it, but too much coding work, for a workaround :-) Thanks for the suggestions though. Much appreciated. @pixelsearch Your the man!!! Thank you... You are awesome... I never would have thought that NCHITTEST could be used for this. Thanks a ton.
Nine Posted October 25, 2020 Posted October 25, 2020 Nice finding @pixelsearch. Got to have to remember this one “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
pixelsearch Posted October 25, 2020 Posted October 25, 2020 Thanks to all of you. This forum is incredible because everybody likes to help. Sharing all together solutions to issues is what makes this forum special. argumentum 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
pixelsearch Posted October 27, 2020 Posted October 27, 2020 (edited) On 10/25/2020 at 3:20 PM, pixelsearch said: You can even scroll the child Gui's (without moving them +++) by dragging the mouse anywhere inside the child GUI's, which could be interesting too. I reworked a bit Func WM_NCHITTEST() so it should be more flexible. For example, maybe someone doesn't want the vertical scrolling to happen when you drag the mouse anywhere in the child windows. Also I posted all 26 WM_NCHITTEST() return values, sorted by code (then by value +++) in this link (test forum) . It's interesting to see in the console what's the return value when you move your mouse here & there, by uncommenting this line : ; ConsoleWrite($iRet) This amended version of Func WM_NCHITTEST() should be useful to rework in case the child windows are resizable, got a caption etc... The point is to first check WM_NCHITTEST() return value, only then decide what to do. WM_NCHITTEST is a really surprising message, very useful expandcollapse popup#include <GUIConstants.au3> #include <GUIScrollbars.au3> #include <WindowsConstants.au3> Opt("GUIOnEventMode", 1) ; Change to OnEvent mode Global $width=500, $height=500, $titel="Tabtest in Childwindow", $hDll = DllOpen("user32.dll") ; create the parentwindow $mainwindow = GUICreate($titel, $width, $height, -1, -1) GUISetBkColor(0x00ffff) ; show the parentwindow GUISetState(@SW_SHOW,$mainwindow) ; create the 1st childwindow with the scrollbars active $childwindo1 = GUICreate("child", 220, $height, 10, 10, $WS_CHILD, $WS_EX_CONTROLPARENT, $mainwindow) _GUIScrollBars_Init($childwindo1, 100, 100) GUISetBkColor(0xff0000, $childwindo1) GUISetState(@SW_SHOW, $childwindo1) $input_1 = GUICtrlCreateInput("Scroll Works",10,10) $input_2 = GUICtrlCreateInput("Tab too",10,40) $label_2a = GUICtrlCreateLabel("Low label 1", 10, $height + 100) ; create the 2nd childwindow with the scrollbars active $childwindo2 = GUICreate("child", 220, $height, 240, 10, $WS_CHILD, $WS_EX_CONTROLPARENT, $mainwindow) _GUIScrollBars_Init($childwindo2, 100, 100) GUISetBkColor(0xff0000, $childwindo2) GUISetState(@SW_SHOW, $childwindo2) $input_3 = GUICtrlCreateInput("Tab Works",10,10) $input_4 = GUICtrlCreateInput("Scroll too",10,40) $label_4a = GUICtrlCreateLabel("Low label 2", 10, $height + 100) GUIRegisterMsg($WM_VSCROLL, "WM_VSCROLL") GUIRegisterMsg($WM_NCHITTEST, "WM_NCHITTEST") ; register close GUISetOnEvent($GUI_EVENT_CLOSE, "close_it",$mainwindow) ;loop While 1 Sleep(100) ; Idle around WEnd ;=============================================== Func close_it() ; exit application GUIDelete($mainwindow) DllClose($hDll) exit EndFunc ;=============================================== Func WM_VSCROLL($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Local $iScrollCode = BitAND($wParam, 0x0000FFFF) Local $iIndex = -1, $iCharY, $iPosY Local $iMin, $iMax, $iPage, $iPos, $iTrackPos For $x = 0 To UBound($__g_aSB_WindowInfo) - 1 If $__g_aSB_WindowInfo[$x][0] = $hWnd Then $iIndex = $x $iCharY = $__g_aSB_WindowInfo[$iIndex][3] ExitLoop EndIf Next If $iIndex = -1 Then Return 0 ; Get all the vertial scroll bar information Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT) $iMin = DllStructGetData($tSCROLLINFO, "nMin") $iMax = DllStructGetData($tSCROLLINFO, "nMax") $iPage = DllStructGetData($tSCROLLINFO, "nPage") ; Save the position for comparison later on $iPosY = DllStructGetData($tSCROLLINFO, "nPos") $iPos = $iPosY $iTrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos") Switch $iScrollCode Case $SB_TOP ; user clicked the HOME keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMin) Case $SB_BOTTOM ; user clicked the END keyboard key DllStructSetData($tSCROLLINFO, "nPos", $iMax) Case $SB_LINEUP ; user clicked the top arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos - 1) Case $SB_LINEDOWN ; user clicked the bottom arrow DllStructSetData($tSCROLLINFO, "nPos", $iPos + 1) Case $SB_PAGEUP ; user clicked the scroll bar shaft above the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos - $iPage) Case $SB_PAGEDOWN ; user clicked the scroll bar shaft below the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iPos + $iPage) Case $SB_THUMBTRACK ; user dragged the scroll box DllStructSetData($tSCROLLINFO, "nPos", $iTrackPos) EndSwitch ; // Set the position and then retrieve it. Due to adjustments ; // by Windows it may not be the same as the value set. DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS) _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO) ;// If the position has changed, scroll the window and update it $iPos = DllStructGetData($tSCROLLINFO, "nPos") If ($iPos <> $iPosY) Then _GUIScrollBars_ScrollWindow($hWnd, 0, $iCharY * ($iPosY - $iPos)) $iPosY = $iPos EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_VSCROLL ;=============================================== Func WM_NCHITTEST($hWnd, $iMsg, $wParam, $lParam) ;~ If $hWnd = $childwindo1 Or $hWnd = $childwindo2 Then ;~ Return $HTVSCROLL ;~ EndIf If $hWnd = $childwindo1 Or $hWnd = $childwindo2 Then ; This works but opens & closes user32.dll plenty of times => commented. ; Local $iRet = _WinAPI_DefWindowProc($hWnd, $iMsg, $wParam, $lParam) ; Same as _WinAPI_DefWindowProc() in WinAPISysWin.au3 but uses $hDll Local $iRet = DllCall($hDll, "lresult", "DefWindowProc", "hwnd", $hWnd, _ "uint", $iMsg, "wparam", $wParam, "lparam", $lParam)[0] ; ConsoleWrite($iRet) Switch $iRet Case $HTVSCROLL Return $HTVSCROLL Case Else Return $HTCLIENT EndSwitch EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_NCHITTEST Edited October 27, 2020 by pixelsearch typo sudeepjd and dmob 2 "I think you are searching a bug where there is no bug... don't listen to bad advice."
Moderators Melba23 Posted October 29, 2020 Moderators Posted October 29, 2020 pixelsearch, A nice piece of detective work. Bravo! M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
pixelsearch Posted October 30, 2020 Posted October 30, 2020 @Melba23 : thanks for the kind words, much appreciated Could you please give us an advice concerning a frequent related question ? Topic DllCall, here is what we read in the help file : If a dll filename is given then the DLL is automatically loaded and then closed at the end of the call. If you want to manually control the loading and unloading of the DLL then you should use DllOpen() and DllClose() and use a handle instead of a filename in this function. It explains why I used "the handle way" in the precedent script : DllCall($hDll, ...) Instead of : _WinAPI_DefWindowProc(...) ; which means : DllCall("user32.dll", ...) I did it only because the WM_NCHITTEST() call is done dozen of times, avoiding a non-stop dll "loading-unloading" process. I don't do this in other scripts where DllCall is used much less often. Now the question : is it really important to "manually control the loading and unloading of the DLL" during DllCall ? Because if it is, then we should examinate each and every Include function, to determine if the use of a Dll handle is the "good" way, as soon as this function is called plenty of times in a script. While writing this, it makes me think at the built in FileWrite() function, with these words found in the help file : If a filename is given rather than a file handle, the file will be opened and closed during the function call. For parsing large text files this will be much slower than using filehandles. But what is expressly recommended for FileWrite (i.e "this will be much slower") isn't so clearly stipulated in the DllCall topic. Thanks. "I think you are searching a bug where there is no bug... don't listen to bad advice."
Nine Posted October 30, 2020 Posted October 30, 2020 The difference is really marginal : #include <Constants.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> $hGUI = GUICreate("") $hTimer = TimerInit() For $i = 1 to 1000 $iRet = _WinAPI_DefWindowProc($hGUI, $WM_USER, 0, 0) Next ConsoleWrite (TimerDiff($hTimer) & @CRLF) $hTimer = TimerInit() For $i = 1 to 1000 $iRet = DllCall("user32.dll", "lresult", "DefWindowProc", "hwnd", $hGUI, "uint", $WM_USER, "wparam", 0, "lparam", 0)[0] Next ConsoleWrite (TimerDiff($hTimer) & @CRLF) +>Setting Hotkeys...--> Press Ctrl+Alt+Break to Restart or Ctrl+BREAK to Stop. 15.7746044264245 11.7413117173742 +>08:34:19 AutoIt3.exe ended.rc:0 +>08:34:19 AutoIt3Wrapper Finished. >Exit code: 0 Time: 1.632 4ms difference between both over 1000 calls. Unless there is an extreme necessity of light speed, I never use that feature. It makes the script more readable using _WinAPI*. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
pixelsearch Posted October 30, 2020 Posted October 30, 2020 (edited) Hi Nine, Thanks for your test. My point was a bit different, opening user32.dll only once, then using its handle : #include <Constants.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> $hGUI = GUICreate("") $hTimer = TimerInit() For $i = 1 to 10000 $iRet = _WinAPI_DefWindowProc($hGUI, $WM_USER, 0, 0) Next ConsoleWrite (TimerDiff($hTimer) & @CRLF) $hDll = DllOpen("user32.dll") $hTimer = TimerInit() For $i = 1 to 10000 $iRet = DllCall($hDll, "lresult", "DefWindowProc", "hwnd", $hGUI, "uint", $WM_USER, "wparam", 0, "lparam", 0)[0] Next ConsoleWrite (TimerDiff($hTimer) & @CRLF) GUIDelete($hGUI) DllClose($hDll) But even like that, there shouldn't be much time difference between both ways, so I probably won't use the handle way anymore when using DllCall Edited October 30, 2020 by pixelsearch Modified script to open user.dll only before the 2nd timer "I think you are searching a bug where there is no bug... don't listen to bad advice."
Nine Posted October 30, 2020 Posted October 30, 2020 Ya, my mistake, read it a bit too fast I guess Results seem to be pretty much in the same proportion, tho... “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
pixelsearch Posted October 30, 2020 Posted October 30, 2020 7 minutes ago, Nine said: Results seem to be pretty much in the same proportion, tho... Maybe because I wrongly opened user.dll too early ? As it shouldn't be opened before the 1st timer, I'm gonna modify the last script and open it only before the 2nd timer, we'll see "I think you are searching a bug where there is no bug... don't listen to bad advice."
Moderators Melba23 Posted October 30, 2020 Moderators Posted October 30, 2020 pixelsearch, Quote Could you please give us an advice concerning a frequent related question ? is it really important to "manually control the loading and unloading of the DLL" during DllCall ? Here is my hobbyist understanding of the situation. DLLs are "loaded" as required but are not necessarily immediately "unloaded" once the call is over. They remain in memory with an internal counter value showing that the DLL is in use. If the same DLL is called by another process then the same code is used and the counter increased to show that there are now 2 processes using it. If one of these processes "closes" the DLL, then all that happens is that the counter is reduced and the code remains in memory as long as there is at least one process still using the code. This would imply that you should indeed open and close the DLL when using it, but with the more common DLLs there is a pretty good chance that the code is already in memory and so there is no penalty for not doing so. There is also the fact that Windows is very likely to do some caching if the same DLL is constantly used, so the DLL code may well be kept in memory for a while even with a zero count, but I am unsure whether this actually happens. The situation regarding file handles is not really analogous as there is no "loading" of the file into memory in the same manner - just the creation of an index in a "small" finite sized array of "open" filenames. I hope that helps. And if anyone wants to expand, or completely change, what I have written above please feel free to do so. M23 pixelsearch 1 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
Confuzzled Posted October 30, 2020 Posted October 30, 2020 (edited) Comment: 'System crash', 'stack overflow', 'unable to obtain handles', 'memory exhausted' error codes is what happens if you create new handles and never close them, especially in re-entrant loops. How do I know? Grins (or cringes) Wait till you try and debug DLLhell, where there are different versions of exactly the same named DLL scattered across your system, all with similar internal function names but different functionality, and the order in which they are encountered by your software determines how far your system remains stable before it crashes and burns. Yes, I'm looking at you Microsoft, Oracle, Nero, Java and Adobe. Hard and fast Rulez (from experience): If you open it, close it. If it is up, put it down when you flush. Keep subroutines and calls open for as short a time as possible. Be aware of local vs global variables. Don't be lazy with variable naming - 'temp' is often found to be a global variable. Read the doco. Test for return codes. Check for version levels during API calls. Always include a 'or else' clause. Make your error codes meaningful and easy to document. Declare your global variables at the top separately. Pseudocode is not wasted code. Planning is not an overhead. Use the right tool for the job. COBOL is not a good environment to write a keylogger package, and Excel is not a good covid data tracker! All developers speak profanity fluently. It is the first and most developed language universally. Getting your code to compile the first time is nearly as good as sex - nearly! Edited October 30, 2020 by Confuzzled argumentum 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now