# Function Reference

# GUIRegisterMsg

Register a user defined function for a known Windows Message ID (WM_MSG).

GUIRegisterMsg ( msgID, "function" )

## Parameters

msgID | A Windows Message ID (see Appendix: Windows Message Codes).
function | The name of the user function to call when the message appears or an empty string "" to unregister a message.

## Return Value

Success: | 1.
Failure: | 0.

## Remarks

!!! To make the user function workable you have to define it with maximum 4 function parameters otherwise the function won't be called !!!
i.e:
Func MyUserFunction($hWndGUI, $iMsgID, $wParam, $lParam)
...
EndFunc
Or
Func MyUserFunction($hWndGUI, $iMsgID)
...
EndFunc
When the user function is called then these 4 parameters have the following values:

Position | Parameter | Meaning
--- | --- | ---
1 | hWnd | The Window handle of the GUI in which the message appears.
2 | iMsg | The Windows message ID.
3 | wParam | The first message parameter as hex value.
4 | lParam | The second message parameter as hex value.

Up to 256 user functions can be registered for message IDs.
By default the AutoIt internal message handler (if there is one for that message) will be actioned after the user function exits. The AutoIt internal message handler will also be actioned if the keyword Return is used with the constant $GUI_RUNDEFMSG (found in GUIConstantsEx.au3).
However, if Return is used with any other value (including no value at all) the AutoIt internal message handler will NOT be actioned (See WM_COMMAND in example).
So an early return from the user function requires Return $GUI_RUNDEFMSG if the AutoIt internal handler for that message is to run (see other examples).
Warning: blocking of running user functions which executes window messages with commands such as "MsgBox()" can lead to unexpected behavior, the return to the system should be as fast as possible !!!
Some controls consume internally specific Windows Message ID, so registering them will have no effect, e.g; WM_CHAR, WM_KEYDOWN, WM_KEYUP are consumed by an edit control.

## Related

GUICtrlGetHandle

## Example

    ; Create an ownerdrawn/colored button

    #include <ButtonConstants.au3>
    #include <FrameConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <MsgBoxConstants.au3>
    #include <StructureConstants.au3>
    #include <WinAPIConv.au3>
    #include <WinAPIDlg.au3>
    #include <WinAPIGdi.au3>
    #include <WinAPIGdiDC.au3>
    #include <WinAPIHObj.au3>
    #include <WinAPISysWin.au3>
    #include <WindowsNotifsConstants.au3>
    #include <WindowsStylesConstants.au3>
    #include <WindowsSysColorConstants.au3>

    Example()

    Func Example()
        Local $hGUI = GUICreate("Ownerdrawn Created Button", 300, 200)

        Local $idButton = GUICtrlCreateButton("", 90, 50, 120, 30)
        GUICtrlSetStyle($idButton, BitOR($WS_TABSTOP, $BS_NOTIFY, $BS_OWNERDRAW)) ; Set the ownerdrawn flag

        Local $idButton2 = GUICtrlCreateButton("Normal Button", 90, 110, 120, 30)

        GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

        ; WM_DRAWITEM has to be registered before showing GUI otherwise the initial drawing is not done
        GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

        GUISetState(@SW_SHOW, $hGUI)

        Local $iMsg
        While 1
            $iMsg = GUIGetMsg()

            Switch $iMsg
                Case $GUI_EVENT_CLOSE
                    ExitLoop

                Case $idButton
                    ; Normally should not fire because of our WM_COMMAND function
                    MsgBox($MB_SYSTEMMODAL, "Info", "Button pressed")

                Case $idButton2
                    ; Normally should not fire because of our WM_COMMAND function
                    MsgBox($MB_SYSTEMMODAL, "Info", "Button2 pressed")

            EndSwitch
        WEnd

        GUIDelete()
    EndFunc   ;==>Example

    ; React on a button click
    Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
        Local $nNotifyCode = _WinAPI_HiWord($wParam)
        Local $iId = _WinAPI_LoWord($wParam)
        Local $hCtrl = $lParam

        If $iId <> 2 And $nNotifyCode = 0 Then ; Check for IDCANCEL - 2
            ; Ownerdrawn buttons do not send a message when pressing ENTER
            ; So if IDOK - 1 comes up, now check for the control that has the current focus
            If $iId = 1 Then
                Local $hFocus = _WinAPI_GetFocus()
                Local $idControl = _WinAPI_GetDlgCtrlID($hFocus)
                PostButtonClick($hWnd, $idControl)
            Else
                MsgBox($MB_SYSTEMMODAL, "WM_COMMAND", "GUIHWnd" & @TAB & ":" & $hWnd & @CRLF & _
                        "MsgId" & @TAB & ":" & $iMsg & @CRLF & _
                        "wParam" & @TAB & ":" & $wParam & @CRLF & _
                        "lParam" & @TAB & ":" & $lParam & @CRLF & @CRLF & _
                        "WM_COMMAND - Infos:" & @CRLF & _
                        "-----------------------------" & @CRLF & _
                        "Code" & @TAB & ":" & $nNotifyCode & @CRLF & _
                        "CtrlId" & @TAB & ":" & $iId & @CRLF & _
                        "CtrlHWnd" & @TAB & ":" & $hCtrl)
            EndIf
            Return 0 ; Only workout clicking on the button
        EndIf

        ; On exit the default AutoIt3 internal message handler will run
        ; It will also run if "Return" returns $GUI_RUNDEFMSG as below
        ; Using "Return" with any other value (or no value at all) means the AutoIt handler
        ; will not run
        Return $GUI_RUNDEFMSG
    EndFunc   ;==>WM_COMMAND

    ; RePost a WM_COMMAND message to a ctrl in a gui window
    Func PostButtonClick($hWnd, $idControl)
        DllCall("user32.dll", "int", "PostMessage", _
                "hwnd", $hWnd, _
                "int", $WM_COMMAND, _
                "int", _WinAPI_LoWord($idControl), _
                "hwnd", GUICtrlGetHandle($idControl))
    EndFunc   ;==>PostButtonClick

    ; Draw the button
    Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam)
        #forceref $iMsg, $wParam, $lParam
        Local Const $tagDRAWITEMSTRUCT = "uint;uint;uint;uint;uint;hwnd;handle;long[4];ulong_ptr"
        Local $tDrawItem = DllStructCreate($tagDRAWITEMSTRUCT, $lParam)

        Local Const $ODT_BUTTON = 4

        Local $nCtlType = DllStructGetData($tDrawItem, 1)
        If $nCtlType = $ODT_BUTTON Then
            ; Local $idControl = DllStructGetData($tDrawItem, 2)
            Local $nItemState = DllStructGetData($tDrawItem, 5)
            Local $hCtrl = DllStructGetData($tDrawItem, 6)
            Local $hDC = DllStructGetData($tDrawItem, 7)
            Local $iLeft = DllStructGetData($tDrawItem, 8, 1)
            Local $iTop = DllStructGetData($tDrawItem, 8, 2)
            Local $iRight = DllStructGetData($tDrawItem, 8, 3)
            Local $iBottom = DllStructGetData($tDrawItem, 8, 4)
            Local $sText = "Ownerdrawn Button"
            Local $nTextColor = 0x5555DD
            Local $nBackColor = 0xFFEEDD
            DrawButton($hWnd, $hCtrl, $hDC, $iLeft, $iTop, $iRight, $iBottom, $nItemState, $sText, $nTextColor, $nBackColor)
            $tDrawItem = 0
            Return 1 ; The internal AutoIt message handler will not run
        EndIf

        $tDrawItem = 0
        Return $GUI_RUNDEFMSG ; Run the default AutoIt internal message handler
    EndFunc   ;==>WM_DRAWITEM

    ; The main drawing procedure
    Func DrawButton($hWnd, $hCtrl, $hDC, $iLeft, $iTop, $iRight, $iBottom, $nItemState, $sText, $nTextColor, $nBackColor)
        #forceref $hWnd

        Local Const $ODS_SELECTED = 0x0001
        Local Const $ODS_GRAYED = 0x0002
        Local Const $ODS_DISABLED = 0x0004
        Local Const $ODS_FOCUS = 0x0010

        Local $bFocused = BitAND($nItemState, $ODS_FOCUS)
        Local $bGrayed = BitAND($nItemState, BitOR($ODS_GRAYED, $ODS_DISABLED))
        Local $bSelected = BitAND($nItemState, $ODS_SELECTED)

        Local $tRECT = DllStructCreate($tagRECT)
        DllStructSetData($tRECT, 'Left', $iLeft)
        DllStructSetData($tRECT, 'Top', $iTop)
        DllStructSetData($tRECT, 'Right', $iRight)
        DllStructSetData($tRECT, 'Bottom', $iBottom)

        Local $nClrTxt = 0
        If $bGrayed Then
            $nClrTxt = _WinAPI_SetTextColor($hDC, _WinAPI_GetSysColor($COLOR_HIGHLIGHTTEXT))
        ElseIf $nTextColor = -1 Then
            $nClrTxt = _WinAPI_SetTextColor($hDC, _WinAPI_GetSysColor($COLOR_BTNTEXT))
        Else
            $nClrTxt = _WinAPI_SetTextColor($hDC, $nTextColor)
        EndIf

        Local $hBrush, $nClrSel
        If $nBackColor = -1 Then
            $hBrush = _WinAPI_GetSysColorBrush($COLOR_BTNFACE)
            $nClrSel = _WinAPI_GetSysColor($COLOR_BTNFACE)
        Else
            $hBrush = _WinAPI_CreateSolidBrush($nBackColor)
            $nClrSel = $nBackColor ;
        EndIf

        Local $nClrBk = _WinAPI_SetBkColor($hDC, $nClrSel)
        Local $hOldBrush = _WinAPI_SelectObject($hDC, $hBrush)

        Local $nTmpLeft = $iLeft
        Local $nTmpTop = $iTop
        Local $nTmpRight = $iRight
        Local $nTmpBottom = $iBottom

        If $bSelected Then
            InflateRect($nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, -1, -1)
            Local $hBrushSel = _WinAPI_CreateSolidBrush(_WinAPI_GetSysColor($COLOR_BTNSHADOW))
            FrameRect($hDC, $nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, $hBrushSel)
            _WinAPI_DeleteObject($hBrushSel)
        Else
            If $bFocused And Not $bSelected Then InflateRect($nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, -1, -1)
            DrawFrameControl($hDC, $nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, $DFC_BUTTON, $DFCS_BUTTONPUSH)
        EndIf

        $nTmpLeft = $iLeft
        $nTmpTop = $iTop
        $nTmpRight = $iRight
        $nTmpBottom = $iBottom

        If $bSelected Then
            InflateRect($nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, -2, -2)
        Else
            If $bFocused And Not $bSelected Then
                InflateRect($nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, -3, -3)
                $nTmpLeft -= 1
                $nTmpTop -= 1
            Else
                InflateRect($nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, -2, -2)
                $nTmpLeft -= 1
                $nTmpTop -= 1
            EndIf
        EndIf

        FillRect($hDC, $nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, $hBrush)

        If $bSelected Or $bGrayed Then
            $nTmpLeft = $nTmpLeft + 2
            $nTmpTop = $nTmpTop + 2
        EndIf

        Local $iFlags = BitOR($DT_NOCLIP, $DT_CENTER, $DT_VCENTER)

        If Not BitAND(_WinAPI_GetWindowLong($hCtrl, $GWL_STYLE), $BS_MULTILINE) Then $iFlags = BitOR($iFlags, $DT_SINGLELINE)

        DrawText($hDC, $sText, $nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, $iFlags)

        If $bGrayed Then
            $nTmpLeft = $iLeft
            $nTmpTop = $iTop
            $nTmpRight = $iRight
            $nTmpBottom = $iBottom

            $nTmpLeft -= 1

            $nClrTxt = _WinAPI_SetTextColor($hDC, _WinAPI_GetSysColor($COLOR_GRAYTEXT))
            DrawText($hDC, $sText, $nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, BitOR($DT_NOCLIP, $DT_CENTER, $DT_VCENTER, $DT_SINGLELINE))
        EndIf

        $nTmpLeft = $iLeft
        $nTmpTop = $iTop
        $nTmpRight = $iRight
        $nTmpBottom = $iBottom

        If $bFocused Then
            $hBrush = _WinAPI_CreateSolidBrush(0)
            FrameRect($hDC, $nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, $hBrush)

            $nTmpLeft = $iLeft
            $nTmpTop = $iTop
            $nTmpRight = $iRight
            $nTmpBottom = $iBottom

            InflateRect($nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom, -4, -4)
            DrawFocusRect($hDC, $nTmpLeft, $nTmpTop, $nTmpRight, $nTmpBottom)
        EndIf

        _WinAPI_SelectObject($hDC, $hOldBrush)
        _WinAPI_DeleteObject($hBrush)
        _WinAPI_SetTextColor($hDC, $nClrTxt)
        _WinAPI_SetBkColor($hDC, $nClrBk)

        Return 1 ; The internal AutoIt message handler will not run
    EndFunc   ;==>DrawButton

    Func DrawFrameControl($hDC, $iLeft, $iTop, $iRight, $iBottom, $iType, $iState)
        Local $tRECT = DllStructCreate($tagRECT)

        DllStructSetData($tRECT, 'Left', $iLeft)
        DllStructSetData($tRECT, 'Top', $iTop)
        DllStructSetData($tRECT, 'Right', $iRight)
        DllStructSetData($tRECT, 'Bottom', $iBottom)

        _WinAPI_DrawFrameControl($hDC, $tRECT, $iType, $iState)
    EndFunc   ;==>DrawFrameControl

    Func DrawFocusRect($hDC, $iLeft, $iTop, $iRight, $iBottom)
        Local $tRECT = DllStructCreate($tagRECT)

        DllStructSetData($tRECT, 'Left', $iLeft)
        DllStructSetData($tRECT, 'Top', $iTop)
        DllStructSetData($tRECT, 'Right', $iRight)
        DllStructSetData($tRECT, 'Bottom', $iBottom)

        _WinAPI_DrawFocusRect($hDC, $tRECT)
    EndFunc   ;==>DrawFocusRect

    Func DrawText($hDC, $sText, $iLeft, $iTop, $iRight, $iBottom, $iFlags)
        Local $tRECT = DllStructCreate($tagRECT)

        DllStructSetData($tRECT, 'Left', $iLeft)
        DllStructSetData($tRECT, 'Top', $iTop)
        DllStructSetData($tRECT, 'Right', $iRight)
        DllStructSetData($tRECT, 'Bottom', $iBottom)

        _WinAPI_DrawText($hDC, $sText, $tRECT, $iFlags)
    EndFunc   ;==>DrawText

    Func FillRect($hDC, $iLeft, $iTop, $iRight, $iBottom, $hBrush)
        Local $tRECT = DllStructCreate($tagRECT)

        DllStructSetData($tRECT, 'Left', $iLeft)
        DllStructSetData($tRECT, 'Top', $iTop)
        DllStructSetData($tRECT, 'Right', $iRight)
        DllStructSetData($tRECT, 'Bottom', $iBottom)

        _WinAPI_FillRect($hDC, $tRECT, $hBrush)
    EndFunc   ;==>FillRect

    Func FrameRect($hDC, $iLeft, $iTop, $iRight, $iBottom, $hBrush)
        Local $tRECT = DllStructCreate($tagRECT)

        DllStructSetData($tRECT, 'Left', $iLeft)
        DllStructSetData($tRECT, 'Top', $iTop)
        DllStructSetData($tRECT, 'Right', $iRight)
        DllStructSetData($tRECT, 'Bottom', $iBottom)

        _WinAPI_FrameRect($hDC, $tRECT, $hBrush)
    EndFunc   ;==>FrameRect

    Func InflateRect(ByRef $iLeft, ByRef $iTop, ByRef $iRight, ByRef $iBottom, $iDX, $iDY)
        Local $tRECT = DllStructCreate($tagRECT)

        DllStructSetData($tRECT, 'Left', $iLeft)
        DllStructSetData($tRECT, 'Top', $iTop)
        DllStructSetData($tRECT, 'Right', $iRight)
        DllStructSetData($tRECT, 'Bottom', $iBottom)

        _WinAPI_InflateRect($tRECT, $iDX, $iDY)

        $iLeft = DllStructGetData($tRECT, 'Left')
        $iTop = DllStructGetData($tRECT, 'Top')
        $iRight = DllStructGetData($tRECT, 'Right')
        $iBottom = DllStructGetData($tRECT, 'Bottom')
    EndFunc   ;==>InflateRect