Jump to content

Recommended Posts

Posted (edited)
#include-once ; #include <_GUIRegisterMsgTell.au3>
;~ #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7

Global Const $__g_sGUIRegisterMsgTell_VERSION = "0.0.0.2"
Global $__g_iGUIRegisterMsgDebugOn = 0


; #FUNCTION# ====================================================================================================================
; Name...........: _GUIRegisterMsgTell
; Description ...: A wrapper for GUIRegisterMsg that registers Windows messages, tracks their assigned functions,
;                  maintains a history of the last 3 assignments, and allows historical pruning.
; Syntax.........: _GUIRegisterMsgTell([$msgID = Default[, $function = Default[, $iPruneIndex = 0]]])
; Parameters ....: $msgID       - [optional] The Windows message ID to intercept.
;                                 If omitted operates in "Dump Mode".
;                  $function    - [optional] The name of the user-defined function to call, or the function itself.
;                                 If omitted, operates in "Retrieve Mode" (Returns current function).
;                                 If set to < -1 (e.g., -2, -3), operates in "Peek Mode" (Returns historical function natively).
;                                 If set to "-1", operates in "Restore Mode" (Reverts to previous function).
;                                 If set to "" (empty string), it explicitly unregisters the message ID.
;                  $iPruneIndex - [optional] Disables standard modes and enters "Prune Mode". Clears a specific history slot
;                                 (replaces with "") while leaving the rest of the chain/timeline intact.
;                                 1 = Clears the Previous (Prior) function slot.
;                                 2 = Clears the Oldest function slot.
; Return values .: Dump Mode ($msgID is a Keyword):
;                    Success - Returns the internal Map of registered messages. (@error = 0, @extended = 2)
;                  Retrieve Mode ($function is a Keyword):
;                    Success - Returns the currently active function name. (@error = 0, @extended = 0)
;                    Failure - Returns "" if the ID has never been touched. (@error = 0, @extended = 1)
;                  Peek Mode ($function < -1):
;                    Success - Returns the historical function name at that depth. (@error = 0, @extended = 0)
;                    Failure - Returns "" if that history depth doesn't exist. (@error = 0, @extended = 4)
;                  Restore Mode ($function = -1):
;                    Success - Reverts to the previous function and returns 1. (@error = 0, @extended = 0)
;                    Failure - Returns 0 if there is no history to restore. (@error = 0, @extended = 3)
;                  Prune Mode ($iPruneIndex > 0):
;                    Success - Returns 1 after replacing that historical tier with "". (@error = 0, @extended = 0)
;                    Failure - Returns 0 if the target history slot doesn't exist. (@error = 0, @extended = 5 or 6)
;                  Register Mode ($msgID and $function provided, $iPruneIndex = 0):
;                    Success - Returns 1 (Return value passed through from native GUIRegisterMsg).
;                    Failure - Returns 0 (Return value passed through from native GUIRegisterMsg).
; Author ........: argumentum ( blame me )
; Related .......: GUIRegisterMsg
; Link ..........: https://www.autoitscript.com/forum/topic/213746-_guiregistermsgtell-a-wrapper-udf-for-guiregistermsg/
; Examples ......: _GUIRegisterMsgTell($WM_COMMAND, "MY_WM_COMMAND") ; Register a specific function
;                  Local $sCurrentFunc = _GUIRegisterMsgTell($WM_COMMAND) ; Retrieve a specific message's function
;                  Local $mAllFuncs = _GUIRegisterMsgTell() ; return the tracking Map
; ===============================================================================================================================
Func _GUIRegisterMsgTell($msgID = Default, $function = Default, $iPruneIndex = 0)
    Local Static $mFuncs[]
    Local $sRestOfStack, $iPipePos, $aHistory, $sFuncName, $sKey = String($msgID)

    ; Dump Mode
    If IsKeyword($msgID) Then
        Return SetError(0, 2, $mFuncs)
    EndIf

    ; Prune Mode (Housekeeping for specific history depth)
    If $iPruneIndex > 0 Then
        If Not MapExists($mFuncs, $sKey) Then Return SetError(0, 5, 0)
        $aHistory = StringSplit($mFuncs[$sKey], "|")
        If ($iPruneIndex + 1) > $aHistory[0] Then Return SetError(0, 6, 0)
        Local $sNewStack = ""
        For $i = 1 To $aHistory[0]
            If $i = ($iPruneIndex + 1) Then
                $sNewStack &= "|" ; Leave the slot completely blank to preserve timeline integrity
            Else
                $sNewStack &= $aHistory[$i] & "|"
            EndIf
        Next
        $mFuncs[$sKey] = StringTrimRight($sNewStack, 1)
        Return SetError(0, 0, 1)
    EndIf

    ; Retrieve Mode
    If IsKeyword($function) Then
        If MapExists($mFuncs, $sKey) Then Return SetError(0, 0, StringSplit($mFuncs[$sKey], "|")[1])
        Return SetError(0, 1, "")
    EndIf

    ; Peek Mode (< -1)
    If (IsNumber($function) And $function < -1) Or StringRegExp(String($function), "^-[2-9]\d*$") Then
        If Not MapExists($mFuncs, $sKey) Or Not StringInStr($mFuncs[$sKey], "|") Then Return SetError(0, 4, "")
        $aHistory = StringSplit($mFuncs[$sKey], "|")
        Local $iTarget = Abs(Int($function)) ; -2 becomes 2, -3 becomes 3
        If $iTarget > $aHistory[0] Then Return SetError(0, 4, "") ; Slot depth doesn't exist
        Return SetError(0, 0, $aHistory[$iTarget])
    EndIf

    ; Restore Mode (-1)
    If $function = -1 Or $function = "-1" Then
        If Not MapExists($mFuncs, $sKey) Then Return SetError(0, 3, 0)
        Local $sStack = $mFuncs[$sKey] ; If we have history, shift it
        If StringInStr($sStack, "|") Then
            $sStack = StringMid($sStack, StringInStr($sStack, "|") + 1)
            $mFuncs[$sKey] = $sStack
            Local $sRestoredFunc = StringSplit($sStack, "|")[1]
            Return __GUIRegisterMsgDebug($msgID, $sRestoredFunc)
        Else ; No history? Just clear it
            $mFuncs[$sKey] = ""
            Return __GUIRegisterMsgDebug($msgID, "")
        EndIf
    EndIf

    ; Register Mode
    $sFuncName = (VarGetType($function) = "UserFunction" ? FuncName($function) : $function)
    If MapExists($mFuncs, $sKey) Then
        $aHistory = StringSplit($mFuncs[$sKey], "|")
        Local $sCurrent = $aHistory[1]
        If $sCurrent <> $sFuncName Then
            If $sFuncName == "" Then
                $iPipePos = StringInStr($mFuncs[$sKey], "|") ; Remove the active function. Do not push it to history.
                $sRestOfStack = ($iPipePos > 0 ? StringMid($mFuncs[$sKey], $iPipePos + 1) : "")
                If $sRestOfStack == "" Then
                    $mFuncs[$sKey] = "" ; Leave a footprint. Do not use MapRemove.
                Else
                    $mFuncs[$sKey] = "|" & $sRestOfStack ; Sync active slot as empty, retain older history
                EndIf
            Else
                If $sCurrent == "" Then ; Overwriting a vacant active slot
                    $iPipePos = StringInStr($mFuncs[$sKey], "|")
                    $sRestOfStack = ($iPipePos > 0 ? StringMid($mFuncs[$sKey], $iPipePos + 1) : "")
                    Local $sNextFunc = ($sRestOfStack <> "" ? StringSplit($sRestOfStack, "|")[1] : "")

                    If $sNextFunc = $sFuncName Then
                        $mFuncs[$sKey] = $sRestOfStack ; Collapse duplicate
                    Else
                        $mFuncs[$sKey] = $sFuncName & ($sRestOfStack <> "" ? "|" & $sRestOfStack : "")
                    EndIf
                Else ; push history down normally (Archive)
                    $mFuncs[$sKey] = $sFuncName & "|" & $mFuncs[$sKey]
                EndIf
            EndIf

            ; enforce the 3-tier history cap
            Local $aTemp = StringSplit($mFuncs[$sKey], "|")
            Local $iMax = ($aTemp[0] > 3 ? 3 : $aTemp[0])
            Local $sTmpStack = ""
            For $i = 1 To $iMax
                $sTmpStack &= $aTemp[$i] & "|"
            Next
            $mFuncs[$sKey] = StringTrimRight($sTmpStack, 1)
        EndIf
    Else
        If $sFuncName <> "" Then
            $mFuncs[$sKey] = $sFuncName
        EndIf
    EndIf

    Return __GUIRegisterMsgDebug($msgID, $function)
EndFunc   ;==>_GUIRegisterMsgTell


; #FUNCTION# ====================================================================================================================
; Name...........: _GUIRegisterMsgTell_Version
; Description ...: Returns the current version string of the UDF.
; Syntax.........: _GUIRegisterMsgTell_Version()
; Return values .: Success - Returns the version string.
; ===============================================================================================================================
Func _GUIRegisterMsgTell_Version()
    Return $__g_sGUIRegisterMsgTell_VERSION
EndFunc   ;==>_GUIRegisterMsgTell_Version


; #FUNCTION# ====================================================================================================================
; Name...........: _GUIRegisterMsgDebugOn
; Description ...: Enables or disables console debugging for the UDF.
; Syntax.........: _GUIRegisterMsgDebugOn([$iVal = Default])
; Parameters ....: $iVal - [optional] 1 to enable, 0 to disable. If Default, just returns current status.
; Return values .: Success - Returns the current debug status (1 or 0).
; ===============================================================================================================================
Func _GUIRegisterMsgDebugOn($iVal = Default)
    If Not IsKeyword($iVal) Then $__g_iGUIRegisterMsgDebugOn = Int($iVal)
    Return $__g_iGUIRegisterMsgDebugOn
EndFunc   ;==>_GUIRegisterMsgDebugOn


; #FUNCTION# ====================================================================================================================
; Name...........: _GUIRegisterMsgTell_Dump
; Description ...: Generates a status report of internal registrations and history, optionally printing to console.
; Syntax.........: _GUIRegisterMsgTell_Dump([$iConsoleWrite = True])
; Parameters ....: $iConsoleWrite - [optional] If True, prints the report to the console. Defaults to True.
; Return values .: Returns the formatted status string. Preserves original error/extended codes.
; ===============================================================================================================================
Func _GUIRegisterMsgTell_Dump($iConsoleWrite = True, $iErr = @error, $iExt = @extended)
    Local $mDump = _GUIRegisterMsgTell() ; Dump Mode returns the map
    Local $sStr, $aKeys = MapKeys($mDump)

    $sStr = @CRLF & "- ======================================================================" & @CRLF
    $sStr &= "-  _GUIRegisterMsgTell() - ACTIVE REGISTRATIONS & HISTORY" & @CRLF
    $sStr &= "- ======================================================================" & @CRLF

    If UBound($aKeys) = 0 Then
        $sStr &= "- No messages have been tracked yet." & @CRLF
        $sStr &= "- ======================================================================" & @CRLF & @CRLF
        If $iConsoleWrite Then ConsoleWrite($sStr)
        Return SetError($iErr, $iExt, $sStr)
    EndIf

    For $sKey In $aKeys
        Local $aHistory = StringSplit($mDump[$sKey], "|")
        $sStr &= "- Message ID [ " & $sKey & " ]" & @CRLF
        $sStr &= "-    ├── Active:   " & ($aHistory[1] = "" ? '("")' : $aHistory[1]) & @CRLF
        $sStr &= "-    ├── Previous: " & ($aHistory[0] >= 2 ? ($aHistory[2] = "" ? '("")' : $aHistory[2]) : "(None)") & @CRLF
        $sStr &= "-    └── Oldest:   " & ($aHistory[0] >= 3 ? ($aHistory[3] = "" ? '("")' : $aHistory[3]) : "(None)") & @CRLF
        $sStr &= "- ----------------------------------------------------------------------" & @CRLF
    Next
    $sStr &= "- ======================================================================" & @CRLF & @CRLF
    If $iConsoleWrite Then ConsoleWrite($sStr)
    Return SetError($iErr, $iExt, $sStr)
EndFunc   ;==>_GUIRegisterMsgTell_Dump


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIRegisterMsgDebug
; Description ...: Internal wrapper for GUIRegisterMsg that optionally writes register events to the console.
; Syntax.........: __GUIRegisterMsgDebug($msgID, $function)
; Parameters ....: $msgID   - The Windows message ID to intercept.
;                  $function - The function name or pointer to register.
; Return values .: Returns the success of the native GUIRegisterMsg function.
; ===============================================================================================================================
Func __GUIRegisterMsgDebug($msgID, $function)
    If $__g_iGUIRegisterMsgDebugOn Then ConsoleWrite('++ _GUIRegisterMsgDebug(' & $msgID & ', "' & (VarGetType($function) = "UserFunction" ? FuncName($function) : String($function)) & '")' & @CRLF)
    Return GUIRegisterMsg($msgID, $function)
EndFunc   ;==>__GUIRegisterMsgDebug

Am working on my code and, is the message ID registered prior to my script by another script/UDF ? 🤔

Using this UDF in your code will help us all have a way to know if that message was registered :)

Edit:
for example, something like this ?

...
#include <GUIDarkTheme.au3> ; https://www.autoitscript.com/forum/topic/213613-guidarktheme-udf/
...
Func _MsgGui_WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local $hWndFrom, $iCode, $tNMHDR;, $hWndListView
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $g_hWndListView
            Switch $iCode
                Case $NM_DBLCLK ; Sent by a list-view control when the user double-clicks an item with the main mouse button
                    AdlibRegister(ListView_Event_OnDBLCLK, 20)
            EndSwitch
    EndSwitch
    If _GUIRegisterMsgTell($WM_NOTIFY, -2) = "__GUIDarkTheme_WM_NOTIFY" Then Return __GUIDarkTheme_WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_MsgGui_WM_NOTIFY
...

 

Edited by argumentum
more

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

  • argumentum changed the title to _GUIRegisterMsgTell() - A wrapper UDF for GUIRegisterMsg
Posted

..ok. An example you can run.
We'll need a UDF.
Ok, here we have one for sliders:

#include-once ; #include <_ScrollUDF_WM_SCROLL.au3>
#include <_GUIRegisterMsgTell.au3> ; https://www.autoitscript.com/forum/topic/213746-_guiregistermsgtell-a-wrapper-udf-for-guiregistermsg/
#include <WinAPISysWin.au3>
#include <WinAPIDlg.au3>
#include <SendMessage.au3>
#include <WindowsNotifsConstants.au3>
#include <GUIConstantsEx.au3>

_GUIRegisterMsgTell($WM_HSCROLL, _ScrollUDF_WM_SCROLL)
_GUIRegisterMsgTell($WM_VSCROLL, _ScrollUDF_WM_SCROLL)

; GUIRegisterMsg($WM_HSCROLL, _ScrollUDF_WM_SCROLL)
; ..could just use it without the wrapper ( _GUIRegisterMsgTell.au3 )
; but this is in great part, a demo for the wrapper.
; Either way is a nice "add-on" if you use any slider(s) in your GUI with just an include  ;)

; #FUNCTION# ====================================================================================================================
; Name...........: _ScrollUDF_WM_SCROLL
; Description ...: Intercepts slider (trackbar) scroll events and translates them into standard WM_COMMAND click notifications.
;                  This allows native AutoIt GUI loops to register real-time slider updates continuously while dragging.
; Syntax.........: _ScrollUDF_WM_SCROLL($hWnd, $iMsg, $wParam, $lParam)
; Parameters ....: $hWnd   - The window handle of the GUI.
;                  $iMsg   - The Windows message ID (typically $WM_HSCROLL or $WM_VSCROLL).
;                  $wParam - The scroll request and current position (Not used internally).
;                  $lParam - The handle of the control sending the scroll message.
; Return values .: Always returns $GUI_RUNDEFMSG to allow default Windows processing of the scroll event to continue.
; Author ........: argumentum ( blame me )
; Related .......: GUIRegisterMsg, GUICtrlCreateSlider
; Examples ......: GUIRegisterMsg($WM_HSCROLL, "_ScrollUDF_WM_SCROLL")
;                  GUIRegisterMsg($WM_VSCROLL, "_ScrollUDF_WM_SCROLL")
; ===============================================================================================================================
Func _ScrollUDF_WM_SCROLL($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam ; drop this in all your GUIs using : GUICtrlCreateSlider()
    If _WinAPI_GetClassName($lParam) = "msctls_trackbar32" Then ; get class matching slider
        Local $idCtrl = _WinAPI_GetDlgCtrlID($lParam) ; get AutoIt Control ID
        If $idCtrl > 0 Then _SendMessage($hWnd, $WM_COMMAND, $idCtrl, $lParam)
    EndIf  ;                      send a click notification: $idCtrl + ($STN_CLICKED = 0)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_ScrollUDF_WM_SCROLL

and the example that uses it:

#include <_GUIRegisterMsgTell.au3>
#include <_ScrollUDF_WM_SCROLL.au3> ; try with out this UDF to see what it does
#include <WindowsNotifsConstants.au3>
#include <GUIConstantsEx.au3>
#include <SliderConstants.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

#include <WinAPISysWin.au3>

Global $g_aShowMe[7]
Exit Example()
Func Example()
    Local $iFormW = 400, $iFormH = 120
    #Region ### START Koda GUI section ### Form=
    Local $sSliderName, $Form1 = GUICreate("Form1", $iFormW, $iFormH)
    GUISetBkColor(0xAABBCC)
    $g_aShowMe[0] = GUICtrlCreateLabel("Label1", 5, 5, $iFormW - 10, 25, BitOR($SS_CENTER, $SS_CENTERIMAGE), $WS_EX_STATICEDGE)
    $g_aShowMe[1] = GUICtrlCreateSlider(5, 35, 30, $iFormH - 45, BitOR($GUI_SS_DEFAULT_SLIDER, $TBS_VERT))
    $g_aShowMe[2] = GUICtrlCreateSlider(40, 35, $iFormW - 90, 30)
    $g_aShowMe[3] = GUICtrlCreateSlider(40, $iFormH - 45, $iFormW - 90, 35, BitOR($GUI_SS_DEFAULT_SLIDER, $TBS_TOP, $TBS_LEFT))
    $g_aShowMe[4] = GUICtrlCreateSlider($iFormW - 45, 35, 35, $iFormH - 45, BitOR($GUI_SS_DEFAULT_SLIDER, $TBS_VERT, $TBS_TOP, $TBS_LEFT))
    GUISetState(@SW_SHOW)
    #EndRegion ### END Koda GUI section ###

    _GUIRegisterMsgTell_Dump()

    _GUIRegisterMsgTell($WM_HSCROLL, _ShowMe_WM_SCROLL)
    _GUIRegisterMsgTell($WM_VSCROLL, _ShowMe_WM_SCROLL)

    _GUIRegisterMsgTell_Dump()

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                GUIDelete()
                Exit
            Case $g_aShowMe[1], $g_aShowMe[2], $g_aShowMe[3], $g_aShowMe[4]
                Switch $g_aShowMe[5]
                    Case $g_aShowMe[1]
                        $sSliderName = "LEFT"
                    Case $g_aShowMe[2]
                        $sSliderName = "TOP"
                    Case $g_aShowMe[3]
                        $sSliderName = "BOTTOM"
                    Case $g_aShowMe[4]
                        $sSliderName = "RIGHT"
                EndSwitch
                GUICtrlSetData($g_aShowMe[0], "Value of the slider on " & $sSliderName & _
                        " is " & GUICtrlRead($g_aShowMe[5]) & ($g_aShowMe[6] = "" ? "" : " ( via " & $g_aShowMe[6] & " )"))

        EndSwitch
    WEnd
EndFunc   ;==>Example

Func _ShowMe_WM_SCROLL($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    $g_aShowMe[5] = _WinAPI_GetDlgCtrlID($lParam) ; get AutoIt Control ID

    ; --- Hand-off to the Previous Handler if any ---
    Local $sPrevFunc = _GUIRegisterMsgTell($iMsg, -2)
    $g_aShowMe[6] = $sPrevFunc
    If $sPrevFunc <> "" Then Return Call($sPrevFunc, $hWnd, $iMsg, $wParam, $lParam)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_ShowMe_WM_SCROLL

image.png.21230103d0a905b150ca25dbe04d6568.png

..that creates the above image.
The UDF updates the state of the control no matter what changed it, while moving.
The example adds the label.

And there you have an example ( for the FAQ )

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

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
×
×
  • Create New...