Page 1 of 1

Unable To Use Small Icons In Listview!

Posted: 22 Mar 2015, 22:46
by ToonyTom
I'm trying to create my own replacement for the system tray using the TrayIcon Library. So far, adding icons works ok, but nothing shows up if I do LV_SetImageList(il,1).
If I useLV_SetImageList(il,0) the icons show up, but since LV_SetImageList is set to large, you can't really click and select anything accurately. :think:
I've also played around with LVM_SETICONSPACING(lvh,18,18) without much success. I really need to use small icons and not large ones.

Is there a simple workaround for this?
Here's my code:

Code: Select all

LVS_AUTOARRANGE:=0x100
LVS_NOSCROLL:=0x2000
LVS_ALIGNLEFT:=0x800

ops=
(Join%a_space%
+%LVS_AUTOARRANGE%
+%LVS_NOSCROLL%
-altsubmit
-multi
-IconSmall
+icon
)

gui,add,listview,x0 y0 w100 h100 vlv HWNDlvh +%ops% ,things
il:=IL_Create(1,1,0) ;0=small, 1=large
LV_SetImageList(il,0) ;0=large, 1=small
LVM_SETICONSPACING(lvh,18,18)

o:=TrayIcon_GetInfo()
loop % o.MaxIndex()
{
	hicon:=o[a_index].hIcon
	inum := DllCall("ImageList_ReplaceIcon", "ptr", il, "int", -1, "ptr", hIcon) + 1
	DllCall("DestroyIcon", "ptr", hIcon)
	LV_Add("icon" inum)
}
gui +resize 
gui,show
return



guisize:
GuiControl,move,lv,% "w" a_guiwidth " h" a_guiheight
return

LVM_SETICONSPACING(HLV,CX,CY) {
	 LVM_FIRST:= 0x1000
	 LVM_SETICONSPACING:= LVM_FIRST + 53
   SendMessage,LVM_SETICONSPACING, 0, % (CX & 0xFFFF) | ((CY & 0xFFFF) << 16), , ahk_id %HLV%
   Return True
}


; ----------------------------------------------------------------------------------------------------------------------
; Name ..........: TrayIcon library
; Description ...: Provide some useful functions to deal with Tray icons.
; AHK Version ...: AHK_L 1.1.13.01 x32/64 Unicode
; Original Author: Sean (http://goo.gl/dh0xIX) (http://www.autohotkey.com/forum/viewtopic.php?t=17314)
; Update Author .: Cyruz (http://ciroprincipe.info) (http://ahkscript.org/boards/viewtopic.php?f=6&t=1229)
; Mod Author ....: Fanatic Guru
; License .......: WTFPL - http://www.wtfpl.net/txt/copying/
; Version Date...: 2014 - 01 - 16
; Note ..........: Many people have updated Sean's original work including me but Cyruz's version seemed the most straight
; ...............: forward update for 64 bit so I adapted it with some of the features from my Fanatic Guru version.
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; Function ......: TrayIcon_GetInfo
; Description ...: Get a series of useful information about tray icons.
; Parameters ....: sExeName  - The exe for which we are searching the tray icon data. Leave it empty to receive data for
; ...............:             all tray icons.
; Return ........: oTrayIcon_GetInfo - An array of objects containing tray icons data. Any entry is structured like this:
; ...............:             oTrayIcon_GetInfo[A_Index].idx     - 0 based tray icon index.
; ...............:             oTrayIcon_GetInfo[A_Index].cmdID   - Command identifier associated with the button.
; ...............:             oTrayIcon_GetInfo[A_Index].pID     - Process ID.
; ...............:             oTrayIcon_GetInfo[A_Index].uID     - Application defined identifier for the icon.
; ...............:             oTrayIcon_GetInfo[A_Index].msgID   - Application defined callback message.
; ...............:             oTrayIcon_GetInfo[A_Index].hIcon   - Handle to the tray icon.
; ...............:             oTrayIcon_GetInfo[A_Index].hWnd    - Window handle.
; ...............:             oTrayIcon_GetInfo[A_Index].Class   - Window class.
; ...............:             oTrayIcon_GetInfo[A_Index].Process - Process executable.
; ...............:             oTrayIcon_GetInfo[A_Index].Tray    - Tray Type (Shell_TrayWnd or NotifyIconOverflowWindow).
; ...............:             oTrayIcon_GetInfo[A_Index].tooltip - Tray icon tooltip.
; Info ..........: TB_BUTTONCOUNT message - http://goo.gl/DVxpsg
; ...............: TB_GETBUTTON message   - http://goo.gl/2oiOsl
; ...............: TBBUTTON structure     - http://goo.gl/EIE21Z
; ----------------------------------------------------------------------------------------------------------------------

TrayIcon_GetInfo(sExeName := "")
{
    Setting_A_DetectHiddenWindows := A_DetectHiddenWindows
    DetectHiddenWindows, On
    oTrayIcon_GetInfo := {}
    For key, sTray in ["Shell_TrayWnd","NotifyIconOverflowWindow"]
    {
        idxTB := TrayIcon_GetTrayBar()
        WinGet, pidTaskbar, PID, ahk_class %sTray%

        hProc := DllCall("OpenProcess", UInt, 0x38, Int, 0, UInt, pidTaskbar)
        pRB   := DllCall("VirtualAllocEx", Ptr, hProc, Ptr, 0, UInt, 20, UInt, 0x1000, UInt, 0x4)

        SendMessage, 0x418, 0, 0, ToolbarWindow32%idxTB%, ahk_class %sTray%   ; TB_BUTTONCOUNT

        szBtn := VarSetCapacity(btn, (A_Is64bitOS ? 32 : 24))
        szNfo := VarSetCapacity(nfo, (A_Is64bitOS ? 32 : 24))
        szTip := VarSetCapacity(tip, 128 * 2)

        Loop, %ErrorLevel%
        {
            SendMessage, 0x417, A_Index - 1, pRB, ToolbarWindow32%idxTB%, ahk_class %sTray%   ; TB_GETBUTTON
            DllCall("ReadProcessMemory", Ptr, hProc, Ptr, pRB, Ptr, &btn, UInt, szBtn, UInt, 0)

            iBitmap := NumGet(btn, 0)
            cmdID   := NumGet(btn, 4)
            statyle := NumGet(btn, 8)
            dwData  := NumGet(btn, (A_Is64bitOS ? 16 : 12))
            iString := NumGet(btn, (A_Is64bitOS ? 24 : 16))

            DllCall("ReadProcessMemory", Ptr, hProc, Ptr, dwData, Ptr, &nfo, UInt, szNfo, UInt, 0)

            hWnd  := NumGet(nfo, 0)
            uID   := NumGet(nfo, (A_Is64bitOS ? 8 : 4))
            msgID := NumGet(nfo, (A_Is64bitOS ? 12 : 8))
            hIcon := NumGet(nfo, (A_Is64bitOS ? 24 : 20))

            WinGet, pID, PID, ahk_id %hWnd%
            WinGet, sProcess, ProcessName, ahk_id %hWnd%
            WinGetClass, sClass, ahk_id %hWnd%

            If !sExeName || (sExeName = sProcess) || (sExeName = pID)
            {
                DllCall("ReadProcessMemory", Ptr, hProc, Ptr, iString, Ptr, &tip, UInt, szTip, UInt, 0)
                Index := (oTrayIcon_GetInfo.MaxIndex()>0 ? oTrayIcon_GetInfo.MaxIndex()+1 : 1)
                oTrayIcon_GetInfo[Index,"idx"]     := A_Index - 1
                oTrayIcon_GetInfo[Index,"cmdID"]   := cmdID
                oTrayIcon_GetInfo[Index,"pID"]     := pID
                oTrayIcon_GetInfo[Index,"uID"]     := uID
                oTrayIcon_GetInfo[Index,"msgID"]   := msgID
                oTrayIcon_GetInfo[Index,"hIcon"]   := hIcon
                oTrayIcon_GetInfo[Index,"hWnd"]    := hWnd
                oTrayIcon_GetInfo[Index,"Class"]   := sClass
                oTrayIcon_GetInfo[Index,"Process"] := sProcess
                oTrayIcon_GetInfo[Index,"Tooltip"] := StrGet(&tip, "UTF-16")
                oTrayIcon_GetInfo[Index,"Tray"]    := sTray
            }
        }
        DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pProc, "Uint", 0, "Uint", 0x8000)
        DllCall("CloseHandle", "Uint", hProc)
    }
    DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
    Return oTrayIcon_GetInfo
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Hide
; Description ..: Hide or unhide a tray icon.
; Parameters ...: cmdID - Command identifier associated with the button.
; ..............: bHide - True for hide, False for unhide.
; ..............: sTray - 1 or Shell_TrayWnd || 0 or NotifyIconOverflowWindow.
; Info .........: TB_HIDEBUTTON message - http://goo.gl/oelsAa
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Hide(cmdID, sTray := "Shell_TrayWnd", bHide:=True)
{
    (sTray == 0 ? sTray := "NotifyIconOverflowWindow" : sTray == 1 ? sTray := "Shell_TrayWnd" : )
    Setting_A_DetectHiddenWindows := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x404, cmdID, bHide, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_HIDEBUTTON
    SendMessage, 0x1A, 0, 0, , ahk_class %sTray%
    DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Delete
; Description ..: Delete a tray icon.
; Parameters ...: idx - 0 based tray icon index.
; ..............: sTray - 1 or Shell_TrayWnd || 0 or NotifyIconOverflowWindow.
; Info .........: TB_DELETEBUTTON message - http://goo.gl/L0pY4R
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Delete(idx, sTray := "Shell_TrayWnd")
{
    (sTray == 0 ? sTray := "NotifyIconOverflowWindow" : sTray == 1 ? sTray := "Shell_TrayWnd" : )
    Setting_A_DetectHiddenWindows := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x416, idx, 0, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_DELETEBUTTON
    SendMessage, 0x1A, 0, 0, , ahk_class %sTray%
    DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Remove
; Description ..: Remove a tray icon.
; Parameters ...: hWnd, uID.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Remove(hWnd, uID)
{
        NumPut(VarSetCapacity(NID,(A_IsUnicode ? 2 : 1) * 384 + A_PtrSize * 5 + 40,0), NID)
        NumPut(hWnd , NID, (A_PtrSize == 4 ? 4 : 8 ))
        NumPut(uID  , NID, (A_PtrSize == 4 ? 8  : 16 ))
        Return DllCall("shell32\Shell_NotifyIcon", "Uint", 0x2, "Uint", &NID)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Move
; Description ..: Move a tray icon.
; Parameters ...: idxOld - 0 based index of the tray icon to move.
; ..............: idxNew - 0 based index where to move the tray icon.
; ..............: sTray - 1 or Shell_TrayWnd || 0 or NotifyIconOverflowWindow.
; Info .........: TB_MOVEBUTTON message - http://goo.gl/1F6wPw
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Move(idxOld, idxNew, sTray := "Shell_TrayWnd")
{
    (sTray == 0 ? sTray := "NotifyIconOverflowWindow" : sTray == 1 ? sTray := "Shell_TrayWnd" : )
    Setting_A_DetectHiddenWindows := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x452, idxOld, idxNew, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_MOVEBUTTON
    DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetTrayBar
; Description ..: Get the tray icon handle.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetTrayBar()
{
    Setting_A_DetectHiddenWindows := A_DetectHiddenWindows
    DetectHiddenWindows, On
    WinGet, ControlList, ControlList, ahk_class Shell_TrayWnd
    RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB)
    Loop, %nTB%
    {
        ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
        hParent := DllCall( "GetParent", Ptr, hWnd )
        WinGetClass, sClass, ahk_id %hParent%
        If (sClass <> "SysPager")
            Continue
        idxTB := A_Index
        Break
    }
    DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
    Return  idxTB
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetHotItem
; Description ..: Get the index of tray's hot item.
; Info .........: TB_GETHOTITEM message - http://goo.gl/g70qO2
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetHotItem()
{
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x447, 0, 0, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd ; TB_GETHOTITEM
    Return ErrorLevel << 32 >> 32
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Button
; Description ..: Simulate mouse button click on a tray icon.
; Parameters ...: sExeName - Executable Process Name of tray icon.
; ..............: sButton  - Mouse button to simulate (L, M, R).
; ..............: bDouble  - True to double click, false to single click.
; ..............: index    - Index of tray icon to click if more than one match.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Button(sExeName, sButton := "L", bDouble := false, index := 1)
{
    Setting_A_DetectHiddenWindows := A_DetectHiddenWindows
    DetectHiddenWindows, On
    WM_MOUSEMOVE      = 0x0200
    WM_LBUTTONDOWN    = 0x0201
    WM_LBUTTONUP      = 0x0202
    WM_LBUTTONDBLCLK = 0x0203
    WM_RBUTTONDOWN    = 0x0204
    WM_RBUTTONUP      = 0x0205
    WM_RBUTTONDBLCLK = 0x0206
    WM_MBUTTONDOWN    = 0x0207
    WM_MBUTTONUP      = 0x0208
    WM_MBUTTONDBLCLK = 0x0209
    sButton := "WM_" sButton "BUTTON"
    oIcons := {}
    oIcons := TrayIcon_GetInfo(sExeName)
    msgID  := oIcons[index].msgID
    uID    := oIcons[index].uID
    hWnd   := oIcons[index].hWnd
    if bDouble
        PostMessage, msgID, uID, %sButton%DBLCLK, , ahk_id %hWnd%
    else
    {
        PostMessage, msgID, uID, %sButton%DOWN, , ahk_id %hWnd%
        PostMessage, msgID, uID, %sButton%UP, , ahk_id %hWnd%
    }
    DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
    return
}

Re: Unable To Use Small Icons In Listview!

Posted: 23 Mar 2015, 03:07
by lexikos
Your options include -IconSmall +icon. These are not independent options. You cannot remove them. They are mutually exclusive view modes:
Icon: Shows a large-icon view. In this view and all the others except Report, the text in columns other than the first is not visible. To display icons in this mode, the ListView must have a large-icon ImageList assigned to it.

IconSmall: Shows a small-icon view.
Which image list is used depends on which view you're in. That is why the ListView has multiple image lists, rather than just letting you create an image list of a different size.

Re: Unable To Use Small Icons In Listview!

Posted: 07 Apr 2015, 14:15
by ToonyTom
Thank you, that really confused me for a while. It didn't explain very much about IconSmall view, so I thought it was just another icon size and not a different 'mode'.

Re: Unable To Use Small Icons In Listview!

Posted: 02 Jul 2015, 21:24
by BGM
I ran the script sample at the top.
Problem is that the mouse seems to be offset or something. It's as if the top 16 pixels of each icon belong to the icon above it.
Why?

If you move upward or side to side, it works correctly.
But if you move downward, it seems to be offset by 16 pixels.

I tried this in a different script with large icons loading from the shell32 dll and had the same problem.

I wonder if this is a bug in ahk?
(AutoHotkey 1.1.22.00 Unicode on Windows 7 Pro x64)

Re: Unable To Use Small Icons In Listview!

Posted: 03 Jul 2015, 10:59
by BGM
I wonder if that extra "area" below the icon belongs to some sort of reserved space for a text label?
If that is the case, how do you remove that?