Jump to content
Sign in to follow this  
Mat

Set the tray icon as a HIcon

Recommended Posts

Mat

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.

Share this post


Link to post
Share on other sites
picea892

Very nicely done..

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

Share this post


Link to post
Share on other sites
Mat

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.

Share this post


Link to post
Share on other sites
Yashied

Share this post


Link to post
Share on other sites
UEZ

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Mat

_GDIPlus_ImageLoadFromFile(*.png) => _GDIPlus_BitmapCreateHICONFromBitmap() => HICON with Alpha

Is there a way to do it without files though??

Share this post


Link to post
Share on other sites
Yashied
picea892

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

Share this post


Link to post
Share on other sites
Mat

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

Share this post


Link to post
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
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.