Page 1 sur 1
[R] Récupérer les chemins des icones des fenêtres
Posté : lun. 13 avr. 2015 18:26
par ZDS
Bonjour à tous !
Toujours dans la lignée des demandes
débiles compliquées, je cherche à récupérer pour chaque fenêtre à l'écran le chemin de son icone pour la réutiliser dans un script à part (sousmenu déroulant par exemple, même si je pense plus à une GUI compacte pleine de GUICtrlCreateButton avec le flag $BS_ICON/0x0040).
Dans MSDN source intarissable de bon tuyaux, je n'ai pas trouvé ce que je veux :
https://msdn.microsoft.com/en-us/library/windows/desktop/ff468921(v=vs.85).aspx
Comme vous le voyez, pour SETTEXT il y a GETTEXT, pour SETFONT il y a GETFONT, mais pour SETICON il y a macache ^^
Vous auriez des idées? Avoir un WinGetIcon qui soit le pendant du [
WinSetIcon de Mikell] serait le top !
Merci d'avance !
PS: Mon but entre autre est d'avoir un petit widget de l'aspect que je souhaite qui listerait les fenêtres à l'écran, ou plutôt aux écrans, et que je ferai apparaître sur mes moniteurs n'ayant pas la barre des tâches (les logiciels comme Multimon Taskbar et équivalent que j'ai pu tester ne sont soit pas stables soit pas customisables soit pas gratuits ^^ - Win 7 Pro 64 avec trois écrans).
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : lun. 13 avr. 2015 22:17
par jguinch
Hello
- Avec
_WinAPI_GetClassLongEx, tu peux récupérer le handle de l'icône utilisée par une fenêtre donnée
- Avec
_WinAPI_CopyIcon, tu peux copier l'icône (handle précédemment récupéré) pour éviter de la perdre si la fenêtre se ferme
- Avec
GUICtrlSendMsg, tu peux appliquer une icône ou image à un contrôle
Ca peut te donner un truc dans ce genre :
► Afficher le texte
Code : Tout sélectionner
#include <WinAPISys.au3>
#include <ButtonConstants.au3>
$hMain = GUICreate("Ma Super GUI")
$hIcon = _WinAPI_GetClassLongEx ( $hMain, $GCL_HICONSM )
$hCopyIcon = _WinAPI_CopyIcon ( $hIcon )
GUICtrlCreateButton('', 10, 10, 200, 32)
_WinAPI_DeleteObject ( GUICtrlSendMsg(-1, $BM_SETIMAGE, $IMAGE_ICON, $hCopyIcon) )
GUICtrlSetData(-1, " " & WinGetTitle($hMain) )
GUISetState()
While 1
If GUIGetMsg() = -3 Then ExitLoop
WEnd
_WinAPI_DestroyIcon($hIcon)
Intéressant comme exercice

Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mar. 14 avr. 2015 13:02
par walkson
Bonjour,
Une autre méthode certainement plus longe que celle de jguinch, il y a _WinAPI_ShellExtractIcon mais qui oblige à un chemin
► Afficher le texte
Code : Tout sélectionner
#include <WinAPI.au3>
#include <WinAPIProc.au3>
#include <WinAPIShellEx.au3>
$pid = ProcessExists ( "autoit3help.exe" )
$way = _WinAPI_GetProcessFileName ( $pid )
$hMain = GUICreate("")
$button = GUICtrlCreateButton(' ', 10, 10, 200, 32)
$aa = GUICtrlGetHandle($button)
_WinAPI_DestroyIcon(_SendMessage($aa, 0xF7, 1, _WinAPI_ShellExtractIcon($way, 0, 32, 32)))
GUISetState()
While 1
If GUIGetMsg() = -3 Then ExitLoop
WEnd
A tout hasard ?...
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mar. 14 avr. 2015 13:31
par jguinch
La différence est que _WinAPI_GetClassLongEx va récupérer le handle de l'icône affichée, alors que _WinAPI_ShellExtractIcon va piocher l'icône dans l'exécutable de l'application.
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mar. 14 avr. 2015 14:12
par mikell
Hmm j'avais abandonné cette piste parce que ça ne marche pas sous XP ...
[Mode Anticipation /ON]
En prévision des inévitables sarcasmes jguinchesques je précise que WinSetIcon fonctionne elle sous
tous les OS Windows
[Mode Anticipation /OFF]
Edit
Testé sur w7 x64 du boulot, ça marche mais ça ne récupère pas l'icone présente
actuellement dans le titre de la fenêtre, par exemple après exécution de l'exemple de WinSetIcon sur 'AutoIt Help' ça récupère l'icone initiale (hh.exe)
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mar. 14 avr. 2015 16:24
par walkson
Va falloir lancer une souscription pour Mikell

Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mar. 14 avr. 2015 22:56
par mikell
C'est malin
@ZDS
► Afficher le texte
Code : Tout sélectionner
#include <WinAPI.au3>
ShellExecute(StringRegExpReplace(@Autoitexe, '(.+)\\[^\\]+', "$1") & "\AutoIt.chm")
Do
Sleep(10)
Until WinExists("AutoIt Help")
$handle = WinGetHandle("AutoIt Help")
_WinSetIcon($handle, "shell32.dll", 137)
$hIcon = _WinGetIcon($handle)
$hIcon2 = _WinAPI_CopyIcon ($hIcon)
_WinAPI_DestroyIcon($hIcon)
Sleep(1000)
WinClose($handle)
;.....
Sleep(300)
Msgbox(0,"", "étape 2 ...")
$hMain = GUICreate("Ma Super GUI", 300, 100)
GUISetState()
_SendMessage($hMain, 0x0080, 1, $hIcon2) ;$WM_SETICON = 0x0080
While 1
If GUIGetMsg() = -3 Then ExitLoop
WEnd
_WinAPI_DestroyIcon($hIcon2)
;=========================================
Func _WinSetIcon($hwnd, $file, $index = 0)
Local $tIcons = DllStructCreate("ptr Data")
DllCall("shell32.dll", "uint", "ExtractIconExW", "wstr", $file, "int", $index, "struct*", 0, "struct*", $tIcons, "uint", 1)
If @error Then Return SetError(1, 0, 0)
Local $hicon = DllStructGetData($tIcons, "Data")
_SendMessage($hwnd, 0x0080, 1, $hicon ) ;$WM_SETICON = 0x0080
; _WinAPI_DestroyIcon($hicon)
EndFunc
Func _WinGetIcon($hwnd)
Return "0x" & Hex(_SendMessage($hwnd, 0x007F, 1, 0)) ;$WM_GETICON = 0x007F
EndFunc

Re: [..] Récupérer les chemins des icones des fenêtres
Posté : dim. 19 avr. 2015 22:18
par ZDS
Merci pour votre aide, mais je n'arrive toujours pas à obtenir ce que je souhaite. L'icone récupérée ne m'a pas l'air utilisable :
► Afficher le texteCode
Code : Tout sélectionner
#include <WinAPISys.au3>
#include <ButtonConstants.au3>
Local $width = 300, $height = 200
; Première fenêtre
Local $GUI1 = GUICreate("Fenêtre d'origine", $width, $height, 1*@DesktopWidth/4-$width/2, @DesktopHeight/2-$height/2)
GUISetState()
Sleep(1000)
; Seconde fenêtre
Local $GUI2 = GUICreate("Fenêtre de destination", $width, $height, 3*@DesktopWidth/4-$width/2, @DesktopHeight/2-$height/2)
GUISetState()
Sleep(1000)
; Pré-traitement
GUISetIcon("test.ico", Default, $GUI1)
WinSetIcon($GUI1, "Test.ico")
Sleep(1000)
; Traitement
Local $icone = WinGetIcon($GUI1)
ConsoleWrite("$icone = "&$icone&@CRLF)
WinSetIcon($GUI2, $icone)
; Boucle
While 1
If GUIGetMsg() = -3 Then ExitLoop
WEnd
_WinAPI_DestroyIcon($icone)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func WinSetIcon($window, $icon)
Local $image = $icon
If IsString($icon) Then
$image = _WinAPI_LoadImage(0, $icon, $IMAGE_ICON, 32, 32, BitOR($LR_LOADFROMFILE, $LR_CREATEDIBSECTION))
If Not $image Then Return False
EndIf
_SendMessage($window, 0x0080, 1, $image) ; $WM_SETICON = 0x0080
If IsString($icon) Then
Sleep(200)
_WinAPI_DestroyIcon($image)
EndIf
EndFunc
Func WinGetIcon($window)
Local $icon = _WinAPI_GetClassLongEx($window, $GCL_HICONSM)
Local $copy = _WinAPI_CopyIcon($icon)
_WinAPI_DestroyIcon($icon)
Return $copy
EndFunc
Ci joint l'icone que j'utilise pour mon test
PS: C'est quand même bizarre que les fichiers .ico ne soient pas dans la liste des extensions autorisées sur le forum ^^
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : lun. 20 avr. 2015 00:08
par mikell
► Afficher le texte
Code : Tout sélectionner
#include <WinAPISys.au3>
#include <ButtonConstants.au3>
Local $width = 300, $height = 200, $ico = @scriptdir & "\test.ico"
; Première fenêtre
Local $GUI1 = GUICreate("Fenêtre d'origine", $width, $height, 1*@DesktopWidth/4-$width/2, @DesktopHeight/2-$height/2)
GUISetState()
Sleep(1000)
; Seconde fenêtre
Local $GUI2 = GUICreate("Fenêtre de destination", $width, $height, 3*@DesktopWidth/4-$width/2, @DesktopHeight/2-$height/2)
GUISetState()
Sleep(1000)
; Pré-traitement
WinSetIcon($GUI1, $ico)
;Sleep(1000)
; Traitement
$icone = WinGetIcon($GUI1)
ConsoleWrite("$icone = "&$icone&@CRLF)
WinSetIcon($GUI2, $icone)
; Boucle
While 1
If GUIGetMsg() = -3 Then ExitLoop
WEnd
_WinAPI_DestroyIcon($icone)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func WinSetIcon($hwnd, $file, $index = 0)
If Number($file) = 0 Then
Local $tIcons = DllStructCreate("ptr Data")
DllCall("shell32.dll", "uint", "ExtractIconExW", "wstr", $file, "int", $index, "struct*", 0, "struct*", $tIcons, "uint", 1)
If @error Then Return SetError(1, 0, 0)
Local $hicon = DllStructGetData($tIcons, "Data")
Else
Local $hicon = $file
EndIf
_SendMessage($hwnd, 0x0080, 1, $hicon ) ;$WM_SETICON = 0x0080
; _WinAPI_DestroyIcon($hicon)
EndFunc
Func WinGetIcon($hwnd)
Return "0x" & Hex(_SendMessage($hwnd, 0x007F, 1, 0)) ;$WM_GETICON = 0x007F
EndFunc
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mer. 22 avr. 2015 22:30
par ZDS
Désolé non, ça ne marche toujours pas ^^ En utilisant ta propre version corrigée (
pour éviter la pixelisation), la fonction WinSetIcon fonctionne uniquement avec le chemin, mais pas en utilisant le résultat en sortie du WinGetIcon (cf code en pièce jointe). J'ai aussi essayé avec une conversion en int avant de faire appel au _SendMessage, sans plus de succès.
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mer. 22 avr. 2015 22:54
par jguinch
Et si tu mets 1 dans _SendMessage au lien de 0 dans WinSetIcon ?
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mer. 22 avr. 2015 23:39
par mikell
Hum chez moi mon code marche (et le tien aussi) à condition de commenter le _WinAPI_DestroyIcon($icon) dans WinSetIcon
Arriver à récupérer une adresse ne veut pas dire arriver à récupérer le contenu s'il a été détruit
Pour tester, avec la ligne en question commentée ou pas :
Code : Tout sélectionner
Local $icone = WinGetIcon($GUI1)
$a = _WinAPI_GetIconInfo($icone)
If not @error Then
msgbox(0,"", $a[1])
Else
msgbox(0,"", "error")
EndIf
GetIconInfoEx serait plus sympa mais je n'ai que XP

Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mer. 22 avr. 2015 23:43
par jguinch
@Mikell : à ce sujet, dans ton premier message, tu dis que ce n'est pas compatible XP. Mais d'après MSDN, les fonctions que j'ai utilisées sont compatibles à partir de Windows 2000. Ou alors j'ai pas compris (très possible

)
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mer. 22 avr. 2015 23:57
par mikell
Non non tu as raison, c'est moi qui m'ai mal esprimé
Ce qui ne marche pas sur XP c'est le
BM_SETIMAGE (et le _WinAPI_GetClassLongEx ne récupère pas l'icone de la fenêtre
affichée)
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : mer. 22 avr. 2015 23:58
par jguinch
OK. Là j'ai comprendu...

Re: [..] Récupérer les chemins des icones des fenêtres
Posté : ven. 24 avr. 2015 22:20
par ZDS
Re bonjour/soir,
Si je pouvais j'aurais aimé avoir l'icone en mémoire dans le script plutot qu'une simple adresse car comme dit précédemment, avoir l'adresse ne garantie pas de la récupérer : pour peu que la fenêtre soit fermée, on ne peut plus avoir l'icone (dans un historique par exemple).
Mais j'ai une autre utilisation prévue pour cette fonction, liée à WinSetIcon de Mikell : pouvoir faire un WinSetState(@SW_HIDE) puis WinSetState(@SW_SHOW), très utile pour réordonner des fenêtres (au sein d'un même groupe).Le souci qui se pose, c'est qu'en faisant WinSetIcon, l'icone est nickel (aucune pixelisation), mais dès qu'on fait WinSetState(@SW_HIDE -> @SW_SHOW), l'icone est pixelisée.
L'idéal serait donc de pouvoir récupérer SOIT le chemin de l'icone pour pouvoir refaire un WinSetIcon juste après le WinSetState(@SW_HIDE -> @SW_SHOW) SOIT récupérer l'icone complète pour la copier et la réappliquer après.
Le problème de Windows XP est que ton icone ne se pixelise pas, donc tu ne peux pas voir le bug dont je parle ^^ (les icones de ta barre de taches etant en 16x16 et non en 32x32)
Merci d'avance !
EDIT: _WinAPI_GetIconInfoEx retourne une erreur (10) sur une fenêtre affectée par WinSetIcon.
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : sam. 25 avr. 2015 12:00
par mikell
Oui c'est aussi pour ça que je parlais de _WinAPI_GetIconInfoEx (que je ne peux pas tester) à utiliser par exemple juste après le WinGetIcon
Les infos qui t'intéressent devraient en principe se trouver dans les éléments 6 / 7 de l'array résultat
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : dim. 26 avr. 2015 13:07
par ZDS
Solution de contournement : Vu que l'icone qui m’intéresse est celle appliquée par WinSetIcon et non celle de base (car je cherche à pouvoir avoir une icone personnalisée pour chaque fenêtre non-AutoIt et pouvoir trier la liste de ces fenêtres), est-il possible d'appliquer une sorte de tag à une fenêtre particulière? Une sorte de postit invisible à l'écran basé sur le handle, qui serait détruit en même temps que la fenêtre, et dans lequel j'écrirais le chemin de l'icone customisée.
Ma solution actuellement envisagée est d'utiliser un fichier INI dont la clef est le handle, et dont la valeur est le chemin de l'icone appliquée. Pas des plus propres, mais je n'aurai à modifier que le WinSetIcon de Mikell pour y inclure le chemin, le WinGetIcon ne faisant que lire la valeur dans le fichier en question (avec un sémaphore autour des opérations en question car plusieurs scripts peuvent toucher aux icônes en même temps). Cela demande de mettre en place un garbage collector, car les handles des fenêtres fermées risquent d'être conservés dans le fichier INI et de grossir la liste.
Le tag serait plus pratique (car pas besoin de "garbage collector"), quelqu'un aurait une idée ou saurait si c'est humainement possible?
Re: [..] Récupérer les chemins des icones des fenêtres
Posté : ven. 26 juin 2015 02:30
par ZDS
Un peu tardif mais bon : je m'en suis sorti avec une solution qui ne me plait que partiellement. Déjà parce qu'elle m'oblige à utiliser un fichier temporaire pour pouvoir évoluer vers un semblant d'utilisation entre plusieurs processus, et surtout parce que je ne l'ai pas améliorée pour l'instant en vue de l'inter processus justement.
Bref, à vous de voir si ça peut vous être utile, merci encore ! Problème [R]ésolu.
► Afficher le texteAffectation des icones et récupération du handle d'une icone affectée
Code : Tout sélectionner
#include <WinAPI.au3>
Local $window = "[CLASS:ApolloRuntimeContentWindow]"
Local $file1 = @ScriptDir&"\Test1.ico"
Local $file2 = @ScriptDir&"\Test2.ico"
WinSetIcon($window, $file1)
MsgBox(0, "Contenu du fichier TEMP", FileRead(WinIcons_file()))
WinSetIcon($window, $file2)
MsgBox(0, "Contenu du fichier TEMP", FileRead(WinIcons_file()))
WinCleanIcons()
MsgBox(0, "Contenu du fichier TEMP", FileRead(WinIcons_file()))
WinClose($window)
WinCleanIcons()
MsgBox(0, "Contenu du fichier TEMP", FileRead(WinIcons_file()))
; Nom du fichier contenant les données
Func WinIcons_file()
Return @TempDir&"\"&"WinIcons_file.ini"
EndFunc
; Fonction de récupération de l'icone attribuée à une fenêtre
Func WinGetIcon($window)
Local $handle = WinGetHandle($window)
If $handle = 0 Then Return False
If Not IsDeclared("WINICONS") Then Global $WINICONS[1][2] = [[0]]
If Not FileExists(WinIcons_file()) Then FileClose(FileOpen(WinIcons_file(),10))
Return Number(IniRead(WinIcons_file(), "WinIcons", "WIN_"&WinGetHandle($handle), ""))
EndFunc
; Fonction d'attribution d'icone à une fenêtre
Func WinSetIcon($window, $file)
Local $handle = WinGetHandle($window)
If $handle = 0 Then Return False
If Not IsDeclared("WINICONS") Then Global $WINICONS[1][2] = [[0]]
If Not FileExists(WinIcons_file()) Then FileClose(FileOpen(WinIcons_file(),10))
If IsString($file) Then
Local $found = 0
For $i = 1 To $WINICONS[0][0]
If StringUpper($file) = $WINICONS[$i][0] Then
$found = $i
ExitLoop
EndIf
Next
If $found = 0 Then
$WINICONS[0][0] = $WINICONS[0][0] + 1
ReDim $WINICONS[$WINICONS[0][0]+1][2]
$WINICONS[$WINICONS[0][0]][0] = StringUpper($file)
$WINICONS[$WINICONS[0][0]][1] = _WinAPI_LoadImage(0, $file, $IMAGE_ICON, 32, 32, BitOR($LR_LOADFROMFILE, $LR_CREATEDIBSECTION))
$found = $WINICONS[0][0]
EndIf
_SendMessage($handle, 0x0080, 1, $WINICONS[$found][1]) ; $WM_SETICON = 0x0080
IniWrite(WinIcons_file(), "WinIcons", "WIN_"&WinGetHandle($handle), $WINICONS[$found][1])
Else
_SendMessage($handle, 0x0080, 1, $file) ; $WM_SETICON = 0x0080
IniWrite(WinIcons_file(), "WinIcons", "WIN_"&WinGetHandle($handle), $file)
EndIf
EndFunc
; Fonction de restauration de l'icone attribuée à une fenêtre
Func WinRestoreIcon($window)
Local $handle = WinGetHandle($window)
If $handle = 0 Then Return False
If Not IsDeclared("WINICONS") Then Global $WINICONS[1][2] = [[0]]
If Not FileExists(WinIcons_file()) Then FileClose(FileOpen(WinIcons_file(),10))
Local $icon = WinGetIcon($handle)
If $icon Then _SendMessage($handle, 0x0080, 1, $icon) ; $WM_SETICON = 0x0080
Return ($icon <> 0)
EndFunc
; Fonction de réinitialisation de l'icone attribuée à une fenêtre
Func WinResetIcon($window)
Local $handle = WinGetHandle($window)
If $handle = 0 Then Return False
If Not IsDeclared("WINICONS") Then Global $WINICONS[1][2] = [[0]]
If Not FileExists(WinIcons_file()) Then FileClose(FileOpen(WinIcons_file(),10))
IniDelete(WinIcons_file(), "WinIcons", "WIN_"&$handle)
_SendMessage($handle, 0x0080, 0, 0) ; $WM_SETICON = 0x0080
Return True
EndFunc
; Fonction de nettoyage de la liste des icones attribuées à des fenêtres
Func WinCleanIcons()
If Not IsDeclared("WINICONS") Then Global $WINICONS[1][2] = [[0]]
If Not FileExists(WinIcons_file()) Then FileClose(FileOpen(WinIcons_file(),10))
Local $keys = IniReadSection(WinIcons_file(), "WinIcons")
If Not @error Then
For $i = 1 To $keys[0][0]
Local $handle = Number(StringTrimLeft($keys[$i][0], StringLen("WIN_")))
If $handle <= 0 Or Not WinExists($handle) Then IniDelete(WinIcons_file(), "WinIcons", $keys[$i][0])
Next
EndIf
EndFunc
PS: Pour le moment ce sont les handles qui sont stockés dans le fichier INI, au final il faudra que ce soit le chemin de l'icone (unifié, pour éviter les soucis de majuscules ou de chemin relatif) pour que chaque processus puisse retrouver la nouvelle icone d'une fenêtre donnée. Le tableau
$WINICONS servira ensuite dans l'autre sens, comparer la valeur à
$WINICONS[$i][0] et utiliser
_SendMessage($handle, 0x0080, 1, WINICONS[$i][1]) ; $WM_SETICON = 0x0080