Jump to content
TexWiller

Function GUICtrlSetImage fails to extract first Icon at index -1

Recommended Posts

TexWiller

I noticed that the example enumicon.au3 uses GUICtrlCreateIcon and GUICtrlSetImage witch works well.

A similar script using GUICtrlCreateButton and GUICtrlSetImage fails to extract the Icon at position -1.

Do someone nows why?

Thanks in advance!

Share this post


Link to post
Share on other sites
BrewManNH

Not without some code to see what you're talking about.

No idea what enumicon.au3 is or does.


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites
JLogan3o13

Moved to the appropriate forum, as the DEV forum very clearly states:

Quote

Do not create AutoIt-related topics here

 


√-1 2^3 ∑ π, and it was delicious!

Share this post


Link to post
Share on other sites
TexWiller

@JLogan3o13

Sorry and thanks! I'm still learning... .

@BrewManNH

Thank you for reply.

Enumicon.au3 is a sample script witch is delivered and installed with AutoIt.
AutoIt3\Examples\GUI\Advanced\enumicon.au3

The script uses first GUICtrlCreateIcon to create Icon-controls with displayed icons in one step.
After this, it uses GUICtrlSetImage to change the Icons on a button-click.

I wrote a similar script witch uses Buttons instead of Icon-Controls. If I try to change the first
Icon (Index -1), the function doesn't returns the first Icon from shell32.dll.

 

; ===============================================================================
;
; Description:      Show all icons in the given file
; Requirement(s):   AutoIt 3.0.103+
; Author(s):        YDY (Lazycat)
;
; ===============================================================================

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

; Setting variables
Global $g_aidIcons[30], $g_aidLabels[30]
Global $g_iStartIndex = 1
Global $g_sFilename = @SystemDir & "\shell32.dll"; Default file is "shell32.dll"
Global $g_iOrdinal = -1

Global $g_idPrev

_Main()

Func _Main()
 Local $iMsg, $sCurFilename, $sTmpFile

 ; Creating GUI and controls
 Local $hGui = GUICreate("Icon Selector by Ordinal value", 385, 435, @DesktopWidth / 2 - 192, _
   @DesktopHeight / 2 - 235, -1, $WS_EX_ACCEPTFILES)
 GUICtrlCreateGroup("", 5, 1, 375, 40)
 GUICtrlCreateGroup("", 5, 50, 375, 380)
 Local $idFile = GUICtrlCreateInput($g_sFilename, 12, 15, 325, 16, -1, $WS_EX_STATICEDGE)
 GUICtrlSetState(-1, $GUI_DROPACCEPTED)
 GUICtrlSetTip(-1, "You can drop files from shell here...")
 Local $idFileSel = GUICtrlCreateButton("...", 345, 14, 26, 18)
 $g_idPrev = GUICtrlCreateButton("Previous", 10, 45, 60, 24, $BS_FLAT)
 GUICtrlSetState(-1, $GUI_DISABLE)
 Local $idNext = GUICtrlCreateButton("Next", 75, 45, 60, 24, $BS_FLAT)
 Local $idToggle = GUICtrlCreateButton("by Name", 300, 45, 60, 24, $BS_FLAT)

 ; This code build two arrays of ID's of icons and labels for easily update
 Local $iCurIndex
 For $iCntRow = 0 To 4
  For $iCntCol = 0 To 5
   $iCurIndex = $iCntRow * 6 + $iCntCol
;******************************************************************************************************
;******************************************************************************************************
   $g_aidIcons[$iCurIndex] = GUICtrlCreateIcon($g_sFilename, $g_iOrdinal * ($iCurIndex + 1), _
     60 * $iCntCol + 25, 70 * $iCntRow + 80)
     ConsoleWrite($g_iOrdinal * ($iCurIndex + 1))
;******************************************************************************************************
  ;My version vould have somthing like this:
  ;... $Button = GUICtrlCreateButton("", 100, 100, 25, 25, $BS_ICON)....
  ;... GUICtrlSetImage($Button, $g_sFilename, -1, 1)....
;******************************************************************************************************
;******************************************************************************************************
   $g_aidLabels[$iCurIndex] = GUICtrlCreateLabel($g_iOrdinal * ($iCurIndex + 1), _
     60 * $iCntCol + 11, 70 * $iCntRow + 115, 60, 20, $SS_CENTER)
  Next
 Next

 GUISetState()

 While 1
  $iMsg = GUIGetMsg()
  ; Code below will check if the file is dropped (or selected)
  $sCurFilename = GUICtrlRead($idFile)
  If $sCurFilename <> $g_sFilename Then
   $g_iStartIndex = 1
   $g_sFilename = $sCurFilename
   _GUIUpdate()
  EndIf
  ; Main "Select" statement that handles other events
  Select
   Case $iMsg = $idFileSel
    $sTmpFile = FileOpenDialog("Select file:", "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", "Executables & dll's (*.exe;*.dll;*.ocx;*.icl)")
    If @error Then ContinueLoop
    GUICtrlSetData($idFile, $sTmpFile); GUI will be updated at next iteration
   Case $iMsg = $g_idPrev
    $g_iStartIndex = $g_iStartIndex - 30
    _GUIUpdate()
   Case $iMsg = $idNext
    $g_iStartIndex = $g_iStartIndex + 30
    _GUIUpdate()
   Case $iMsg = $idToggle
    If $g_iOrdinal = -1 Then
     $g_iOrdinal = 1
     GUICtrlSetData($idToggle, "by Ordinal")
     WinSetTitle($hGui, "", "Icon Selector by Name value")
    Else
     $g_iOrdinal = -1
     GUICtrlSetData($idToggle, "by Name")
     WinSetTitle($hGui, "", "Icon Selector by Ordinal value")
    EndIf
    _GUIUpdate()
   Case $iMsg = $GUI_EVENT_CLOSE
    Exit
  EndSelect
 WEnd
EndFunc   ;==>_Main

; Just updates GUI icons, labels and set state of "Previous" button
Func _GUIUpdate()
 ConsoleWrite("start")
 Local $iCurIndex

 For $iCntRow = 0 To 4
  For $iCntCol = 0 To 5
   $iCurIndex = $iCntRow * 6 + $iCntCol
;******************************************************************************************************
;******************************************************************************************************
   GUICtrlSetImage($g_aidIcons[$iCurIndex], $g_sFilename, $g_iOrdinal * ($iCurIndex + $g_iStartIndex))
;******************************************************************************************************
;******************************************************************************************************
   If $g_iOrdinal = -1 Then
    GUICtrlSetData($g_aidLabels[$iCurIndex], -($iCurIndex + $g_iStartIndex))
   Else
    GUICtrlSetData($g_aidLabels[$iCurIndex], '"' & ($iCurIndex + $g_iStartIndex) & '"')
   EndIf
  Next
 Next
 ; This is because we don't want negative values
 If $g_iStartIndex = 1 Then
  GUICtrlSetState($g_idPrev, $GUI_DISABLE)
 Else
  GUICtrlSetState($g_idPrev, $GUI_ENABLE)
 EndIf
EndFunc   ;==>_GUIUpdate

Share this post


Link to post
Share on other sites
BrewManNH

Instead of showing what you might have in your script, please post your script, or a reproducer script that demonstrates what you're doing and how it's not working.

Also, please post the code using the code tags, the "<>" button on the editor will let you do that.


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites
TexWiller

Thank you for the hint. So hier is my sample script:

#NoTrayIcon
;============================================================================================================
;Programm Options
;============================================================================================================
Opt("MustDeclareVars", 1) ;Variables must be pre-declared.
Opt("TrayMenuMode", 3)    ;The default tray menu items will not be shown, items are not checked when selected.

;============================================================================================================
;Libraries Inclusions
;============================================================================================================

#include <ColorConstants.au3>
#include <TrayConstants.au3>
#include <WindowsConstants.au3>
#include <FontConstants.au3>
#include <GuiConstantsEx.au3>
#include <Array.au3>
#include <GuiButton.au3>
#include <StaticConstants.au3>


;============================================================================================================
;Global Vars
;============================================================================================================

Global $MainGUIWiHd
Global $MGUIGetMsg0
Global $TrayMenMain
Global $TrayMenExit



Main()



Func Main()

    ;------------------------------------------------------------------------------------------------------------
    ;Create Main Window
    ;------------------------------------------------------------------------------------------------------------
    $MainGUIWiHd = GUICreate("Sample", 520, 520, 50, 50, BitOR($WS_SYSMENU, $WS_CAPTION, $DS_SETFOREGROUND))
    GUISetFont (8, $FW_NORMAL, $GUI_FONTNORMAL, "Arial", $MainGUIWiHd, $CLEARTYPE_QUALITY)
    GUISetBkColor(0xDDDDDD, $MainGUIWiHd)
    GUISetState(@SW_SHOW, $MainGUIWiHd)
    WinWaitActive($MainGUIWiHd)

    ;============================================================================================================
    ;Create Traymenu
    ;============================================================================================================

    ;Create a Traymenu.
    $TrayMenMain = TrayCreateItem("Sample", -1, 0)

        ;Create a Separator line.
        TrayCreateItem("", -1, -1)

        ;Create a Menuitem.
        $TrayMenExit = TrayCreateItem("Exit", -1, -1)

    ;Show the Traymenu.
    TraySetState($TRAY_ICONSTATE_SHOW)

    ;#comments-start

    ;------------------------------------------------------------------------------------------------------------
    ;Sample
    ;------------------------------------------------------------------------------------------------------------

    Local $IconButtons[0]   ;Array to manage Buttons
    Local $IconBLabels[0]   ;Array to manage Buttons

    Local $ButtonPosLe = 10 ;Inserting Position X
    Local $ButtonPosTo = 10 ;Inserting Position Y

    Local $ButtonCount
    Local $MessageText
    Local $MessageTemp
    Local $IcPosOffset = 0

    for $ButtonCount = 1 to 70

        ;Jump to higher position after 60 Icons
        if $ButtonCount > 60 then $IcPosOffset = 265

        _ArrayAdd($IconButtons, GUICtrlCreateButton("", $ButtonPosLe, $ButtonPosTo, 45, 45, $BS_ICON))
        _ArrayAdd($IconBLabels, GUICtrlCreateLabel( -1 * ($ButtonCount + $IcPosOffset), $ButtonPosLe, $ButtonPosTo + 45, 45, 15))
        GUICtrlSetStyle($IconBLabels[$ButtonCount - 1], BitOR($SS_CENTER, $SS_CENTERIMAGE))

        $ButtonPosLe = $ButtonPosLe + 50

        If Mod($ButtonCount, 10) = 0 Then
            $ButtonPosTo = $ButtonPosTo + 70
            $ButtonPosLe = 10
        EndIf

        ;retrieving Icons by negative ordinal position
        ;*****************************************************************************************
        $MessageTemp = GUICtrlSetImage($IconButtons[$ButtonCount - 1], "shell32.dll", -1 * ($ButtonCount + $IcPosOffset) , 1)
        ;*****************************************************************************************
        if  $ButtonCount + $IcPosOffset = 1 or _
            $ButtonCount + $IcPosOffset = 50 or _
            $ButtonCount + $IcPosOffset = 51 or _
            $ButtonCount + $IcPosOffset = 52 or _
            $ButtonCount + $IcPosOffset = 53 or _
            $ButtonCount + $IcPosOffset = 328 Then

            $MessageText = "Position: " & $ButtonCount + $IcPosOffset & " (of shell32.dll containing 327 Icons)" & @CRLF & @CRLF
            $MessageText = $MessageText & "Current GUICtrlSetImage return value is: " & $MessageTemp & @CRLF & @CRLF
            if $ButtonCount + $IcPosOffset <> 328 Then
                $MessageText = $MessageText & "But no Icon is retrieved... ."
                Else
                $MessageText = $MessageText & "As expected cose there are only 327 Icons... ."
            EndIf

            MsgBox($MB_SYSTEMMODAL, "Info", $MessageText, 0, $MainGUIWiHd)

            GUICtrlSetBkColor ($IconBLabels[$ButtonCount - 1], $COLOR_RED)

        EndIf

        If $ButtonCount + $IcPosOffset > 327 Then   GUICtrlSetBkColor ($IconBLabels[$ButtonCount - 1], $COLOR_LIME)

    Next

    ;*****************************************************************************************
    $MessageText = "Retrieving by negative ordinal position, the first position fails." & @CRLF & @CRLF
    $MessageText = $MessageText & "Position 50 to 53 are also there but without Icon." & @CRLF & @CRLF
    $MessageText = $MessageText & "Starting from position 328 GUICtrlSetImage returns 0 (no more Icons)." & @CRLF & @CRLF
    ;*****************************************************************************************

    MsgBox($MB_SYSTEMMODAL,"Info", $MessageText, 0,$MainGUIWiHd)


    ;*****************************************************************************************
    $MessageText = "Trying with positive values, retrieving of position 1 works." & @CRLF & @CRLF
    $MessageText = $MessageText & "But 50 to 53 are stil without Icon... ." & @CRLF & @CRLF

    $MessageText = $MessageText & "This behavior seems inconsistent to me, considering that the function" & @CRLF
    $MessageText = $MessageText & "GUICtrlCreateICON is able to retrieve the first Icon by using -1... ." & @CRLF & @CRLF
    $MessageText = $MessageText & "Maybe is -1 a reserved value to the function GUICtrlSetIMAGE?" & @CRLF
    $MessageText = $MessageText & "Or is it a bug?" & @CRLF
    ;*****************************************************************************************

    MsgBox($MB_SYSTEMMODAL,"Info", $MessageText, 0,$MainGUIWiHd)

    $MessageTemp = GUICtrlSetImage($IconButtons[65], "shell32.dll", 1, 1)
    GUICtrlSetData($IconBLabels[65], 1)
    GUICtrlSetBkColor ($IconBLabels[65], $COLOR_YELLOW)

    $MessageTemp = GUICtrlSetImage($IconButtons[66], "shell32.dll", 50, 1)
    GUICtrlSetData($IconBLabels[66], 50)
    GUICtrlSetBkColor ($IconBLabels[66], $COLOR_YELLOW)

    $MessageTemp = GUICtrlSetImage($IconButtons[67], "shell32.dll", 51, 1)
    GUICtrlSetData($IconBLabels[67], 51)
    GUICtrlSetBkColor ($IconBLabels[67], $COLOR_YELLOW)

    $MessageTemp = GUICtrlSetImage($IconButtons[68], "shell32.dll", 52, 1)
    GUICtrlSetData($IconBLabels[68], 52)
    GUICtrlSetBkColor ($IconBLabels[68], $COLOR_YELLOW)

    $MessageTemp = GUICtrlSetImage($IconButtons[69], "shell32.dll", 53, 1)
    GUICtrlSetData($IconBLabels[69], 53)
    GUICtrlSetBkColor ($IconBLabels[69], $COLOR_YELLOW)

    ;============================================================================================================
    ;GUI Loop
    ;============================================================================================================
    While True
        ;------------------------------------------------------------------------------------------------------------
        ;Get GUI-Messages
        ;------------------------------------------------------------------------------------------------------------
        $MGUIGetMsg0 = GUIGetMsg()
        if $MGUIGetMsg0 = $GUI_EVENT_CLOSE Then ExitLoop
        ;------------------------------------------------------------------------------------------------------------
        ;Get Traymenu Messages
        ;------------------------------------------------------------------------------------------------------------
        Switch TrayGetMsg()
            Case $TrayMenExit ;Exit.
            ExitLoop
        EndSwitch
        ;------------------------------------------------------------------------------------------------------------
    WEnd


EndFunc


Hope it works on your system... .

  • Thanks 1

Share this post


Link to post
Share on other sites
Bilgus

Thanks for the reproducer It made It much easier to see your issue

I added this as a test to see what the WinAPI function does

Local $hIcon = _WinAPI_ExtractIcon ("shell32.dll", -1 * ($ButtonCount + $IcPosOffset))

        ConsoleWrite("Ordinal " & -1 * ($ButtonCount + $IcPosOffset) & "hIcon = " & $hIcon &@CRLF)
        _WinAPI_DestroyIcon($hIcon)

And it to returned 0 for the handle of index -1

so I went to the MSDN page and found this

Quote
nIconIndex [in]

Type: UINT

The zero-based index of the icon to retrieve. For example, if this value is 0, the function returns a handle to the first icon in the specified file.

If this value is -1, the function returns the total number of icons in the specified file. If the file is an executable file or DLL, the return value is the number of RT_GROUP_ICON resources. If the file is an .ICO file, the return value is 1.

If this value is a negative number not equal to –1, the function returns a handle to the icon in the specified file whose resource identifier is equal to the absolute value of nIconIndex. For example, you should use –3 to extract the icon whose resource identifier is 3. To extract the icon whose resource identifier is 1, use the ExtractIconEx function.

Looked back at the definition in the helpfile 

Quote

GUICtrlSetImage

....

[optional] Icon name if the file contains multiple icons. Can be an ordinal name if negative number. Otherwise -1.

The way I see it you have two options..

;retrieving Icons by negative ordinal position
        ;*****************************************************************************************
        Local $iOrdinal = -1 * ($ButtonCount + $IcPosOffset)
        $iOrdinal = $iOrdinal = -1 ? 0 : $iOrdinal
        Local $hIcon = _WinAPI_ExtractIcon ("shell32.dll", $iOrdinal)
        $MessageTemp = GUICtrlSetImage($IconButtons[$ButtonCount - 1], "shell32.dll",  $iOrdinal, 1)
        ConsoleWrite("Ordinal " & $iOrdinal & " hIcon = " & $hIcon & " $MessageTemp = " & $MessageTemp & @CRLF)
        _WinAPI_DestroyIcon($hIcon)
        ;*****************************************************************************************

Or

;retrieving Icons by Positive position
        ;*****************************************************************************************
        Local $iIconPos = 1 * ($ButtonCount + $IcPosOffset)
        Local $hIcon = _WinAPI_ExtractIcon ("shell32.dll", $iIconPos)
        $MessageTemp = GUICtrlSetImage($IconButtons[$ButtonCount - 1], "shell32.dll",  $iIconPos, 1)
        ConsoleWrite("Position " & $iIconPos & " hIcon = " & $hIcon & " $MessageTemp = " & $MessageTemp & @CRLF)
        _WinAPI_DestroyIcon($hIcon)
        ;*****************************************************************************************

So opening shell32.dll in ResourceHacker icons 50-53 are blank so those are expected

The other thing is that the ordinal names all start in the 100's

So your icon that you are calling with -1 is actually supposed to be -102

Local $iOrdinal = 1 * ($ButtonCount + $IcPosOffset)
        $iOrdinal = $iOrdinal = -1 ? -102 : $iOrdinal
        Local $hIcon = _WinAPI_ExtractIcon ("shell32.dll", $iOrdinal)
        $MessageTemp = GUICtrlSetImage($IconButtons[$ButtonCount - 1], "shell32.dll",  $iOrdinal, 1)
        ConsoleWrite("Ordinal " & $iOrdinal & " hIcon = " & $hIcon & " $MessageTemp = " & $MessageTemp & @CRLF)
        _WinAPI_DestroyIcon($hIcon)

So I'd say that means ';retrieving Icons by Positive position' Wins

Share this post


Link to post
Share on other sites
TexWiller

First, thank you for your research and for your code sample. I found something else in your code that I was missing in AutoIt so far:

$iOrdinal = $iOrdinal = -1 ? 0 : $iOrdinal

Probably because I allways searched for a command like: "IIf(Expression, TruePart, FalsePart)" and not for an operator... .:)

Then, to your suggested solution. I read in the AutoIt-Help that some libraries are only accessible by negative values.

"... Passing a negative number causes 1-based "index" behaviour. Some 
Dll can have icon extracted just with negative numbers. ..."

So I wanted a solution that would work in any case. "_WinAPI_ExtractIconEx" would do the extraction job, but how to get the

icon on the button after extraction?

Because "GUICtrlSetImage" seems to be the most direct and recommended way to put pictures on buttons, I hoped there

would be a way to use the function with -1 (maybe some kind of flag)... ?

What other function would use negative numbers and directly put the icon on a button, and also without using Image lists?

I could not find any. Does anyone have a hint?


 

Share this post


Link to post
Share on other sites
Bilgus

 

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

×