Jump to content

Recommended Posts

Posted (edited)

image.png.5af4a0eafbc2261d114a48db0831cc19.png

image.png.da8aace5e361e95d32446fe581a6cc56.png

Spoiler
#NoTrayIcon
#AutoIt3Wrapper_UseX64=y
#include <Date.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiMenu.au3>
#include <sqlite.au3>
#include <Debug.au3>

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3> ; Required for $SS_LEFTNOWORDWRAP

DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

Opt("TrayIconHide", 1)
Opt("TrayMenuMode", 3)

;~ Global Const $WM_APP = 0x8000
;~ Global Const $TRAY_CALLBACK_MSG = $WM_APP + 1
Global Const $TRAY_CALLBACK_MSG = 0x8000 + 1

Global $g_iLBUTTONDBLCLK = 0
Global $g_hDummyGUI = GUICreate("TrayHelper")
Global $g_iLogToFile = 1

Exit main()
Func main()
    If WinExists('STUB-' & @ScriptName) Then Exit 5
    AutoItWinSetTitle('STUB-' & @ScriptName)
    If $g_iLogToFile Then FileWriteLine(StringTrimRight(@ScriptFullPath, 4) & ".log", @CRLF & _Now() & @CRLF & "Loaded - PID:" & @AutoItPID & @CRLF)
    Local $iBGColor = 0xFF005500, $iBorderColor = 0xFF349eeb
    Local $iFGColor = 0xFFE6A800 ; 0xFFFFFFFF ; Default to White text
    _CreateNumberIcon("X", $iBGColor, $iFGColor, $iBorderColor, "..loading.." & @LF & " ")
;~  _Win11_TrayNotify_HiDPI("Bluetooth", "..loading..", 4000)
    main_updateTrayWithInfo()
    AdlibRegister(main_updateTrayWithInfo, 600000) ; 10 min.

    While 1
        Sleep(100)
    WEnd
EndFunc   ;==>main

Func main_updateTrayWithInfo()

    Local $hTimer = TimerInit(), $aBluetoothInventory = _Bluetooth_Get_Device_Inventory()

    Local $sArray = _SQLite_Display2DResult($aBluetoothInventory, 0, True)
    ConsoleWrite($sArray)
    If $g_iLogToFile Then FileWriteLine(StringTrimRight(@ScriptFullPath, 4) & ".log", @CRLF & _Now() & @CRLF & $sArray)

    Local $sText = "?", $iLevel = "?", $iBGColor, $iBorderColor = 0xFF349eeb
    Local $iFGColor = 0xFFFFFFFF ; Default to White text

    If UBound($aBluetoothInventory) > 1 Then
        $iLevel = Int($aBluetoothInventory[1][6])
        $sText = $aBluetoothInventory[1][0] & ':  ' & $aBluetoothInventory[1][6] & @LF & '(' & $aBluetoothInventory[1][1] & ')' & @LF & ' '
        If $iLevel > 99 Then $iLevel = 99
    EndIf


    ; Determine the background color based on the current number
    If $iLevel >= 50 Then
        $iBGColor = 0xFF004488 ; BLUE
    ElseIf $iLevel >= 20 Then
        $iBGColor = 0xFFE6A800 ; YELLOW
        $iFGColor = 0xFF000000 ; BLACK text
    Else
        $iBGColor = 0xFFD32F2F ; RED
    EndIf

    _CreateNumberIcon($iLevel, $iBGColor, $iFGColor, $iBorderColor, $sText)

EndFunc   ;==>main_updateTrayWithInfo


Func _TrayMouseEvents($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam

    Local Const $WM_LBUTTONUP = 0x0202
    Local Const $WM_LBUTTONDBLCLK = 0x0203
    Local Const $WM_RBUTTONUP = 0x0205

    Switch $lParam
        Case $WM_LBUTTONUP
            ConsoleWrite("--> Primary Click Single!" & @CRLF)
            Return 0

        Case $WM_LBUTTONDBLCLK
            ConsoleWrite("--> Primary Double Click Action!" & @CRLF)
            ConsoleWrite("Action: You Double-Clicked the custom tray icon!" & @CRLF)
            AdlibUnRegister(main_updateTrayWithInfo)
            _CreateNumberIcon("X")
            $g_iLBUTTONDBLCLK = 1
            main_updateTrayWithInfo()
            AdlibRegister(main_updateTrayWithInfo, 600000) ; 10 min.

            Return 0

        Case $WM_RBUTTONUP ; This handles Secondary Click automatically (Righty OR Lefty!)
            ConsoleWrite("--> Secondary Click! (Show Context Menu)" & @CRLF)

            Local $hMenu = _GUICtrlMenu_CreatePopup()
            _GUICtrlMenu_InsertMenuItem($hMenu, 0, "Browse folder", 1001)
            _GUICtrlMenu_InsertMenuItem($hMenu, 1, "Reload script", 1002)
            _GUICtrlMenu_InsertMenuItem($hMenu, 2, "", 0)
            _GUICtrlMenu_InsertMenuItem($hMenu, 3, "Exit script", 1009)

            Local $tPoint = DllStructCreate("long X;long Y")
            DllCall("user32.dll", "bool", "GetCursorPos", "struct*", $tPoint)

            DllCall("user32.dll", "bool", "SetForegroundWindow", "hwnd", $hWnd)

            Local $aRet = DllCall("user32.dll", "int", "TrackPopupMenu", "handle", $hMenu, "uint", 0x0100, "int", DllStructGetData($tPoint, "X"), "int", DllStructGetData($tPoint, "Y"), "int", 0, "hwnd", $hWnd, "ptr", 0)
            Local $iSelectedID = $aRet[0]

            _GUICtrlMenu_DestroyMenu($hMenu)

            Switch $iSelectedID
                Case 1001
                    AdlibRegister(OnTrayMenu_BrowseScript, 10)

                Case 1002
                    ConsoleWrite("ReloadScript..." & @CRLF)
                    AdlibRegister(OnTrayMenu_ReloadScript, 10)

                Case 1009
                    AdlibRegister(OnTrayMenu_ExitScript, 10)

            EndSwitch

            Return 0

    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>_TrayMouseEvents

Func OnTrayMenu_ExitScript()
    AdlibUnRegister(OnTrayMenu_ExitScript)
    AutoItWinSetTitle('EXIT-' & @ScriptName)
    Exit
EndFunc   ;==>OnTrayMenu_ExitScript

Func OnTrayMenu_BrowseScript()
    AdlibUnRegister(OnTrayMenu_BrowseScript)
    Local $iPID = ShellExecute(@WindowsDir & "\explorer.exe", '/n,/select,"' & @ScriptFullPath & '"', "")
    ConsoleWrite('- $iPID: ' & $iPID & @CRLF)
EndFunc   ;==>OnTrayMenu_BrowseScript

Func OnTrayMenu_ReloadScript()
    AdlibUnRegister(OnTrayMenu_ReloadScript)
    AutoItWinSetTitle('RELOAD-' & @ScriptName)
    ShellExecute(@AutoItExe, '"' & @ScriptFullPath & '"')
    Exit
EndFunc   ;==>OnTrayMenu_ReloadScript


Func _CreateNumberIcon($iNumber, $iBGColor = 0xFF004488, $iFGColor = 0xFFFFFFFF, $iBorderColor = 0xFF34eb58, $sStr = "")
    Local Static $iInitGDIPlus = _UpdateTray("StartUp")
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0(16, 16)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, 4)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)

    _GDIPlus_GraphicsClear($hGraphics, $iBorderColor)

    Local $hBrushBG = _GDIPlus_BrushCreateSolid($iBGColor)
    Local $iFillWidth = 1
    Local $iFillOtherSide = 13
    _GDIPlus_GraphicsFillRect($hGraphics, $iFillWidth, $iFillWidth, $iFillOtherSide, $iFillOtherSide, $hBrushBG)

    Local $hBrushText = _GDIPlus_BrushCreateSolid($iFGColor)
    Local $hFamily = _GDIPlus_FontFamilyCreate("Arial")

    ; Get the current DPI for the primary monitor
    Local $hDC = _WinAPI_GetDC(0)
    Local $iDPI_X = _WinAPI_GetDeviceCaps($hDC, 88) ; 88 = LOGPIXELSX
    _WinAPI_ReleaseDC(0, $hDC)

    ; Calculate the scaling ratio (96 is the standard 100% DPI)
    Local $fScale = $iDPI_X / 96

    ; Use the scale to adjust your font size dynamically
    Local $iFontSize = 8 / $fScale
    Local $hFont = _GDIPlus_FontCreate($hFamily, $iFontSize, 1)
    Local $hFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hFormat, 1)
    _GDIPlus_StringFormatSetLineAlign($hFormat, 1)
    Local $tLayout = _GDIPlus_RectFCreate(0, 0, 16, 16)

    _GDIPlus_GraphicsDrawStringEx($hGraphics, String($iNumber), $hFont, $tLayout, $hFormat, $hBrushText)

    Local $hGDI_Bitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)

    Local $aMask = DllCall("gdi32.dll", "handle", "CreateBitmap", "int", 16, "int", 16, "uint", 1, "uint", 1, "ptr", 0)
    Local $hMask = $aMask[0]

    Local $tICONINFO = DllStructCreate("int fIcon; dword xHotspot; dword yHotspot; handle hbmMask; handle hbmColor")
    DllStructSetData($tICONINFO, "fIcon", 1)
    DllStructSetData($tICONINFO, "hbmMask", $hMask)
    DllStructSetData($tICONINFO, "hbmColor", $hGDI_Bitmap)

    Local $aIcon = DllCall("user32.dll", "handle", "CreateIconIndirect", "struct*", $tICONINFO)
    Local $hIcon = $aIcon[0]

    DllCall("gdi32.dll", "bool", "DeleteObject", "handle", $hMask)
    DllCall("gdi32.dll", "bool", "DeleteObject", "handle", $hGDI_Bitmap)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_StringFormatDispose($hFormat)
    _GDIPlus_BrushDispose($hBrushText)
    _GDIPlus_BrushDispose($hBrushBG)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBitmap)

    _UpdateTray($hIcon, $sStr)
    DllCall("user32.dll", "bool", "DestroyIcon", "handle", $hIcon)

    If ($iNumber < 50 Or $g_iLBUTTONDBLCLK) And ($iNumber <> "X") Then _Win11_TrayNotify_HiDPI("Bluetooth", $sStr, 6000, BitAND($iBGColor, 0x00FFFFFF), BitAND($iFGColor, 0x00FFFFFF))
    $g_iLBUTTONDBLCLK = 0
;~  _Win11_TrayNotify_HiDPI($sTitle = "", $sMessage = "", $iDuration = 6000, $iBgColor = 0x704218, $iFgColor = 0xFFFF00)

    Return 0
EndFunc   ;==>_CreateNumberIcon

Func _UpdateTray_OnShutdown()
    _UpdateTray("ShutDown", "")
    GUIRegisterMsg($TRAY_CALLBACK_MSG, "")
    If IsHWnd($g_hDummyGUI) Then GUIDelete($g_hDummyGUI)
    _GDIPlus_Shutdown()
EndFunc   ;==>_UpdateTray_OnShutdown

Func _UpdateTray($hIcon, $sStr = "")
    Local Static $iStartup = "StartUp", $_bTrayCreated = False, $_tNID = DllStructCreate("dword Size;hwnd Wnd;uint ID;uint Flags;uint CallbackMessage;handle Icon;wchar Tip[128]")

    If $iStartup = "StartUp" Then
        DllStructSetData($_tNID, "Size", DllStructGetSize($_tNID))
        DllStructSetData($_tNID, "Wnd", $g_hDummyGUI)
        DllStructSetData($_tNID, "ID", 999)
        DllStructSetData($_tNID, "Flags", 0x07)
        DllStructSetData($_tNID, "CallbackMessage", $TRAY_CALLBACK_MSG)

        GUIRegisterMsg($TRAY_CALLBACK_MSG, "_TrayMouseEvents")

        _GDIPlus_Startup()
        OnAutoItExitRegister(_UpdateTray_OnShutdown)
        $iStartup = "Running"
        If $hIcon = "StartUp" Then Return 1

    ElseIf $hIcon = "ShutDown" Then
        DllCall("shell32.dll", "bool", "Shell_NotifyIconW", "dword", 0x02, "struct*", $_tNID) ; NIM_DELETE
        _GDIPlus_Shutdown()
        Return 2
    EndIf

    DllStructSetData($_tNID, "Icon", $hIcon)
    DllStructSetData($_tNID, "Tip", String($sStr))

    If Not $_bTrayCreated Then
        DllCall("shell32.dll", "bool", "Shell_NotifyIconW", "dword", 0x00, "struct*", $_tNID)
        $_bTrayCreated = True
    Else
        DllCall("shell32.dll", "bool", "Shell_NotifyIconW", "dword", 0x01, "struct*", $_tNID)
    EndIf
EndFunc   ;==>_UpdateTray

; ======================================================================================

Func _Bluetooth_Get_Device_Inventory()
    Local $a_GetBluetoothDeviceInfo = _GetBluetoothDeviceInfo()
    Local $aError[1][1] = [["No Bluetooth Radio found or Bluetooth is turned off."]]

    ; Initialize Radio
    Local $tFindRadioParams = DllStructCreate("dword dwSize")
    DllStructSetData($tFindRadioParams, "dwSize", DllStructGetSize($tFindRadioParams))
    Local $hRadioOut = 0
    Local $aRadioCall = DllCall("Bthprops.cpl", "hwnd", "BluetoothFindFirstRadio", "ptr", DllStructGetPtr($tFindRadioParams), "hwnd*", $hRadioOut)
    If @error Or $aRadioCall[0] = 0 Then
        SetError(1)
        Return $aError
    EndIf
    Local $hRadio = $aRadioCall[2]
    Local $hRadioFindHandle = $aRadioCall[0]

    ; Search Parameters
    Local $sSearchParams = "dword dwSize; bool fReturnAuthenticated; bool fReturnRemembered; bool fReturnUnknown; bool fReturnConnected; bool fIssueInquiry; byte cTimeoutMultiplier; hwnd hRadio;"
    Local $tSearchParams = DllStructCreate($sSearchParams)
    DllStructSetData($tSearchParams, "dwSize", DllStructGetSize($tSearchParams))
    DllStructSetData($tSearchParams, "fReturnAuthenticated", 1)
    DllStructSetData($tSearchParams, "fReturnRemembered", 1)
    DllStructSetData($tSearchParams, "fReturnUnknown", 1)
    DllStructSetData($tSearchParams, "fReturnConnected", 1)
    DllStructSetData($tSearchParams, "fIssueInquiry", 1)
    DllStructSetData($tSearchParams, "cTimeoutMultiplier", 4)
    DllStructSetData($tSearchParams, "hRadio", $hRadio)

    ; Device Struct Definition
    Local $sDeviceInfo = "dword dwSize; int64 Address; dword ulClassofDevice; bool fConnected; bool fRemembered; bool fAuthenticated; " & _
            "ushort LastSeenYear; ushort LastSeenMonth; ushort LastSeenDayOfWeek; ushort LastSeenDay; ushort LastSeenHour; ushort LastSeenMinute; ushort LastSeenSecond; ushort LastSeenMS; " & _
            "ushort LastUsedYear; ushort LastUsedMonth; ushort LastUsedDayOfWeek; ushort LastUsedDay; ushort LastUsedHour; ushort LastUsedMinute; ushort LastUsedSecond; ushort LastUsedMS; " & _
            "wchar szName[248];"
    Local $tDeviceInfo = DllStructCreate($sDeviceInfo)
    DllStructSetData($tDeviceInfo, "dwSize", DllStructGetSize($tDeviceInfo))

    ; Prepare Output Array Structure (Columns: 0 to 7)
    Local $aResult[1][7] = [["Device Name", "MAC Address (Hex)", "Device Class", "Connected", "Remembered", "Last Used", "Battery Level"]]
    Local $iDeviceCount = 0

    ; Start Device Loop
    Local $aDeviceCall = DllCall("Bthprops.cpl", "hwnd", "BluetoothFindFirstDevice", "ptr", DllStructGetPtr($tSearchParams), "ptr", DllStructGetPtr($tDeviceInfo))

    If @error Or $aDeviceCall[0] = 0 Then
        DllCall("Bthprops.cpl", "bool", "BluetoothFindRadioClose", "hwnd", $hRadioFindHandle)
        DllCall("kernel32.dll", "bool", "CloseHandle", "hwnd", $hRadio)
        Return $aResult
    Else
        Local $hDeviceFindHandle = $aDeviceCall[0]
        Local $sName, $iAddress, $iClass, $bConnected, $bRemembered, $sHexMac, $sFormattedHexMac, $sLastUsed, $sBatteryVal, $iMajorClass

        While 1

            ; Get Data from API
            $sName = DllStructGetData($tDeviceInfo, "szName")
            $iAddress = DllStructGetData($tDeviceInfo, "Address")
            $iClass = DllStructGetData($tDeviceInfo, "ulClassofDevice")
            $bConnected = DllStructGetData($tDeviceInfo, "fConnected")
            $bRemembered = DllStructGetData($tDeviceInfo, "fRemembered")
            $sHexMac = StringLower(Hex($iAddress, 12))
            $sFormattedHexMac = StringRegExpReplace($sHexMac, "(.{2})(?=.)", "$1:")

            ; Parse Timestamp
            $sLastUsed = "Never"
            If DllStructGetData($tDeviceInfo, "LastUsedYear") > 0 Then
                $sLastUsed = DllStructGetData($tDeviceInfo, "LastUsedMonth") & "/" & DllStructGetData($tDeviceInfo, "LastUsedDay") & "/" & DllStructGetData($tDeviceInfo, "LastUsedYear") & _
                        " " & StringRight("00" & DllStructGetData($tDeviceInfo, "LastUsedHour"), 2) & ":" & StringRight("00" & DllStructGetData($tDeviceInfo, "LastUsedMinute"), 2)
            EndIf

            ; Fetch Live Battery if connected
            $sBatteryVal = "N/A"    ;  (Offline)"
            For $iEntry = 0 To UBound($a_GetBluetoothDeviceInfo) - 1
                If $a_GetBluetoothDeviceInfo[$iEntry][6] = $sFormattedHexMac Then $sBatteryVal = $a_GetBluetoothDeviceInfo[$iEntry][1]
            Next

            ; Major Device Class occupies bits 8 to 12
            $iMajorClass = BitShift(BitAND($iClass, 0x1F00), 8)

;~          If $iMajorClass = 4 And $bRemembered Then
            If $iMajorClass = 4 And $bConnected Then

                $iDeviceCount += 1
                ReDim $aResult[$iDeviceCount + 1][UBound($aResult, 2)]

                $aResult[$iDeviceCount][0] = $sName
                $aResult[$iDeviceCount][1] = StringUpper($sFormattedHexMac)
                $aResult[$iDeviceCount][2] = "0x" & Hex($iClass, 6)
                $aResult[$iDeviceCount][3] = ($bConnected ? "True" : "False")
                $aResult[$iDeviceCount][4] = ($bRemembered ? "True" : "False")
                $aResult[$iDeviceCount][5] = $sLastUsed
                $aResult[$iDeviceCount][6] = $sBatteryVal ; << don't work here

            EndIf

            ; Next Device
            Local $aNextCall = DllCall("Bthprops.cpl", "bool", "BluetoothFindNextDevice", "hwnd", $hDeviceFindHandle, "ptr", DllStructGetPtr($tDeviceInfo))
            If @error Or $aNextCall[0] = 0 Then ExitLoop
        WEnd

        DllCall("Bthprops.cpl", "bool", "BluetoothFindDeviceClose", "hwnd", $hDeviceFindHandle)
    EndIf

    ; Cleanup
    DllCall("Bthprops.cpl", "bool", "BluetoothFindRadioClose", "hwnd", $hRadioFindHandle)
    DllCall("kernel32.dll", "bool", "CloseHandle", "hwnd", $hRadio)

    Return $aResult
EndFunc   ;==>_Bluetooth_Get_Device_Inventory

Func _GetBluetoothDeviceInfo()
    Local Const $DIGCF_PRESENT = 0x00000002
    Local Const $DIGCF_DEVICEINTERFACE = 0x00000010

    ; Define properties to query: {GUID}, Property ID
    Local $aKeys[5][2] = [ _
            ["{a45c254e-df1c-4efd-8020-67d146a850e0}", 14], _ ; Friendly Name
            ["{104EA319-6EE2-4701-BD47-8DDBF425BBE5}", 2], _ ; Battery Level
            ["{a45c254e-df1c-4efd-8020-67d146a850e0}", 13], _ ; Manufacturer (May still be blank for Generic BT devices!)
            ["{a45c254e-df1c-4efd-8020-67d146a850e0}", 3], _ ; Hardware ID
            ["{78c34fc8-104a-4aca-9ea4-524d52996e57}", 256] _ ; Instance ID
            ]

    Local $iNumProps = UBound($aKeys)

    ; Bluetooth Device Interface Class GUID
    Local $tGUID = DllStructCreate("ulong;ushort;ushort;byte[8]")
    DllCall("ole32.dll", "long", "CLSIDFromString", "wstr", "{0000111e-0000-1000-8000-00805f9b34fb}", "ptr", DllStructGetPtr($tGUID))

    ; Handle to active Bluetooth objects
    Local $aHdev = DllCall("setupapi.dll", "handle", "SetupDiGetClassDevsW", _
            "ptr", DllStructGetPtr($tGUID), "ptr", 0, "hwnd", 0, "dword", BitOR($DIGCF_PRESENT, $DIGCF_DEVICEINTERFACE))
    If @error Or $aHdev[0] = -1 Then Return SetError(1, 0, 0)
    Local $hDevInfo = $aHdev[0]

    ; Explicit structural memory boundaries for 64-bit portability
    Local $sInterfaceDataDef = "dword cbSize;ulong;ushort;ushort;byte[8];ulong_ptr Reserved"
    Local $tDeviceInterfaceData = DllStructCreate($sInterfaceDataDef)
    DllStructSetData($tDeviceInterfaceData, "cbSize", DllStructGetSize($tDeviceInterfaceData))

    Local $sDevInfoDataDef = "dword cbSize;ulong;ushort;ushort;byte[8];ulong_ptr DevInst"
    Local $tDeviceInfoData = DllStructCreate($sDevInfoDataDef)
    DllStructSetData($tDeviceInfoData, "cbSize", DllStructGetSize($tDeviceInfoData))

    Local $iIndex = 0
    Local $aResults[50][$iNumProps]
    Local $iCount = 0

    While True
        Local $aEnum = DllCall("setupapi.dll", "bool", "SetupDiEnumDeviceInterfaces", _
                "handle", $hDevInfo, "ptr", 0, "ptr", DllStructGetPtr($tGUID), "dword", $iIndex, "ptr", DllStructGetPtr($tDeviceInterfaceData))

        If @error Or Not $aEnum[0] Then ExitLoop

        ; Match interface to specific hardware instance block
        DllCall("setupapi.dll", "bool", "SetupDiGetDeviceInterfaceDetailW", _
                "handle", $hDevInfo, "ptr", DllStructGetPtr($tDeviceInterfaceData), "ptr", 0, "dword", 0, "dword*", 0, "ptr", DllStructGetPtr($tDeviceInfoData))

        Local $bHasData = False

        ; Loop through our mapped DEVPROPKEYs
        For $i = 0 To $iNumProps - 1
            Local $tPropKey = DllStructCreate("ulong;ushort;ushort;byte[8];ulong")
            DllCall("ole32.dll", "long", "CLSIDFromString", "wstr", $aKeys[$i][0], "ptr", DllStructGetPtr($tPropKey))
            DllStructSetData($tPropKey, 5, $aKeys[$i][1])

            ; Use a generic byte buffer large enough for any standard type
            Local $tBuffer = DllStructCreate("byte[1024]")
            Local $iPropType = 0
            Local $iReqSize = 0

            ; Extract Property
            Local $aProp = DllCall("setupapi.dll", "bool", "SetupDiGetDevicePropertyW", _
                    "handle", $hDevInfo, "ptr", DllStructGetPtr($tDeviceInfoData), "ptr", DllStructGetPtr($tPropKey), _
                    "ulong*", $iPropType, "ptr", DllStructGetPtr($tBuffer), "dword", 1024, "dword*", $iReqSize, "dword", 0)

            Local $sValue = ""

            ; If extraction succeeded, cast the memory dynamically based on the returned PropertyType
            If Not @error And $aProp[0] Then
                $iPropType = $aProp[4] ; $aProp[4] holds the type of data Windows returned

                If $iPropType = 0x00000012 Or $iPropType = 0x00002012 Then
                    ; DEVPROP_TYPE_STRING or DEVPROP_TYPE_STRING_LIST
                    Local $tString = DllStructCreate("wchar[512]", DllStructGetPtr($tBuffer))
                    $sValue = DllStructGetData($tString, 1)

                ElseIf $iPropType = 0x00000003 Then
                    ; DEVPROP_TYPE_BYTE (Used for Battery Levels)
                    $sValue = DllStructGetData($tBuffer, 1, 1)
                    If $sValue >= 0 And $sValue <= 100 Then $sValue &= "%"

                ElseIf $iPropType = 0x00000007 Then
                    ; DEVPROP_TYPE_UINT32
                    Local $tInt = DllStructCreate("dword", DllStructGetPtr($tBuffer))
                    $sValue = DllStructGetData($tInt, 1)
                EndIf

                If $sValue <> "" Then $bHasData = True
            EndIf

            $aResults[$iCount][$i] = (StringLen($sValue) < 2 ? "N/A" : $sValue)
        Next

        ; Only move to the next row if the device actually had populated metadata
        If $bHasData Then $iCount += 1

        ; Dynamically resize array if you have more than 50 Bluetooth components
        If $iCount >= UBound($aResults) Then ReDim $aResults[UBound($aResults) + 20][$iNumProps]

        $iIndex += 1
    WEnd

    DllCall("setupapi.dll", "bool", "SetupDiDestroyDeviceInfoList", "handle", $hDevInfo)

    If $iCount = 0 Then Return SetError(2, 0, 0)

    ReDim $aResults[$iCount][$iNumProps + 2]

    Local $aMatch, $sFormattedMAC ; get MAC from InstanceID
    For $n = 0 To UBound($aResults) - 1
        $aMatch = StringRegExp($aResults[$n][$iNumProps - 1], "&([0-9A-Fa-f]{12})_", 1)
        If @error Then ContinueLoop
        $sFormattedMAC = StringRegExpReplace($aMatch[0], "(.{2})(?!$)", "$1:")
        If @error Then ContinueLoop
        $aResults[$n][$iNumProps + 1] = $sFormattedMAC
    Next
    Return $aResults
EndFunc   ;==>_GetBluetoothDeviceInfo

; ======================================================================================

;~ ConsoleWrite("DeviceClass desc.: " & _DecodeDeviceClass(0x240404) & @CRLF)
Func _DecodeDeviceClass($iCoD)

;~              Local $iCoD = 0x240404
;~              ; Major Service Classes (Bits 13 to 23)
;~              Local $iServiceClass = BitAND($iCoD, 0xFFE000)
;~              ; Major Device Class (Bits 8 to 12)
;~              Local $iMajorClass = BitShift(BitAND($iCoD, 0x1F00), 8) ; Will return 4 for Audio/Video
;~              ; Minor Device Class (Bits 2 to 7)
;~              Local $iMinorClass = BitShift(BitAND($iCoD, 0xFC), 2)  ; Will return 1 for Headset, 6 for Headphones



    Local $iMajorClass = BitShift(BitAND($iCoD, 0x1F00), 8)
    Local $iMinorClass = BitShift(BitAND($iCoD, 0x00FC), 2)
    Local $sMajorText = "Unknown"
    Local $sMinorText = "Generic"

    ; Look-up for Major Device Class
    Switch $iMajorClass
        Case 1
            $sMajorText = "Computer"
        Case 2
            $sMajorText = "Phone"
        Case 3
            $sMajorText = "Network Access Point"
        Case 4
            $sMajorText = "Audio/Video"
        Case 5
            $sMajorText = "Peripheral (Mouse/Keyboard)"
        Case 6
            $sMajorText = "Imaging (Printer/Scanner)"
        Case 7
            $sMajorText = "Wearable"
    EndSwitch

    ; Look-up for Minor Device Class ( for Audio/Video family )
    If $iMajorClass = 4 Then
        Switch $iMinorClass
            Case 1
                $sMinorText = "Wearable Headset"
            Case 2
                $sMinorText = "Hands-free Device"
            Case 4
                $sMinorText = "Microphone"
            Case 5
                $sMinorText = "Loudspeaker"
            Case 6
                $sMinorText = "Headphones"
            Case 7
                $sMinorText = "Portable Audio"
            Case 11
                $sMinorText = "Set-top Box"
            Case 12
                $sMinorText = "HiFi Audio Device"
            Case 13
                $sMinorText = "VCR/DVD/BlueRay"
            Case 14
                $sMinorText = "Video Camera"
            Case 15
                $sMinorText = "Display/Monitor and Loudspeaker"
        EndSwitch
    EndIf

    Return $sMajorText & " -> " & $sMinorText
EndFunc   ;==>_DecodeDeviceClass

; ======================================================================================

;~ _Win11_TrayNotify_HiDPI("HiDPI Alert", "yes, this is an alert. Be alerted !", 4000)
; close it by ESC or mouse click on it ( left or right )
Func _Win11_TrayNotify_HiDPI($sTitle = "", $sMessage = "", $iDuration = 6000, $iBGColor = 0x704218, $iFGColor = 0xFFFF00)
    Local Static $hNotifyGUI = 0, $h_Timer, $i_Duration = -2, $i_Clicked1 = 0, $i_Clicked2

    ; removed the "_HiDPI_" stuff,

    If Eval("sTitle") = "" And Eval("sMessage") = "" Then ; Eval() is needed because of Adlib ;)
        Local $aMouse = MouseGetPos()
        Local $aWinPos = WinGetPos($hNotifyGUI)
        Local $aRet = DllCall("user32.dll", "short", "GetAsyncKeyState", "int", 0x1B) ; 0x1B = VK_ESCAPE
        If Not @error And $i_Clicked1 = 0 And BitAND($aRet[0], 0x8000) Then $i_Clicked1 = 1
        If IsArray($aMouse) And IsArray($aWinPos) Then
            If $aMouse[0] >= $aWinPos[0] And $aMouse[0] <= ($aWinPos[0] + $aWinPos[2]) And _
                    $aMouse[1] >= $aWinPos[1] And $aMouse[1] <= ($aWinPos[1] + $aWinPos[3]) Then

                $aRet = DllCall("user32.dll", "short", "GetAsyncKeyState", "int", 0x01) ; 0x01 = VK_LBUTTON
                If Not @error Then
                    If $i_Clicked1 = 0 And BitAND($aRet[0], 0x8000) Then $i_Clicked1 = 2
                    If $i_Clicked1 = 2 And Not BitAND($aRet[0], 0x8000) Then $i_Clicked1 = 1
                EndIf

                $aRet = DllCall("user32.dll", "short", "GetAsyncKeyState", "int", 0x02) ; 0x02 = VK_RBUTTON
                If Not @error Then
                    If $i_Clicked2 = 0 And BitAND($aRet[0], 0x8000) Then $i_Clicked2 = 2
                    If $i_Clicked2 = 2 And Not BitAND($aRet[0], 0x8000) Then $i_Clicked2 = 1
                EndIf

            EndIf
        EndIf

        If $i_Clicked1 = 1 Or $i_Clicked2 = 1 Or TimerDiff($h_Timer) >= $i_Duration Then
            AdlibUnRegister("_Win11_TrayNotify_HiDPI")
            If GUIDelete($hNotifyGUI) Then $hNotifyGUI = 0
        EndIf
        Return
    EndIf

    AdlibUnRegister("_Win11_TrayNotify_HiDPI")
    If IsHWnd($hNotifyGUI) Then GUIDelete($hNotifyGUI)

    Local $hDC = DllCall("user32.dll", "handle", "GetDC", "hwnd", 0)
    Local $iLogPixelsY = DllCall("gdi32.dll", "int", "GetDeviceCaps", "handle", $hDC[0], "int", 90)
    DllCall("user32.dll", "int", "ReleaseDC", "hwnd", 0, "handle", $hDC[0])
    Local $fScale = $iLogPixelsY[0] / 96
    $fScale = 1 ; remove this line if you're gonna use "_HiDPI_" stuff

    $i_Duration = $iDuration
    $i_Clicked1 = 0
    $i_Clicked2 = 0
    Local $iWidth = 300
    Local $iHeight = 85

    $hNotifyGUI = GUICreate("_Win11_TrayNotify_HiDPI|PID:" & @AutoItPID, $iWidth, $iHeight, -1, -1, 0x80880000, -1, WinGetHandle('STUB-' & @ScriptName))
    GUISetBkColor($iBGColor, $hNotifyGUI)

    GUICtrlCreateLabel($sTitle, 15, 10, $iWidth - 30, 27, $SS_LEFTNOWORDWRAP)
    GUICtrlSetColor(-1, $iFGColor)
    GUICtrlSetFont(-1, 10, 800, 0, "Segoe UI")

    GUICtrlCreateLabel($sMessage, 15, 45, $iWidth - 30, 30, $SS_LEFTNOWORDWRAP)
    GUICtrlSetColor(-1, $iFGColor)
    GUICtrlSetFont(-1, 9, 400, 0, "Segoe UI")


    Local $iScaledWidth = $iWidth * $fScale
    Local $iScaledHeight = $iHeight * $fScale
    Local $iPadding = 10 * $fScale
    Local $iX = @DesktopWidth - $iScaledWidth - $iPadding
    Local $iY = @DesktopHeight - 100 - $iScaledHeight - $iPadding
    Local $aTrayPos = WinGetPos("[CLASS:Shell_TrayWnd]")
    If IsArray($aTrayPos) Then $iY = @DesktopHeight - $aTrayPos[3] - $iScaledHeight - $iPadding

    WinMove($hNotifyGUI, "", $iX, $iY)
    GUISetState(@SW_SHOWNOACTIVATE, $hNotifyGUI)
    WinSetOnTop($hNotifyGUI, "", 1)
    $h_Timer = TimerInit()
    AdlibRegister("_Win11_TrayNotify_HiDPI", 100) ; 100 mSec. should be ok
EndFunc   ;==>_Win11_TrayNotify_HiDPI

 

I use earbuds ( these cheaper ones because they don't bother my ears** ) and the internal batteries of each side are different. Meaning that one always dies hours before the other and I wanted a "tray indicator" because the build-in on windows one takes clicking, and the "battery low" announcement annoys me when am not close to the PC.
Now if I happen to see the battery at 40% or less I know that might as well swap them with my other set of earbuds if I feel like it.
** since I don't inset them in my ear canal ( just let them loose ), I also have a sound equalizer ( FxSound ) to make them sound better.

Code wise here are examples of a fake tray icon with clicking and Bluetooth radio, and other Bluetooth things if you scrape them out of the script.
It checks every 10 min.

P.S.: Was thinking of adding a "on new devise connected" thing, and if I ever do, I'll update the example.

Edit 2026.07.08:
Added a popup/tray thing to make it more visible that the battery is 40% or below.
Added update on tray DClick

Edited by argumentum
newer

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

Posted (edited)
On 6/30/2026 at 3:59 PM, argumentum said:

Was thinking of adding a "on new devise connected" thing, and if I ever do, I'll update the example.

Am not gonna use it but you might

image.thumb.png.ae33b75d66d0a3b375938d5ae9cf289d.png

#AutoIt3Wrapper_UseX64=y
#AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#include <ListViewConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <GUIDarkTheme.au3> ;    https://www.autoitscript.com/forum/topic/213613-guidarktheme-udf/
#include <GuiCtrls_HiDpi.au3> ;  https://www.autoitscript.com/forum/topic/210613-guictrls_hidpi-udf-in-progress/

_HiDpi_Ctrl_LazyInit()

;~ Global Const $WM_DEVICECHANGE = 0x0219
Global Const $DBT_DEVICEARRIVAL = 0x8000
Global Const $DBT_DEVICEREMOVECOMPLETE = 0x8004 ; A device or piece of media has been removed. ; https://learn.microsoft.com/en-us/windows/win32/devio/wm-devicechange
Global Const $DBT_DEVTYP_DEVICEINTERFACE = 0x00000005

Global $g_hGUI, $g_idListView, $g_hDeviceNotify

_GUI_Create()
_Reg_DetailedDeviceNotifications()
_ConsoleListviewWrite("- Ready.")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit ; will automatically trigger the cleanup function
    EndSwitch
WEnd

Func WM_DEVICECHANGE_Handler($hWnd, $iMsg, $wParam, $lParam)
    _ConsoleListviewWrite('+ Func WM_DEVICECHANGE_Handler(' & $hWnd & ', ' & $iMsg & ', ' & $wParam & ', ' & $lParam & ')' & @CRLF)
    If $wParam = $DBT_DEVICEARRIVAL Or $wParam = $DBT_DEVICEREMOVECOMPLETE Then

        Local $tHeader = DllStructCreate("dword Size; dword DeviceType; dword Reserved", $lParam)

        If DllStructGetData($tHeader, "DeviceType") = $DBT_DEVTYP_DEVICEINTERFACE Then

            Local $iTotalSize = DllStructGetData($tHeader, "Size")
            Local $iStringLen = ($iTotalSize - 28) / 2

            Local $tInterface = DllStructCreate("dword Size; dword DeviceType; dword Reserved; byte ClassGuid[16]; wchar Name[" & $iStringLen & "]", $lParam)
            Local $sDevicePath = DllStructGetData($tInterface, "Name")

            If StringInStr($sDevicePath, "MMDEVAPI") Then

                ; Extract the endpoint GUID block between the brackets: {d448e9f2-5211-490a-bef1-58b9f9cc4881}
                ; Match standard 8-4-4-4-12 hex pattern inside curly braces
                Local $aGuidMatch = StringRegExp($sDevicePath, "(?i)\{([[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12})\}", 3)

                If UBound($aGuidMatch) > 0 Then

                    ; The audio endpoint subkey format uses the full curly braces
                    Local $sEndpointGUID = "{" & $aGuidMatch[0] & "}"

                    Local $sRoot = (@AutoItX64) ? "HKLM" : "HKLM64"
                    Local $sParentKey = $sRoot & "\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\" & $sEndpointGUID
                    Local $sPropsKey = $sParentKey & "\Properties"  ; Windows Audio Properties subkey for the endpoint
;~                  Local $sFxPropsKey = $sParentKey & "\FxProperties" ; meh

                    _ConsoleListviewWrite("    + $sPropsKey: " & $sPropsKey & @CRLF)

                    ; PKEY_Device_FriendlyName (Native Windows Audio property key)
                    Local $sFriendlyName = RegRead($sPropsKey, "{a45c254e-df1c-4efd-8020-67d146a850e0},2")

                    ; PKEY_Device_EnumeratorName (tells us if it's SWD, USB, BTHENUM, etc.) ; didn't test much
                    Local $sEnumerator = RegRead($sPropsKey, "{a45c254e-df1c-4efd-8020-67d146a850e0},24")

                    _ConsoleListviewWrite("    +   $sEnumerator:    " & $sEnumerator & @CRLF)
                    _ConsoleListviewWrite("    + $sFriendlyName:    " & $sFriendlyName & @CRLF)

                    ; SKIP BLANK ENTRIES ( race condition protection ? )
                    If $sFriendlyName = "" And $sEnumerator = "" Then Return $GUI_RUNDEFMSG

                    Local $sEvent = ($wParam = $DBT_DEVICEARRIVAL) ? "Connected" : "Disconnected"

                    ; Check if the underlying enumerator or description points to Bluetooth
                    If StringInStr($sEnumerator, "BTH") Or StringInStr($sFriendlyName, "Bluetooth") Then
                        _ConsoleListviewWrite("--> Bluetooth Audio " & $sEvent & ": " & $sFriendlyName & @CRLF)

                        ; =========================================================================
                        ; YOUR CUSTOM CODE GOES HERE
                        ; e.g., If $sEvent = "Connected" Then _DoSomething()
                        ; I would use AdlibRegister(,1000) for the possible race condition
                        ; =========================================================================

                        ; Read raw values
                        Local $iRawFormFactor = RegRead($sPropsKey, "{a45c254e-df1c-4efd-8020-67d146a850e0},0")
                        Local $iRawState = RegRead($sParentKey, "DeviceState")

                        ; Translate to human readable becuse we are nice people
                        Local $sFormFactorReadable = _GetAudioFormFactorName($iRawFormFactor)
                        Local $sStateReadable = _GetAudioDeviceStateName($iRawState)

                        _ConsoleListviewWrite("    + Hardware Profile: " & $sFormFactorReadable & @CRLF)
                        _ConsoleListviewWrite("    + Current Status:   " & $sStateReadable & @CRLF)

                    EndIf
                EndIf
            EndIf
        EndIf
    EndIf

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DEVICECHANGE_Handler

; =========================================================================
; Desc: Translates Windows EndpointFormFactor DWORD into readable text
; =========================================================================
Func _GetAudioFormFactorName($iFormFactor)
    Switch Int($iFormFactor)
        Case 0
            Return "Remote Device"
        Case 1
            Return "Speakers"
        Case 2
            Return "Headphones"
        Case 3
            Return "Earphones"
        Case 4
            Return "Built-in Microphone Array"
        Case 5
            Return "Headset (Microphone + Playback)"
        Case 6
            Return "Handset"
        Case 7
            Return "Digital Audio Interface (SPDIF/HDMI)"
        Case 8
            Return "Line Level In/Out (Aux)"
        Case 9
            Return "SPDIF Interface"
        Case 10
            Return "HDMI Device"
        Case 11
            Return "Unknown Form Factor"
        Case Else
            Return "Undefined (" & $iFormFactor & ")"
    EndSwitch
EndFunc   ;==>_GetAudioFormFactorName

; =========================================================================
; Desc: Translates Windows MMDevice DEVICE_STATE_xxx constants
; =========================================================================
Func _GetAudioDeviceStateName($iState)
    Switch Int($iState)
        Case 1 ; DEVICE_STATE_ACTIVE
            Return "Active / Connected"
        Case 2 ; DEVICE_STATE_DISABLED
            Return "Disabled by User"
        Case 4 ; DEVICE_STATE_NOTPRESENT
            Return "Hardware Unplugged / Missing"
        Case 8 ; DEVICE_STATE_UNPLUGGED
            Return "Jack Unplugged"
        Case 26843546 ; Common combined state for certain disabled virtual profiles
            Return "Disabled (Unavailable)"
        Case Else
            Return "Unknown Status (" & $iState & ")"
    EndSwitch
EndFunc   ;==>_GetAudioDeviceStateName

Func _ConsoleListviewWrite($sStr)
    Local $iBgColor, $sTime = @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC
    $sStr &= (StringRight($sStr, 2) = @CRLF ? "" : @CRLF)
    ConsoleWrite($sStr)
    FileWriteLine(StringTrimRight(@ScriptFullPath, 4) & "_" & @YEAR & @MON & @MDAY & ".log", $sTime & " | " & $sStr)

    Switch StringLeft($sStr, 1)
        Case "+" ; Success -> Green-ish
;~          $iBgColor = 0xD4EDDA
            $iBgColor = 0x0F3D1A
            $sStr = StringTrimLeft($sStr, 1) ; Strip the "+"

        Case "!" ; Error -> Red-ish
;~          $iBgColor = 0xF8D7DA
            $iBgColor = 0x5C1D24
            $sStr = StringTrimLeft($sStr, 1) ; Strip the "!"

        Case ">", "-" ; Warning/Info -> Yellow/Orange-ish
;~          $iBgColor = 0xFFF3CD
            $iBgColor = 0x5C4308
            $sStr = StringTrimLeft($sStr, 1) ; Strip the symbol

        Case Else
;~          $iBgColor = 0x212529
            $iBgColor = 0x121212
    EndSwitch

    GUICtrlSetBkColor(GUICtrlCreateListViewItem($sTime & "|" & StringStripWS($sStr, 1), $g_idListView), $iBgColor)

    ; Auto-scroll to the bottom
    GUICtrlSendMsg($g_idListView, $LVM_ENSUREVISIBLE, GUICtrlSendMsg($g_idListView, $LVM_GETITEMCOUNT, 0, 0) - 1, 0)
EndFunc   ;==>_ConsoleListviewWrite

Func _GUI_Create()
    Local $iFormW = 600, $iFormH = 400
    $g_hGUI = _HiDPI_GUICreate("Bluetooth Monitor", $iFormW, $iFormH, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX, $WS_THICKFRAME, $WS_TABSTOP))
    GUIRegisterMsg($WM_DEVICECHANGE, "WM_DEVICECHANGE_Handler")
    $g_idListView = _HiDPI_GUICtrlCreateListView("Time|Message", 0, 0, $iFormW, $iFormH, -1, BitOR($LVS_EX_FULLROWSELECT, $WS_VSCROLL))
    GUICtrlSetResizing(-1, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKBOTTOM)
    GUICtrlSendMsg($g_idListView, $LVM_SETCOLUMNWIDTH, 0, _HiDpi_CtrlAdjRatio(80))
    GUICtrlSendMsg($g_idListView, $LVM_SETCOLUMNWIDTH, 1, @DesktopWidth)
    _GUIDarkTheme_ApplyDark($g_hGUI)
    GUISetState(@SW_SHOW)
EndFunc   ;==>_GUI_Create

Func _Reg_DetailedDeviceNotifications()

    ; Convert the Bluetooth Device Class GUID into a binary structure.
    ; GUID for Bluetooth Devices: {0850302A-B344-4FDA-9BE9-90576B8D46F0}
    Local $sGUID = "{0850302A-B344-4FDA-9BE9-90576B8D46F0}"
    Local $tGUID = DllStructCreate("byte[16]")
    DllCall("ole32.dll", "hresult", "CLSIDFromString", "wstr", $sGUID, "struct*", $tGUID)

    ; Create the DEV_BROADCAST_DEVICEINTERFACE structure for the registration request.
    ; Note: We only need Name[1] here because we are just sending the header to Windows, not reading from it yet.
    Local $tDevInterface = DllStructCreate("dword Size; dword DeviceType; dword Reserved; byte ClassGuid[16]; wchar Name[1]")
    DllStructSetData($tDevInterface, "Size", DllStructGetSize($tDevInterface))
    DllStructSetData($tDevInterface, "DeviceType", $DBT_DEVTYP_DEVICEINTERFACE)
    DllStructSetData($tDevInterface, "ClassGuid", DllStructGetData($tGUID, 1))

    Local $aRet = DllCall("user32.dll", "ptr", "RegisterDeviceNotificationW", "hwnd", $g_hGUI, "struct*", $tDevInterface, "dword", 4) ; 0) ; ; 0x00000004 is DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
    If @error Or Not IsArray($aRet) Or Not $aRet[0] Then
        MsgBox(16, "Error", "Failed to register for detailed device notifications.")
        Exit
    EndIf

    $g_hDeviceNotify = $aRet[0]
    OnAutoItExitRegister("_Cleanup_DeviceNotification")
EndFunc   ;==>_Reg_DetailedDeviceNotifications

Func _Cleanup_DeviceNotification()
    ; Check if the handle exists before attempting to unregister it
    If IsDeclared("g_hDeviceNotify") And $g_hDeviceNotify Then
        _ConsoleListviewWrite("--> unregistering device notification hook" & @CRLF)
        DllCall("user32.dll", "bool", "UnregisterDeviceNotification", "ptr", $g_hDeviceNotify)
        $g_hDeviceNotify = 0 ; Clear the handle
    EndIf
    If IsHWnd($g_hGUI) Then
        If GUIDelete($g_hGUI) Then $g_hGUI = 0
    EndIf
EndFunc   ;==>_Cleanup_DeviceNotification

 

Edited by argumentum

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...