Jump to content

Set the tray icon as a HIcon


Mat
 Share

Recommended Posts

So I wanted to have my program display a number in the system tray, and decided to do it programatically (e.g. not 99 icons). Reading through MSDN resulted in me writing my own code to do everything myself, and menus were a pain. Ideally I wanted to use all AutoIt tray functions BUT use a HIcon rather than a file path. Impossible eh? Not with the AutoIt source code!! All you need to do is know the following:

Global Const $AUT_WM_NOTIFYICON = $WM_USER + 1
Global Const $AUT_NOTIFY_ICON_ID = 1
Global $TRAY_ICON_GUI = WinGetHandle(AutoItWinGetTitle())

And then you have everything you need to use the Shell_NotifyIcon function as if you were AutoIt:

Func _Tray_SetHIcon($hIcon)
    Local $tNOTIFY = DllStructCreate($tagNOTIFYICONDATA)
    DllStructSetData($tNOTIFY, "Size", DllStructGetSize($tNOTIFY))
    DllStructSetData($tNOTIFY, "Wnd", $TRAY_ICON_GUI)
    DllStructSetData($tNOTIFY, "ID", $AUT_NOTIFY_ICON_ID)
    DllStructSetData($tNOTIFY, "Icon", $hIcon)
    DllStructSetData($tNOTIFY, "Flags", BitOR($NIF_ICON, $NIF_MESSAGE))
    DllStructSetData($tNOTIFY, "CallbackMessage", $AUT_WM_NOTIFYICON)

    Local $aRet = DllCall("shell32.dll", "int", "Shell_NotifyIconW", "dword", $NIM_MODIFY, "ptr", DllStructGetPtr($tNOTIFY))
    If (@error) Then Return SetError(1, 0, 0)

    Return $aRet[0] <> 0
EndFunc   ;==>_Tray_SetHIcon

MWAHAHAHAHA

_GDIPlus_BitmapCreateHICONFromBitmap which strangely does not appear in GDIPlus.au3 means you can use a bitmap:

Func _GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $hIcon = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Or Not $hIcon[0] Then Return SetError(@error, @extended, $hIcon[2])

    Return $hIcon[2]
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap

NB: Still needs GDIPlus.au3 to be included and used as normal (_GDIPlus_Startup etc)

Then all you need is some simple drawing code:

_GDIPlus_Startup()

Local $hBitmap, $hImage, $hGraphic, $hIcon

$hBitmap = _WinAPI_CreateSolidBitmap(0, 0xFFFFFF, 16, 16)
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage)

For $i = 99 To 1 Step -1
    _GDIPlus_GraphicsClear($hGraphic, 0xFFFFFFFF)
    _GDIPlus_GraphicsDrawString($hGraphic, $i, (StringLen($i) - 2) * - 3, 2, "Arial", 8)

    $hIcon = _GDIPlus_BitmapCreateHICONFromBitmap($hImage)
    _Tray_SetHIcon($hIcon)
    _WinAPI_DestroyIcon($hIcon)

    Sleep(200)
Next

_GDIPlus_ImageDispose($hImage)
_GDIPlus_GraphicsDispose($hGraphic)
_WinAPI_DeleteObject($hBitmap)

_GDIPlus_Shutdown()

complete code:

#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>

Global Const $tagNOTIFYICONDATA = "dword Size;" & _
        "hwnd Wnd;" & _
        "uint ID;" & _
        "uint Flags;" & _
        "uint CallbackMessage;" & _
        "ptr Icon;" & _
        "wchar Tip[128];" & _
        "dword State;" & _
        "dword StateMask;" & _
        "wchar Info[256];" & _
        "uint Timeout;" & _
        "wchar InfoTitle[64];" & _
        "dword InfoFlags;" & _
        "dword Data1;word Data2;word Data3;byte Data4[8];" & _
        "ptr BalloonIcon"

Global Const $NIM_ADD = 0
Global Const $NIM_MODIFY = 1

Global Const $NIF_MESSAGE = 1
Global Const $NIF_ICON = 2

Global Const $AUT_WM_NOTIFYICON = $WM_USER + 1 ; Application.h
Global Const $AUT_NOTIFY_ICON_ID = 1 ; Application.h

AutoItWinSetTitle("this is a test 123")
Global $TRAY_ICON_GUI = WinGetHandle(AutoItWinGetTitle()) ; Internal AutoIt GUI

;;;

_GDIPlus_Startup()

Local $hBitmap, $hImage, $hGraphic, $hIcon

$hBitmap = _WinAPI_CreateSolidBitmap(0, 0xFFFFFF, 16, 16)
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage)

For $i = 99 To 1 Step -1
    _GDIPlus_GraphicsClear($hGraphic, 0xFFFFFFFF)
    _GDIPlus_GraphicsDrawString($hGraphic, $i, (StringLen($i) - 2) * - 3, 2, "Arial", 8)

    $hIcon = _GDIPlus_BitmapCreateHICONFromBitmap($hImage)
    _Tray_SetHIcon($hIcon)
    _WinAPI_DestroyIcon($hIcon)

    Sleep(200)
Next

_GDIPlus_ImageDispose($hImage)
_GDIPlus_GraphicsDispose($hGraphic)
_WinAPI_DeleteObject($hBitmap)

_GDIPlus_Shutdown()

;;;

Func _Tray_SetHIcon($hIcon)
    Local $tNOTIFY = DllStructCreate($tagNOTIFYICONDATA)
    DllStructSetData($tNOTIFY, "Size", DllStructGetSize($tNOTIFY))
    DllStructSetData($tNOTIFY, "Wnd", $TRAY_ICON_GUI)
    DllStructSetData($tNOTIFY, "ID", $AUT_NOTIFY_ICON_ID)
    DllStructSetData($tNOTIFY, "Icon", $hIcon)
    DllStructSetData($tNOTIFY, "Flags", BitOR($NIF_ICON, $NIF_MESSAGE))
    DllStructSetData($tNOTIFY, "CallbackMessage", $AUT_WM_NOTIFYICON)

    Local $aRet = DllCall("shell32.dll", "int", "Shell_NotifyIconW", "dword", $NIM_MODIFY, "ptr", DllStructGetPtr($tNOTIFY))
    If (@error) Then Return SetError(1, 0, 0)

    Return $aRet[0] <> 0
EndFunc   ;==>_Tray_SetHIcon

Func _GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $hIcon = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Or Not $hIcon[0] Then Return SetError(@error, @extended, $hIcon[2])

    Return $hIcon[2]
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap

I love AutoIt.

Link to comment
Share on other sites

Very nicely done..

I will have to rewrite my scripts to use this function....See my previous hack attempt at the same.

Wow... That's some complex but very useful code there, saving an icon could be very useful. I'm surprised I missed out on _GDIPlus_BitmapCreateHICONFromBitmap cause I searched. That could have saved me a bit of time.

Any idea about transparency? Thats the only thing missing.

Link to comment
Share on other sites

Link to comment
Share on other sites

Very nice!

I see that smashley's HICON to ICO helped you. :P Sorry you were not the one who asked for HIcons... :mellow:

BR,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Hi there

Think this might be the function for transparency you are looking for. Got it somewhere on the forum a while back, maybe someone will step forward to take credit. (probably Malkey)

#include <GDIPlus.au3>

#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>

Global Const $tagNOTIFYICONDATA = "dword Size;" & _
        "hwnd Wnd;" & _
        "uint ID;" & _
        "uint Flags;" & _
        "uint CallbackMessage;" & _
        "ptr Icon;" & _
        "wchar Tip[128];" & _
        "dword State;" & _
        "dword StateMask;" & _
        "wchar Info[256];" & _
        "uint Timeout;" & _
        "wchar InfoTitle[64];" & _
        "dword InfoFlags;" & _
        "dword Data1;word Data2;word Data3;byte Data4[8];" & _
        "ptr BalloonIcon"

Global Const $NIM_ADD = 0
Global Const $NIM_MODIFY = 1

Global Const $NIF_MESSAGE = 1
Global Const $NIF_ICON = 2

Global Const $AUT_WM_NOTIFYICON = $WM_USER + 1 ; Application.h
Global Const $AUT_NOTIFY_ICON_ID = 1 ; Application.h

AutoItWinSetTitle("this is a test 123")
Global $TRAY_ICON_GUI = WinGetHandle(AutoItWinGetTitle()) ; Internal AutoIt GUI

;;;

_GDIPlus_Startup()

Local $hBitmap, $hImage, $hGraphic, $hIcon

$hBitmap = _WinAPI_CreateSolidBitmap(0, 0xFFFFFF, 16, 16)
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage)

$sImageIn = @ScriptDir&"\test.ico"

$hImage=_ImageToTransPNG($sImageIn,5,5)

    $hIcon = _GDIPlus_BitmapCreateHICONFromBitmap($hImage)
    _Tray_SetHIcon($hIcon)
    _WinAPI_DestroyIcon($hIcon)

    Sleep(5000)
;Next

_GDIPlus_ImageDispose($hImage)
_GDIPlus_GraphicsDispose($hGraphic)
_WinAPI_DeleteObject($hBitmap)

_GDIPlus_Shutdown()

;;;

Func _Tray_SetHIcon($hIcon)
    Local $tNOTIFY = DllStructCreate($tagNOTIFYICONDATA)
    DllStructSetData($tNOTIFY, "Size", DllStructGetSize($tNOTIFY))
    DllStructSetData($tNOTIFY, "Wnd", $TRAY_ICON_GUI)
    DllStructSetData($tNOTIFY, "ID", $AUT_NOTIFY_ICON_ID)
    DllStructSetData($tNOTIFY, "Icon", $hIcon)
    DllStructSetData($tNOTIFY, "Flags", BitOR($NIF_ICON, $NIF_MESSAGE))
    DllStructSetData($tNOTIFY, "CallbackMessage", $AUT_WM_NOTIFYICON)

    Local $aRet = DllCall("shell32.dll", "int", "Shell_NotifyIconW", "dword", $NIM_MODIFY, "ptr", DllStructGetPtr($tNOTIFY))
    If (@error) Then Return SetError(1, 0, 0)

    Return $aRet[0] <> 0
EndFunc   ;==>_Tray_SetHIcon

Func _GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $hIcon = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Or Not $hIcon[0] Then Return SetError(@error, @extended, $hIcon[2])

    Return $hIcon[2]
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap


Func _ImageToTransPNG($sInFile, $iXPixel = 0, $iYPixel = 0)
    Local $hImage, $iW, $iH, $iFirstPixel, $iTransPixel, $tBitmapData, $iStride, $iScan0, $iX, $iY, $tPixel, $iPixel
    Local $v_BufferA, $AllPixels, $sREResult1, $sPix

    $hImage = _GDIPlus_ImageLoadFromFile($sInFile)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)

    ;=> Start Work araound For XP, GDIPBitmapLockBits() seem to hard crash autoit When using images that are less then 24bpp
    ; If your using Vista or Newer OS then this won't be called or needed.
    If StringInStr('"WIN_2003","WIN_XP","WIN_2000"', @OSVersion) Then
        Local $aRet, $hBmp, $hBitmap, $hGraphic
        $aRet = _GDIPlus_ImageGetPixelFormat($hImage)
        If Int(StringRegExpReplace($aRet[1], "\D+", "")) < 24 Then
            $hBmp = _WinAPI_CreateBitmap($iW, $iH, 1, 32)
            $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp)
            _WinAPI_DeleteObject($hBmp)
            $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBitmap)
            _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_ImageDispose($hImage)          
            $hImage = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, $iW, $iH, $GDIP_PXF32ARGB)
            _GDIPlus_BitmapDispose($hBitmap)
        EndIf
    EndIf
    ;=> End Work around

    $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)
    $iStride = DllStructGetData($tBitmapData, "stride")
    $iScan0 = DllStructGetData($tBitmapData, "Scan0")

    ; Get Pixel colour to be transparent at coordinates ($iXPixel, $iYPixel).
    $tPixel = DllStructCreate("int", $iScan0 + ($iYPixel * $iStride) + ($iXPixel * 4))
    $iFirstPixel = DllStructGetData($tPixel, 1)
    $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF)


    $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1")
    ConsoleWrite($iFirstPixel & @LF)
    $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00"
    $v_BufferA = DllStructCreate("byte[" & $iH * $iW * 4 & "]", $iScan0) ; Create DLL structure for all pixels
    $AllPixels = DllStructGetData($v_BufferA, 1)
    $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ")
    $sPix = "0x" & StringStripWS(StringRegExpReplace($sREResult1, "(" & $iFirstPixel & ")", $iTransPixel), 8)
    $AllPixels = DllStructSetData($v_BufferA, 1, $sPix)

    _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
  ;  _GDIPlus_ImageSaveToFileEx($hImage, $sOutFile, _GDIPlus_EncodersGetCLSID("PNG"))
 ;   _GDIPlus_ImageDispose($hImage)

    Return $hImage
EndFunc   ;==>_ImageToTransPNG

Picea892

test.ico

Edited by picea892
Link to comment
Share on other sites

Hi there

Think this might be the function for transparency you are looking for. Got it somewhere on the forum a while back, maybe someone will step forward to take credit. (probably Malkey)

#include <GDIPlus.au3>

#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>

Global Const $tagNOTIFYICONDATA = "dword Size;" & _
        "hwnd Wnd;" & _
        "uint ID;" & _
        "uint Flags;" & _
        "uint CallbackMessage;" & _
        "ptr Icon;" & _
        "wchar Tip[128];" & _
        "dword State;" & _
        "dword StateMask;" & _
        "wchar Info[256];" & _
        "uint Timeout;" & _
        "wchar InfoTitle[64];" & _
        "dword InfoFlags;" & _
        "dword Data1;word Data2;word Data3;byte Data4[8];" & _
        "ptr BalloonIcon"

Global Const $NIM_ADD = 0
Global Const $NIM_MODIFY = 1

Global Const $NIF_MESSAGE = 1
Global Const $NIF_ICON = 2

Global Const $AUT_WM_NOTIFYICON = $WM_USER + 1 ; Application.h
Global Const $AUT_NOTIFY_ICON_ID = 1 ; Application.h

AutoItWinSetTitle("this is a test 123")
Global $TRAY_ICON_GUI = WinGetHandle(AutoItWinGetTitle()) ; Internal AutoIt GUI

;;;

_GDIPlus_Startup()

Local $hBitmap, $hImage, $hGraphic, $hIcon

$hBitmap = _WinAPI_CreateSolidBitmap(0, 0xFFFFFF, 16, 16)
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage)

$sImageIn = @ScriptDir&"\test.ico"

$hImage=_ImageToTransPNG($sImageIn,5,5)

    $hIcon = _GDIPlus_BitmapCreateHICONFromBitmap($hImage)
    _Tray_SetHIcon($hIcon)
    _WinAPI_DestroyIcon($hIcon)

    Sleep(5000)
;Next

_GDIPlus_ImageDispose($hImage)
_GDIPlus_GraphicsDispose($hGraphic)
_WinAPI_DeleteObject($hBitmap)

_GDIPlus_Shutdown()

;;;

Func _Tray_SetHIcon($hIcon)
    Local $tNOTIFY = DllStructCreate($tagNOTIFYICONDATA)
    DllStructSetData($tNOTIFY, "Size", DllStructGetSize($tNOTIFY))
    DllStructSetData($tNOTIFY, "Wnd", $TRAY_ICON_GUI)
    DllStructSetData($tNOTIFY, "ID", $AUT_NOTIFY_ICON_ID)
    DllStructSetData($tNOTIFY, "Icon", $hIcon)
    DllStructSetData($tNOTIFY, "Flags", BitOR($NIF_ICON, $NIF_MESSAGE))
    DllStructSetData($tNOTIFY, "CallbackMessage", $AUT_WM_NOTIFYICON)

    Local $aRet = DllCall("shell32.dll", "int", "Shell_NotifyIconW", "dword", $NIM_MODIFY, "ptr", DllStructGetPtr($tNOTIFY))
    If (@error) Then Return SetError(1, 0, 0)

    Return $aRet[0] <> 0
EndFunc   ;==>_Tray_SetHIcon

Func _GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $hIcon = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Or Not $hIcon[0] Then Return SetError(@error, @extended, $hIcon[2])

    Return $hIcon[2]
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap


Func _ImageToTransPNG($sInFile, $iXPixel = 0, $iYPixel = 0)
    Local $hImage, $iW, $iH, $iFirstPixel, $iTransPixel, $tBitmapData, $iStride, $iScan0, $iX, $iY, $tPixel, $iPixel
    Local $v_BufferA, $AllPixels, $sREResult1, $sPix

    $hImage = _GDIPlus_ImageLoadFromFile($sInFile)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)

    ;=> Start Work araound For XP, GDIPBitmapLockBits() seem to hard crash autoit When using images that are less then 24bpp
    ; If your using Vista or Newer OS then this won't be called or needed.
    If StringInStr('"WIN_2003","WIN_XP","WIN_2000"', @OSVersion) Then
        Local $aRet, $hBmp, $hBitmap, $hGraphic
        $aRet = _GDIPlus_ImageGetPixelFormat($hImage)
        If Int(StringRegExpReplace($aRet[1], "\D+", "")) < 24 Then
            $hBmp = _WinAPI_CreateBitmap($iW, $iH, 1, 32)
            $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp)
            _WinAPI_DeleteObject($hBmp)
            $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBitmap)
            _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_ImageDispose($hImage)          
            $hImage = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, $iW, $iH, $GDIP_PXF32ARGB)
            _GDIPlus_BitmapDispose($hBitmap)
        EndIf
    EndIf
    ;=> End Work around

    $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)
    $iStride = DllStructGetData($tBitmapData, "stride")
    $iScan0 = DllStructGetData($tBitmapData, "Scan0")

    ; Get Pixel colour to be transparent at coordinates ($iXPixel, $iYPixel).
    $tPixel = DllStructCreate("int", $iScan0 + ($iYPixel * $iStride) + ($iXPixel * 4))
    $iFirstPixel = DllStructGetData($tPixel, 1)
    $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF)


    $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1")
    ConsoleWrite($iFirstPixel & @LF)
    $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00"
    $v_BufferA = DllStructCreate("byte[" & $iH * $iW * 4 & "]", $iScan0) ; Create DLL structure for all pixels
    $AllPixels = DllStructGetData($v_BufferA, 1)
    $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ")
    $sPix = "0x" & StringStripWS(StringRegExpReplace($sREResult1, "(" & $iFirstPixel & ")", $iTransPixel), 8)
    $AllPixels = DllStructSetData($v_BufferA, 1, $sPix)

    _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
  ;  _GDIPlus_ImageSaveToFileEx($hImage, $sOutFile, _GDIPlus_EncodersGetCLSID("PNG"))
 ;   _GDIPlus_ImageDispose($hImage)

    Return $hImage
EndFunc   ;==>_ImageToTransPNG

Picea892

Sorry I haven't been here for a while... I am busy trying to get a variety of methods to work, but this looks promising.

Thanks

Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...