seadoggie01 Posted 5 hours ago Posted 5 hours ago I'm trying to make a script that will add a secondary icon to the taskbar when I have unread emails. Outlook doesn't show this well and I sometimes miss emails for an hour or more. Currently, the script creates a GUI, draws a red circle with a black border, then draws some text on top of that. The number will eventually be the unread email count, but for testing it's just an incrementing number. That all works fine. The issue seems to be when I'm trying to convert the GDIPlus Graphic into a Icon to display in the taskbar. Instead of drawing the same circle with text over Outlook's icon, it draws a solid black square. According to MS's documentation, I need to pass a HICON (a handle to an icon?) to the function ITaskbarList3::SetOverlayIcon. I've tried a few different things, but here's the current code: expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WinAPIIcons.au3> ; #include <Taskbar.au3> ; A UDF I created for myself. Instead I extracted the necessary things to this file Global Const $__g_sCLSID_TaskbarList = "{56FDF344-FD6D-11D0-958A-006097C9A090}" Global Const $__g_sIID_ITaskbarList3 = "{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}" Global Const $__g_tagITaskbarList3 = _ "HrInit hresult();" & _ "AddTab hresult(hwnd);" & _ "DeleteTab hresult(hwnd);" & _ "ActivateTab hresult(hwnd);" & _ "SetActiveAlt hresult(hwnd);" & _ "MarkFullscreenWindow hresult(hwnd;boolean);" & _ "SetProgressValue hresult(hwnd;uint64;uint64);" & _ "SetProgressState hresult(hwnd;int);" & _ "RegisterTab hresult(hwnd;hwnd);" & _ "UnregisterTab hresult(hwnd);" & _ "SetTabOrder hresult(hwnd;hwnd);" & _ "SetTabActive hresult(hwnd;hwnd;dword);" & _ "ThumbBarAddButtons hresult(hwnd;uint;ptr);" & _ "ThumbBarUpdateButtons hresult(hwnd;uint;ptr);" & _ "ThumbBarSetImageList hresult(hwnd;ptr);" & _ "SetOverlayIcon hresult(hwnd;ptr;wstr);" & _ "SetThumbnailTooltip hresult(hwnd;wstr);" & _ "SetThumbnailClip hresult(hwnd;ptr);" Global $__g_iFontSize = 12 Main() Func Main() ; Create GUI Local $hGUI = GUICreate("GDI+", 400, 300) GUISetState(@SW_SHOW) Local $iX = 138, $iY = 108, $iWidth = 32, $iHeight = 32, $iBorder = 1 _GDIPlus_Startup() Local $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) Local $hTextBrush = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) Local $hFormat = _GDIPlus_StringFormatCreate() Local $hFamily = _GDIPlus_FontFamilyCreate("Arial") Local $hFont = _GDIPlus_FontCreate($hFamily, $__g_iFontSize) Local $tLayout = _GDIPlus_RectFCreate($iX + 2, $iY + 2, $iWidth, $iHeight - 5) Local $hBackgroundBrush = _GDIPlus_BrushCreateSolid(0xFFFF0000) Local $hPen = _GDIPlus_PenCreate(0xFF000000, $iBorder) Local $iIndex = 0 Local $hTimer = TimerInit() Local $oTB = _Taskbar_Init() Local $hBitmap, $hIcon ; Loop until the user exits. Do ; only update after 1 second If TimerDiff($hTimer) > 1000 Then If $iIndex > 0 Then _WinAPI_DestroyIcon($hIcon) _GDIPlus_BitmapDispose($hBitmap) EndIf ; Clear the graphics _GDIPlus_GraphicsClear($hGraphic, 0xFFFFFFFF) ; Draw a filled circle _GDIPlus_GraphicsFillEllipse($hGraphic, $iX, $iY, $iWidth, $iHeight, $hBackgroundBrush) ; Draw a border circle _GDIPlus_GraphicsDrawEllipse($hGraphic, $iX, $iY, $iWidth, $iHeight, $hPen) ; Draw the text in the circle DrawStringCentered($hGraphic, $iIndex, $hFont, $tLayout, $hFormat, $hTextBrush) ; Extract the graphic to a bitmap $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphic) If ErrMsg(_GDIPlus_BitmapCreateFromGraphics) Then Exit ; Convert the Bitmap into an icon $hIcon = _GDIPlus_HICONCreateFromBitmap($hBitmap) If ErrMsg(_GDIPlus_HICONCreateFromBitmap) Then Exit $hIcon = _WinAPI_Create32BitHICON($hIcon, true) If ErrMsg(_WinAPI_Create32BitHICON) Then Exit ; Add the icon to the window AddIconToWin("Inbox", $oTB, $hIcon) $iIndex += 1 if($iIndex > 99) Then $iIndex = 99 $hTimer = TimerInit() EndIf Until GUIGetMsg() = $GUI_EVENT_CLOSE ; Clean up resources _GDIPlus_FontDispose($hFont) _GDIPlus_PenDispose($hPen) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_BrushDispose($hTextBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() ; Clear the icon AddIconToWin("Inbox", $oTB, null) EndFunc Func DrawStringCentered($hGraphic, $iIndex, $hFont, $tLayout, $hFormat, $hTextBrush) ; Determine the width of the string Local $aInfo = _GDIPlus_GraphicsMeasureString($hGraphic, $iIndex, $hFont, $tLayout, $hFormat) Local $tIndex = $aInfo[0] ; Offset + Half of (Area's width - font's width) $tIndex.X = $tLayout.X + (($tLayout.Width - $tIndex.Width) / 2) ; Offset + Half of (Area's width - font's width) $tIndex.Y = $tLayout.Y + (($tLayout.Height - _GDIPlus_FontGetHeight($hFont, $hGraphic)) / 2) ; Finally, draw the string _GDIPlus_GraphicsDrawStringEx($hGraphic, $iIndex, $hFont, $tIndex, $hFormat, $hTextBrush) EndFunc Func AddIconToWin($sSearch, $oTB, $hIcon) Local $hWnd = WinGetHandle($sSearch) if ErrMsg(WinGetHandle) Then Exit _Taskbar_SetOverlayIcon($oTB, $hWnd, $hIcon, "Custom Icon") If ErrMsg(_Taskbar_SetOverlayIcon) Then Exit EndFunc Func AddIconToOutlook() Local $hWnd = WinGetHandle("Inbox") if ErrMsg(WinGetHandle) Then Exit Debug(WinGetTitle($hWnd)) Local $oTB = _Taskbar_Init() If ErrMsg(_Taskbar_Init) Then Exit Local $hIcon = _WinAPI_ShellExtractIcon(@SystemDir & "\shell32.dll", 109, 64, 64) If ErrMsg(_WinAPI_ShellExtractIcon) Then Exit _Taskbar_SetOverlayIcon($oTB, $hWnd, $hIcon, "No Entry") If ErrMsg(_Taskbar_SetOverlayIcon) Then Exit Debug("Should've set the icon now? I think?") EndFunc Func Debug($sMsg, $sPrefix = "+") ConsoleWrite($sPrefix & $sMsg & @CRLF) EndFunc Func ErrMsg($sMsg = "", $iError = @error, $iExtended = @extended, $iScriptLineNum = @ScriptLineNumber) Local $__g_bUsingVSCode = true ; If there is an error, then write the error message If $iError Then ; If we've used a Function as the message (it looks really nice when I do) then print the name of the function If IsFunc($sMsg) Then $sMsg = FuncName($sMsg) Local $sText = "" If StringInStr(@ScriptName, ".au3") Then If $__g_bUsingVSCode Then $sText = @ScriptFullPath & ":" & $iScriptLineNum & ":5 - See below for message" & @CRLF Else $sText = '"' & @ScriptFullPath & '" (' & $iScriptLineNum & ',5) : (See below for message)' & @CRLF EndIf EndIf If $iExtended <> 0 Then $sMsg = "Extended: " & $iExtended & " - " & $sMsg $sText &= "! Error: " & $iError & " - " & $sMsg Debug($sText, "") EndIf ; Preserve the error Return SetError($iError, $iExtended, $iError) EndFunc Func _Taskbar_Init() Local $oTB = ObjCreateInterface($__g_sCLSID_TaskbarList, $__g_sIID_ITaskbarList3, $__g_tagITaskbarList3) Local $oErrHnd = ObjEvent("AutoIt.Error", FuncName(__Taskbar_ErrorHandler)) $oTB.HrInit() If @error Then Return SetError(@error, @extended, False) Return $oTB EndFunc ;==>_Taskbar_Init ; These are icons added to your taskbar icon, showing status usually. Each window only gets 1. Set $hIcon to NULL to clear. ; (Win11) Teams uses this to show your status (busy, free, inactive) and Outlook uses it to show if you have an unread email ; Returns True on success, sets @error on failure Func _Taskbar_SetOverlayIcon(ByRef $oTB, $hWnd, $hIcon, $sAltText = "") Local $oErrHnd = ObjEvent("AutoIt.Error", FuncName(__Taskbar_ErrorHandler)) Local $vRet = $oTB.SetOverlayIcon($hWnd, $hIcon, $sAltText) If @error Then Return SetError(@error, @extended, False) If $vRet = 0 Then Return True Return SetError($vRet, 0, False) EndFunc ;==>_Taskbar_SetOverlayIcon Func __Taskbar_ErrorHandler() ConsoleWrite(@ScriptName & " (" & $oError.scriptline & ") : ==> COM Error intercepted !" & @CRLF & _ @TAB & "err.number is: " & @TAB & @TAB & "0x" & Hex($oError.number) & @CRLF & _ @TAB & "err.windescription:" & @TAB & $oError.windescription & @CRLF & _ @TAB & "err.description is: " & @TAB & $oError.description & @CRLF & _ @TAB & "err.source is: " & @TAB & @TAB & $oError.source & @CRLF & _ @TAB & "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _ @TAB & "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _ @TAB & "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _ @TAB & "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _ @TAB & "err.retcode is: " & @TAB & "0x" & Hex($oError.retcode) & @CRLF & @CRLF) EndFunc I think I might be doing something wrong when I'm converting Graphics > Bitmap > Icon > Icon, but I'm not sure what to try instead. I'm also doing something wrong when I'm centering the string in the circle, but I can figure that out if I spend a little more time on it. All my code provided is Public Domain... but it may not work. Use it, change it, break it, whatever you want. Spoiler My Humble Contributions:Personal Function Documentation - A personal HelpFile for your functionsAcro.au3 UDF - Automating Acrobat ProToDo Finder - Find #ToDo: lines in your scriptsUI-SimpleWrappers UDF - Use UI Automation more Simply-erKeePass UDF - Automate KeePass, a password managerInputBoxes - Simple Input boxes for various variable types
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