Heheheh. Blazingly fast dynamic icon generation, anyone?
Code:
#NoEnv
backclr = 0x7F000000
marginx = 1
marginy = 1
bars = 3
barpadding = 1
pct1 = 25
pct2 = 50
pct3 = 75
clr1 = 0x0000FF
clr2 = 0x00FF00
clr3 = 0xFF0000
width = 16
height = 16
display_gui = 1
if display_gui
{
Gui, Add, Picture, hwndpic, shell32.dll
Gui, Show, % "W" (width<100 ? 100 : width+20) "H" height+10
}
Loop { ; Test loop and random numbers to demonstrate speed!!!.
Loop, 3
Random, pct%A_Index%, 0, 100
if !(hdcScreen := DllCall("GetDC","uint",0))
return
VarSetCapacity(buf,40,0), NumPut(40,buf), NumPut(1,buf,12,"ushort")
NumPut(width,buf,4), NumPut(height,buf,8), NumPut(32,buf,14,"ushort")
; Note that a compatible bitmap's format depends on the current display settings.
; Changing the display depth after creating the icon may cause colour loss.
;if hbm := DllCall("CreateCompatibleBitmap","uint",hdcScreen,"int",width,"int",height)
if hbm := DllCall("CreateDIBSection","uint",hdcScreen,"uint",&buf,"uint",0
,"uint*",pBits,"uint",0,"uint",0)
{
if hdc := DllCall("CreateCompatibleDC","uint",hdcScreen)
{
; Select the bitmap into a device context to draw on it.
; Note that the previous bitmap should always be reselected afterwards.
if hbm_old := DllCall("SelectObject","uint",hdc,"uint",hbm)
{
; Calculate the (maximum) bar size.
barwidth := floor((width-marginx*2-(bars-1)*barpadding)/bars)
barheight := height-marginy*2
; Draw the bars!
x := marginx
Loop, %bars%
{
RECT(rc
, x
, marginy+barheight*(pct%A_Index%/100)
, x+barwidth
, height-marginy)
hbr := DllCall("CreateSolidBrush","uint",clr%A_Index%)
DllCall("FillRect","uint",hdc,"uint",&rc,"uint",hbr)
DllCall("DeleteObject","uint",hbr), hbr:=0
x += barwidth+barpadding
}
DllCall("SelectObject","uint",hdc,"uint",hbm_old)
}
; Since GDI doesn't support alpha-blending, we must manually set the
; pixels to our background colour. We must also set the alpha component
; of each bar pixel to 255, otherwise bars become mostly invisible.
offset = 0
Loop, %height% {
Loop, %width% {
px := NumGet(pBits+offset)
NumPut(px ? 255<<24|px : backclr, pBits+offset)
offset += 4
}
}
VarSetCapacity(mask,64,0)
hbm_mask := DllCall("CreateBitmap","int",width,"int",height,"uint",1,"uint",1,"uint",&mask)
DllCall("DeleteDC","uint",hdc)
}
}
DllCall("ReleaseDC","uint",0,"uint",hdcScreen)
hicon_old := hicon
VarSetCapacity(ii,20,0), NumPut(1,ii,0), NumPut(hbm,ii,16), NumPut(hbm_mask,ii,12)
hicon := DllCall("CreateIconIndirect","uint",&ii)
; "The system copies the bitmaps in the ICONINFO structure before creating the icon or cursor."
DllCall("DeleteObject","uint",hbm)
DllCall("DeleteObject","uint",hbm_mask)
; Prepare the NOTIFYICONDATA struct.
VarSetCapacity(nid,444,0), NumPut(444,nid)
; Set nid.hWnd to the script's main window.
DetectHiddenWindows, On
Process, Exist
NumPut(WinExist("ahk_class AutoHotkey ahk_pid " ErrorLevel), nid,4)
DetectHiddenWindows, Off
; Set nid.uID to AHK_NOTIFYICON. hWnd and uID identify the tray icon.
NumPut(1028,nid,8)
; Set nid.hIcon=hicon and nid.uFlags=NIF_ICON.
NumPut(hicon,nid,20), NumPut(0x2,nid,12)
; Set the new icon. (NIM_MODIFY=0x1)
DllCall("shell32\Shell_NotifyIcon","uint",0x1,"uint",&nid)
if display_gui
SendMessage, 0x170, hicon,,, ahk_id %pic%
if hicon_old
DllCall("DestroyIcon","uint",hicon)
} ; end test loop
return
GuiClose:
ExitApp
; helper function for readability
RECT(ByRef rc, left, top, right, bottom) {
VarSetCapacity(rc,16), NumPut(bottom,NumPut(right,NumPut(top,NumPut(left,rc,0))))
}
It needs a bit of cleaning up, but hopefully you can make sense of it. It isn't really meant to be a reusable function. You can probably tell that I hacked the loop and DestroyIcon call in at the last moment...
Note that it might not work correctly on older versions of Windows (which don't support 32-bit tray icons.)

Supposedly the icon should be 4-bit on Windows 9x/NT4, and no higher than the current display depth on Win2k.
If you'd like to use any or all of it in your script, feel free to do so.
majkinetor wrote:
I am currently working on Shell_IconNotify encapsulation. I succeded to add arbitrary number of tray icons in the tray menu, but still working on interface and APIs.
Sounds good. Modifying the existing icon is easy, but you see the default green icon for a (very!) brief moment as the script starts up.
