Jump to content

How to use icon handles in ListViews? Not possible?


lod3n
 Share

Recommended Posts

I have been tinkering with something that plays with visible windows, and a window selector I am working on uses a listview. So, I've written a function, getIconHandleByHwnd(), below, that can determine the correct icon to show for each window, but it retrieves an icon handle, not the filename of a icon resource file and index, which is great for Tabs and Menu Items

So far as I can determine, and from a great deal of forum searching, the only way to set the icon of a ListView item is with GuiCtrlSetImage, and it ONLY works by means of specifying a specific icon file resource and index number.

Does anybody know how to use an icon handle instead? Or, how to convert an icon handle in such a way that it could be used? Google turns up very little, and it sounds like I might be screwed. However! The Applications tab of Task Manager seems to be doing this exact thing, so how the heck do THEY do it?

Provided is a scaled down version of the code I'm working on, and a commented out fictional function to set the listview item's icon by icon handle. I am happy writing the function, but I need a lead on how I might do so.


#include <GUIConstants.au3>
#Include <GuiListView.au3>
Opt("MustDeclareVars", 0)

$guiWinList = GUICreate("Visible Windows")

$mylist = GUICtrlCreateListView("Handle  |Title  ", 10, 10, 380, 380, $LVS_REPORT)
$var = WinList()
For $i = 1 To $var[0][0]
    $winHandle = $var[$i][1]
    $winTitle = $var[$i][0]
    If $winTitle <> "" And IsVisible($winHandle) And _
            WinGetProcess($winHandle) <> @AutoItPID And $winHandle <> 0 Then
        $lvitem = GUICtrlCreateListViewItem($winHandle & "|" & $winTitle, $mylist)
        
;set icon traditionaly:
        GUICtrlSetImage($lvitem, "shell32.dll", 224)
        
;but I'd rather do this
;~           $hIcon = getIconHandleByHwnd($winHandle);this works elsewhere, for tabs and menu items
;~           SomeFunctionToSetListViewItemIconByIconHandle($mylist,$lvitem,$hIcon)
;~           DestroyIcon($hIcon)
        
    EndIf
Next
_GUICtrlListViewSetColumnWidth($mylist, 0, $LVSCW_AUTOSIZE)
_GUICtrlListViewSetColumnWidth($mylist, 1, $LVSCW_AUTOSIZE)
GUISetState()

While 1
    $msg = GUIGetMsg()

    Switch $msg
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd
Exit

;required functions

Func IsVisible($handle)
    If BitAND(WinGetState($handle), 2) Then
        Return 1
    Else
        Return 0
    EndIf
EndFunc;==>IsVisible

Func getIconHandleByFile($pszPath)
    $SHGFI_ICON = 0x100     ;Get icon
    $SHGFI_SMALLICON = 0x1    ;Get Small Icon

    $dwFileAttributes = 0
    $psfi = DllStructCreate("uint;int;dword;char[260];char[80]"); thanks Holger!
    $cbSizeFileInfo = DllStructGetSize($psfi)
    $uFlags = BitOR($SHGFI_ICON, $SHGFI_SMALLICON)

    $hImgSmall = DllCall('shell32.dll', 'int', 'SHGetFileInfo', _
            'str', $pszPath, _
            'uint', $dwFileAttributes, _
            'ptr', DllStructGetPtr($psfi), _
            'uint', $cbSizeFileInfo, _
            'uint', $uFlags)

    Return DllStructGetData($psfi, 1)
EndFunc;==>getIconHandleByFile

Func getIconHandleByHwnd($hwnd)
    $hwnd = HWnd($hwnd)
    $WM_GETICON = 0x7F
    $GCL_HICONSM = -34
    $GCL_HICON = -14
    $IDI_APPLICATION = 32512
    $hIcon = 0
    $hIcon = _SendMessage ($hwnd, $WM_GETICON, False, 0)
    If ($hIcon == 0) Then $hIcon = _SendMessage ($hwnd, $WM_GETICON, True, 0)
    If ($hIcon == 0) Then
        $hIcon = DllCall("user32.dll", "int", "GetClassLong", "hwnd", $hwnd, "int", $GCL_HICONSM)
        $hIcon = $hIcon[0]
    EndIf
    If ($hIcon == 0) Then
        $hIcon = DllCall("user32.dll", "int", "GetClassLong", "hwnd", $hwnd, "int", $GCL_HICON)
        $hIcon = $hIcon[0]
    EndIf
    If ($hIcon == 0) Then
        $pid = WinGetProcess(HWnd($hwnd))
        $path = getExePathByPid($pid)
        $hIcon = getIconHandleByFile($path)
    EndIf
    Return $hIcon
EndFunc;==>getIconHandleByHwnd

Func DestroyIcon($hIcon)
   $bResult = DllCall('user32.dll', 'int', 'DestroyIcon', 'hwnd', $hIcon)
   Return $bResult[0]
EndFunc;==>DestroyIcon

Func getExePathByPid($pid)
    $objWMIService = ObjGet("winmgmts:\\.\root\CIMV2")
    $colItems = $objWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE ProcessId = " & $pid, "WQL", 0x10 + 0x20)
    If IsObj($colItems) Then
        For $objItem In $colItems
            Return $objItem.ExecutablePath
        Next
    EndIf
EndFunc;==>getExePathByPid

[code=auto:0]

Edit: added line breaks to [ autoit ] and [ code ] tags, funny, I don't remember having to do that in the past.

Edited by lod3n

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

If you want to use icon handles, you can do this by loading an ImageList with the icons that you want and then setting the ListView ImageList. I've done this with the Auto3Lib ListView before, so I assume that you can do it with the GUIListView too. If you need help with how to load an icon into a ImageList, take a look at the __ImageList_ReplaceIcon function at the bottom of A3LImageList.au3. Also take a look at _ImageList_AddIcon. I think all you need is the bottom half of that function to do what you want. If you get stuck, give me a shout.

Auto3Lib: A library of over 1200 functions for AutoIt
Link to comment
Share on other sites

Ah, I didn't know you could replace an imagelist... say, that has interesting possibilities. Excellent! This works nicely, thanks for your help:

#include <GUIConstants.au3>
#Include <GuiListView.au3>
Opt("MustDeclareVars", 0)

;$LVM_FIRST = 0x1000 ; defined in GuiListView.au3
$LVM_SETIMAGELIST = $LVM_FIRST + 3
$ILC_MASK = 0x1
$ILC_COLOR32 = 0x20
$ILC_COLOR24 = 0x18
$ILC_PERITEMMIRROR = 0x00008000
$lvFlags = $ILC_COLOR32+$ILC_MASK+$ILC_PERITEMMIRROR

$guiWinList = GUICreate("Visible Windows")

$mylist = GUICtrlCreateListView("Title  |Handle  ", 10, 10, 380, 380, $LVS_REPORT)
$mylistImageList = DllCall("ComCtl32.dll", "hwnd", "ImageList_Create", "int", 16, "int", 16, "int", $lvFlags, "int", 0, "int", 1)
$mylistImageList = $mylistImageList[0]

$var = WinList()
For $i = 1 To $var[0][0]
    $winHandle = $var[$i][1]
    $winTitle = $var[$i][0]
    If $winTitle <> "" And IsVisible($winHandle) And _
        WinGetProcess($winHandle) <> @AutoItPID And $winHandle <> 0 Then
        $lvitem = GUICtrlCreateListViewItem($winTitle & "|" & $winHandle, $mylist)
        GUICtrlSetImage($lvitem, "shell32.dll", 224);have to set something, or there'll be no image list to swap out!

        $hIcon = getIconHandleByHwnd($var[$i][1])
        $nIndex = DllCall('comctl32.dll', 'int', 'ImageList_AddIcon', 'hwnd', $mylistImageList, 'hwnd', $hIcon)
        DllCall('user32.dll', 'int', 'DestroyIcon', 'hwnd', $hIcon)
        
    EndIf
Next
_SendMessage(GUICtrlGetHandle($mylist), $LVM_SETIMAGELIST, 1, $mylistImageList)
_GUICtrlListViewSetColumnWidth($mylist, 0, $LVSCW_AUTOSIZE)
_GUICtrlListViewSetColumnWidth($mylist, 1, $LVSCW_AUTOSIZE)
GUISetState()

While 1
    $msg = GUIGetMsg()

    Switch $msg
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd
Exit

;required functions

Func IsVisible($handle)
    If BitAND(WinGetState($handle), 2) Then
        Return 1
    Else
        Return 0
    EndIf
EndFunc   ;==>IsVisible

Func getIconHandleByFile($pszPath)
    $SHGFI_ICON = 0x100        ;Get icon
    $SHGFI_SMALLICON = 0x1          ;Get Small Icon

    $dwFileAttributes = 0
    $psfi = DllStructCreate("uint;int;dword;char[260];char[80]") ; thanks Holger!
    $cbSizeFileInfo = DllStructGetSize($psfi)
    $uFlags = BitOR($SHGFI_ICON, $SHGFI_SMALLICON)

    $hImgSmall = DllCall('shell32.dll', 'int', 'SHGetFileInfo', _
            'str', $pszPath, _
            'uint', $dwFileAttributes, _
            'ptr', DllStructGetPtr($psfi), _
            'uint', $cbSizeFileInfo, _
            'uint', $uFlags)

    Return DllStructGetData($psfi, 1)
EndFunc   ;==>getIconHandleByFile

Func getIconHandleByHwnd($hwnd)
    $hwnd = HWnd($hwnd)
    $WM_GETICON = 0x7F
    $GCL_HICONSM = -34
    $GCL_HICON = -14
    $IDI_APPLICATION = 32512
    $hIcon = 0
    $hIcon = _SendMessage ($hwnd, $WM_GETICON, False, 0)
    If ($hIcon == 0) Then $hIcon = _SendMessage ($hwnd, $WM_GETICON, True, 0)
    If ($hIcon == 0) Then
        $hIcon = DllCall("user32.dll", "int", "GetClassLong", "hwnd", $hwnd, "int", $GCL_HICONSM)
        $hIcon = $hIcon[0]
    EndIf
    If ($hIcon == 0) Then
        $hIcon = DllCall("user32.dll", "int", "GetClassLong", "hwnd", $hwnd, "int", $GCL_HICON)
        $hIcon = $hIcon[0]
    EndIf
    If ($hIcon == 0) Then
        $pid = WinGetProcess(HWnd($hwnd))
        $path = getExePathByPid($pid)
        $hIcon = getIconHandleByFile($path)
    EndIf
    Return $hIcon
EndFunc   ;==>getIconHandleByHwnd

Func getExePathByPid($pid)
    $objWMIService = ObjGet("winmgmts:\\.\root\CIMV2")
    $colItems = $objWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE ProcessId = " & $pid, "WQL", 0x10 + 0x20)
    If IsObj($colItems) Then
        For $objItem In $colItems
            Return $objItem.ExecutablePath
        Next
    EndIf
EndFunc   ;==>getExePathByPid

Edited by lod3n

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

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...