Extraction d'icône des exe/dll/icl

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Extraction d'icône des exe/dll/icl

Message par Anonyme2 »

J'ai posté ce code sur le forum anglais en réponse à une question.

Ce code extrait et affiche une icône d'un fichier exe (mais fonctionne aussi pour les dll) en fonction de la taille demandée. Le code teste que l'icône est de forme carré mais ne tient pas compte de la profondeur des couleurs. C'est possible de modifier le code pour prendre en compte cette profondeur. Non testé sur icône vista sous Vista mais ça doit marcher.

Code : Tout sélectionner

EnableExplicit

#Return_Error = 0

; Utilisé pour charger une Dll, ICL, EXE en datafile (non executable)
#LOAD_LIBRARY_AS_DATAFILE = 2

Structure IconFind
     Size.l
     hIcon.i
EndStructure


Macro HIWORD(Value)
     (Value>>16)
EndMacro

Macro LOWORD(Value)
     Value & $FFFF
EndMacro

Macro MAKEINTRESOURCE(INT)
     LOWORD(INT)
EndMacro

Macro IS_INTRESOURCE(Val)
     HIWORD(Val)
EndMacro


; ici commence la callback utilisé pour compter les icônes des DLL/EXE 32 bits
; here start callback used to count up DLL/EXE 32 bits icons

Procedure.l Enumerate_Icon(hModule, lpszType, lpszName, *Icon.IconFind)
     ; la fonction énumère les identifiants des d'icônes et pas des groupes d'icônes
     
     ; mémorise le handle du bloc d'information de la ressource recherchée
     Protected Find_Resource = 0
     ; mémorise le handle du bloc d'information des données de la ressource chargée
     Protected LoadResource = 0
     ; mémorise le pointeur sur le premier octet de la ressource retournée par LockResource_()
     Protected *lpIconesource.BITMAPINFOHEADER = 0
     
     
     
     If IS_INTRESOURCE(lpszName)
          ; c'est un pointeur sur une chaîne
          Find_Resource = FindResource_(hModule, PeekS(lpszName), #RT_ICON)
     Else
          ; c'est une valeur non un pointeur
          Find_Resource = FindResource_(hModule, MAKEINTRESOURCE(lpszName), #RT_ICON)
     EndIf
     
     
     ; l'API a échouée ? si oui on quitte, on passe au suivant
     If Find_Resource = #Null
          ProcedureReturn #True ; #True pour continuer l'opération
     EndIf
     
     ; on charge la ressource en mémoire, l'opération a réussie ?
     LoadResource = LoadResource_(hModule, Find_Resource)
     If LoadResource = #Null
          ProcedureReturn #True ; #True pour continuer l'opération
     EndIf
     
     
     ; *lpIconesource est un pointeur sur le premier octet de la ressource
     ; si *lpIconesource vaut 0, l'opération a échouée
     *lpIconesource = LockResource_(LoadResource)
     If *lpIconesource = #Null
          ProcedureReturn #True  ; #True pour continuer l'opération
     EndIf 
     
     ; retrouve la taille de l'icône
     If (*lpIconesource\biWidth = *Icon\size) And (*lpIconesource\biheight/2) = *Icon\size
          ; icone trouvé, on extrait
          ; ; Let the OS make us an icon
          *Icon\hIcon = CreateIconFromResourceEx_(*lpIconesource, SizeofResource_(hModule, Find_Resource), #True, $00030000, *Icon\size, *Icon\size, 0)
          ProcedureReturn #False   ; on stoppe l'énumération
     EndIf
     
     ProcedureReturn #True ; #true pour continuer l'opération
     
EndProcedure

Procedure.l Create_Icon_From_EXEFile(szFileName$, Size)
     ; mémorise le handle de l'exe ou dll ouvert
     Protected hLibrary = 0
     ; mémorise les données propres à l'icone
     Protected IconData.IconFind
     
     
     ; Load the DLL/EXE-NOTE : must be a 32bit EXE/DLL For this To work
     ; Charge Le fichier DLL/EXE, doit être au format PE (32 bits) pour fonctionner
     hLibrary = LoadLibraryEx_(szFileName$, #Null, #LOAD_LIBRARY_AS_DATAFILE)
     If hLibrary = #Null
          ; //Failed To load-abort
          ; Impossible de charger le module, on quitte
          Debug "Unable to load exe file/Impossible de charger le fichier exe"
          ProcedureReturn #Return_Error
     EndIf
     
     IconData\Size = Size
     
     ; enumerate icons in ressource
     EnumResourceNames_(hLibrary, #RT_ICON, @Enumerate_Icon(), @IconData)
     
     ; libère les ressources
     FreeLibrary_(hLibrary)
     
     ProcedureReturn IconData\hIcon
EndProcedure
et un petit exemple, changez la taille de l'icone voulue et bien sur le chemin de l'exe de votre choix

Code : Tout sélectionner

; init
Global icone = 0


;   Change here the size you want to get
Global size = 32


;   Change here the file name
Global File$ = "K:\PureBasic\Projets\Editeur d icones\Version 4\Essai_Icon.exe"

Global File$ = "C:\Program Files\adslTV\Uninstal.exe"

If OpenWindow(0, 0, 0, 300, 300, "Extraction icone", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
     
     icone = Create_Icon_From_EXEFile(File$, size)
     
     If icone = 0
       MessageRequester("Erreur","Aucune icone au format demandé", 16)
       End
     EndIf
     
     ImageGadget(0, (WindowWidth(0)-size)/2, (WindowHeight(0)-size)/2, 0, 0, icone, #PB_Image_Border)
     
     Repeat 
     Until WaitWindowEvent() = #PB_Event_CloseWindow
     
     ; don't forget to destroy icon
     If icone
          DestroyIcon_(icone)
     EndIf
EndIf
Dernière modification par Anonyme2 le ven. 26/déc./2008 9:22, modifié 1 fois.
SpaceMan
Messages : 290
Inscription : mar. 26/oct./2004 19:35
Contact :

Message par SpaceMan »

Interessant denis !
Merci
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

oui, tres interressant :D
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

J'ai fait des tests sous Vista mais ça ne fonctionnait pas. Le format vista compressé est 256 x 256 (règles MS)
J'ai ajouté un test sur la signature PNG de l'image car les données de la ressource dans ce cas n'ont rien à voir avec les valeurs comme la largeur etc mais sont des données propres à l'image. Comme il existe aussi des images 256 x 256 non compressées, j'ai modifié le code pour que ces icônes soient extraites également.

Ce code fonctionne pour les fichiers au format PE (32 bit) comme les dll/exe/icl.

Le format icl 16 bit (il est répandu sur internet) demande un code particulier pour retrouver la ressource (j'ai aussi écrit du code pour ce format) mais comme les infos manquent sur ce format, tous les fichiers ne sont pas conformes (souvent des problème d'intégrité du header du NE). Il vaut mieux convertir les icl 16 bits en icl 32 pour n'utiliser que le format 32 bits.

Code : Tout sélectionner

; http://www.purebasic.fr/english/viewtopic.php?t=35751
; 
EnableExplicit

#Return_Error = 0

; Utilisé pour charger une Dll, ICL, EXE en datafile (non executable)
#LOAD_LIBRARY_AS_DATAFILE = 2

; identifiant de l'icône vista compressé/Id of Vista packed icon
; les huit premiers octets d'un fichier PNG contiennent les valeurs décimales suivantes :
; 137 80 78 71 13 10 26 10
; The first eight bytes of a PNG file always contain the following (decimal) values: 
; 137 80 78 71 13 10 26 10
; 137 80 78 71 13 10 26 10  --> to a quad = $A1A0A0D474E5089
#Compression_Vista = $A1A0A0D474E5089


Structure IconFind
     Size.l
     hIcon.i
EndStructure


Macro HIWORD(Value)
     (Value>>16)
EndMacro

Macro LOWORD(Value)
     Value & $FFFF
EndMacro

Macro MAKEINTRESOURCE(INT)
     LOWORD(INT)
EndMacro

Macro IS_INTRESOURCE(Val)
     HIWORD(Val)
EndMacro


; ici commence la callback utilisé pour compter les icônes des DLL/EXE 32 bits
; here start callback used to count up DLL/EXE 32 bits icons

Procedure.l Enumerate_Icon(hModule, lpszType, lpszName, *Icon.IconFind)
     ; la fonction énumère les identifiants des d'icônes et pas des groupes d'icônes
     
     ; mémorise le handle du bloc d'information de la ressource recherchée
     Protected Find_Resource = 0
     ; mémorise le handle du bloc d'information des données de la ressource chargée
     Protected LoadResource = 0
     ; mémorise le pointeur sur le premier octet de la ressource retournée par LockResource_()
     Protected *lpIconesource.BITMAPINFOHEADER = 0
     
     
     
     If IS_INTRESOURCE(lpszName)
          ; c'est un pointeur sur une chaîne
          Find_Resource = FindResource_(hModule, PeekS(lpszName), #RT_ICON)
     Else
          ; c'est une valeur non un pointeur
          Find_Resource = FindResource_(hModule, MAKEINTRESOURCE(lpszName), #RT_ICON)
     EndIf
     
     
     ; l'API a échouée ? si oui on quitte, on passe au suivant
     If Find_Resource = #Null
          ProcedureReturn #True ; #True pour continuer l'opération
     EndIf
     
     ; on charge la ressource en mémoire, l'opération a réussie ?
     LoadResource = LoadResource_(hModule, Find_Resource)
     If LoadResource = #Null
          ProcedureReturn #True ; #True pour continuer l'opération
     EndIf
     
     
     ; *lpIconesource est un pointeur sur le premier octet de la ressource
     ; si *lpIconesource vaut 0, l'opération a échouée
     *lpIconesource = LockResource_(LoadResource)
     If *lpIconesource = #Null
          ProcedureReturn #True  ; #True pour continuer l'opération
     EndIf
     
     Select *Icon\size
          Case 256   ; format Vista 
               If PeekQ(*lpIconesource) = #Compression_Vista
                    ; icone trouvé, on extrait/ Let the OS make us an icon
                    *Icon\hIcon = CreateIconFromResourceEx_(*lpIconesource, SizeofResource_(hModule, Find_Resource), #True, $00030000, *Icon\size, *Icon\size, 0)
                    ProcedureReturn #False   ; on stoppe l'énumération
               ElseIf (*lpIconesource\biWidth = *Icon\size) And (*lpIconesource\biheight/2) = *Icon\size ; format 256x256 witout compression
                    ; icone trouvé, on extrait/ Let the OS make us an icon
                    *Icon\hIcon = CreateIconFromResourceEx_(*lpIconesource, SizeofResource_(hModule, Find_Resource), #True, $00030000, *Icon\size, *Icon\size, 0)
                    ProcedureReturn #False   ; on stoppe l'énumération
               EndIf
               
          Default ; autres formats
               ; retrouve la taille de l'icône
               If (*lpIconesource\biWidth = *Icon\size) And (*lpIconesource\biheight/2) = *Icon\size
                    ; icone trouvé, on extrait/ Let the OS make us an icon
                    *Icon\hIcon = CreateIconFromResourceEx_(*lpIconesource, SizeofResource_(hModule, Find_Resource), #True, $00030000, *Icon\size, *Icon\size, 0)
                    ProcedureReturn #False   ; on stoppe l'énumération
               EndIf
               
     EndSelect
     
     
     ProcedureReturn #True ; #true pour continuer l'opération
     
EndProcedure

Procedure.l Create_Icon_From_EXEFile(szFileName$, Size)
     ; mémorise le handle de l'exe ou dll ouvert
     Protected hLibrary = 0
     ; mémorise les données propres à l'icone
     Protected IconData.IconFind
     
     
     ; Load the DLL/EXE-NOTE : must be a 32bit EXE/DLL For this To work
     ; Charge Le fichier DLL/EXE, doit être au format PE (32 bits) pour fonctionner
     hLibrary = LoadLibraryEx_(szFileName$, #Null, #LOAD_LIBRARY_AS_DATAFILE)
     If hLibrary = #Null
          ; //Failed To load-abort
          ; Impossible de charger le module, on quitte
          Debug "Unable to load exe file/Impossible de charger le fichier exe"
          ProcedureReturn #Return_Error
     EndIf
     
     IconData\Size = Size
     
     ; enumerate icons in ressource
     EnumResourceNames_(hLibrary, #RT_ICON, @Enumerate_Icon(), @IconData)
     
     ; libère les ressources
     FreeLibrary_(hLibrary)
     ProcedureReturn IconData\hIcon 
EndProcedure


; init
Global icone = 0


;   Change here the size you want to get
Global size = 256


;   Change here the file name

Global File$ = "C:\Windows\System32\ntprint.exe"

Global File$ = "C:\Windows\System32\odbcad32.exe"

Global File$ = "H:\Icl\AAA.icl"

Global File$ = "K:\PureBasic\Projets\Editeur d icones\Version 4\Essai_Icon.exe"


If OpenWindow(0, 0, 0, 300, 300, "Extraction icone", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
     
     icone = Create_Icon_From_EXEFile(File$, size)
     
     If icone = 0
          MessageRequester("Erreur", "Aucune icone au format demandé", 16)
          End
     EndIf
     
     ImageGadget(0, (WindowWidth(0)-size)/2, (WindowHeight(0)-size)/2, 0, 0, icone, #PB_Image_Border)
     
     Repeat
     Until WaitWindowEvent() = #PB_Event_CloseWindow
     
     ; don't forget to destroy icon
     If icone
          DestroyIcon_(icone)
     EndIf
EndIf
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

Pour le moment, moi, dans ma lib IconEx, pour charger une icone particulière dans le programme (format et taille voulu d'une icone), je prenait l'icône avec tous les formats, j'isolais le format souhaité et je crée une icone virtuel en mémoire ne comportant que le format souhaité
Ensuite, je charge l'icône avec CatchImage

Mais je ne sais pas si ca marche avec une icône Vista
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Heu, en fait c'est ce que je fais ... :?:
sauf pour le format
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

oui, mais ma lecture du format, moi, elle est plutot empirique ... :oops:
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

J'ai fait des tests sous XP, XP professionnel et Win2000 professionnel, toutes les API des ressources suivantes fonctionnent même pour les icônes compressées Vista, le système n'analyse pas le type de ressource avec ces fonctions :

FindResource_()
LoadResource_()
LockResource_()
SizeofResource_()

Lockressource donne un pointeur sur les données de l'image, donc sous les OS qui ne supportent pas les images compressées Vista, l'API CreateIconFromResourceEx échoue.

J'ai écrit un petite procedure pour créer tout de même une icône Vista sous ces OS (ou plutôt une icône décodée au format RVBA), bien qu'ils ne puissent pas l'afficher correctement du fait de la couche alpha.

Certaines icônes Vista ont une profondeur de couleurs de 16 ou 256 couleus définie dans la ressource. J'ai beaucoup de mal à comprendre car l'image PNG elle a vraiment une profondeur sur 32 bit (24 pour la couleur et 8 bits de couche alpha).
J'ai utilisé le décodage PB et j'ai bien une profondeur de 32, j'ai utilisé la librairie Freeimage et c'est pareil, j'ai décodé le segment IHDR avec mon propre code et c'est toujours une profondeur de 32, aucun segment définissant une palette de couleurs. Je cherche toujours à comprendre.

Voilà la fonction que j'utilise pour créer une icône Vista, sachant qu'elle aura toujours une profondeur de 32 (24 bit de couleurs (RVB) et 8 bits pour la couche alpha).

Code : Tout sélectionner

;- Structures Image
Structure Image
     StructureUnion
          bm.BITMAP
          pii.ICONINFO
     EndStructureUnion
EndStructure


Procedure.l BitmapToIcon(hBmpSrc, width, height)
     
     ;///////////////////////////////////////////////////////////////////////////////////////////////////
     ;
     ; FONCTION: BitmapToIcon()
     ; 
     ; BUT: créer une icône depuis l'image Bmp passée en paramètre par hBmpSrc
     ;
     ; PARAMS: hBmpSrc - identifiant dynamique de l'image bitmap à convertir en icône
     ;         hBmpSrc = ImageId(#image)
     ;         width - largeur de l'icône
     ;         width - hauteur de l'icône
     ;
     ; RETOURNE: le handle Microsoft sur l'icône, qui est détruit ensuite par la fonction
     ;           appelante
     ;           Retourne #Return_Error (= 0) en cas d'erreur
     ;
     ;///////////////////////////////////////////////////////////////////////////////////////////////////
     
     
     
     ;// mémorise le handle du contexte de périphérique (hdc)
     Protected hdc
     ;// mémorise le handle de l'icône créée
     Protected LocalIcon
     ;// mémorise le handle de l'image bmp crée pour le masque de l'icône créée
     Protected BmpCreated
     ;// mémoire partagée pour retrouver les infos du bitmap puis celle de l'icône
     Protected Var.Image
     
     
     
     ;// retrouve les informations sur l'image passée en paramètre
     If GetObject_(hBmpSrc, SizeOf(BITMAP), 0) = #Return_Error
          ProcedureReturn #Return_Error
     EndIf
     
     ;// crée un contexte de périphérique basée compatible avec l'écran courant
     hdc = CreateCompatibleDC_(0)
     If hdc = #Return_Error
          ProcedureReturn #Return_Error
     EndIf
     
     ;// crée un bitmap compatible avec le périphérique basé sur le hdc
     BmpCreated = CreateCompatibleBitmap_(hdc, width, height)
     If BmpCreated = #Return_Error
          DeleteDC_(hdc)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// remplissage des champs de la variable (pour l'icône
     Var\pii.ICONINFO\fIcon = #True
     Var\pii\hbmMask = BmpCreated
     Var\pii\hbmColor = hBmpSrc
     
     ;// création de l'icône
     LocalIcon = CreateIconIndirect_(@Var)
     
     ;// libération des ressources des divers éléments créés
     DeleteDC_(hdc)
     DeleteObject_(BmpCreated)
     DeleteObject_(Var\pii\hbmMask)
     DeleteObject_(Var\pii\hbmColor)
     
     ;// retourne le handle de l'icône
     ProcedureReturn LocalIcon
EndProcedure
Srod a publié sur le forum anglais une procedure qui s'appelle SaveIcon() et qui fonctionne bien, je l'utilise en l'ayant modifié un peu. Tu fais une recherche sur le forum anglais avec SaveIcon et tu peux l'utiliser, tu passes le handle de l'icône Vista décompressée (le résultat de la procédure ci-dessus) et le nom de fichier .ico pour l'enregistrer.

Maintenant, pour décoder l'icône vista même sous un OS autre que Vista, j'utilise ce code

Lorsque tu as le pointeur retourné par LockResource_() (*lpIconesource dans l'exemple ci-dessous), tu fais ceci :

Code : Tout sélectionner

#Compression_Vista = $A1A0A0D474E5089
If PeekQ(*lpIconesource) = #Compression_Vista 
      UsePNGImageDecoder()
      hBmpSrc = CatchImage(#PB_Any, *lpIconesource)
      
      If hBmpSrc
           hIcon = BitmapToIcon(ImageID(hBmpSrc), width, height)
           If hIcon
                ; ici hIcon est le handle de l'icône
                ; tu fais ce que tu veux avec le handle
           endif

           ; destruction de l'icône
           DestroyIcon_(hIcon) : hIcon = 0

           ; destruction de l'image PB
           FreeImage(hBmpSrc) : hBmpSrc = 0
      EndIf

else
   ; ce n'est pas une icône vista
endif
A+
Répondre