Maison développement back-end Golang Modification de l'icône du programme Golang

Modification de l'icône du programme Golang

May 10, 2023 pm 08:37 PM

Lorsque nous utilisons des ordinateurs tous les jours, nous devons souvent ouvrir certains programmes couramment utilisés. Ces programmes afficheront une icône spécifique sur notre interface afin que nous puissions les identifier et les trouver rapidement. Mais dans certains cas, nous souhaiterons peut-être modifier ces icônes de programme, par exemple pour les rendre plus cohérentes avec nos préférences ou thèmes personnels.

Dans cet article, nous nous concentrerons sur la façon d'utiliser Golang et certaines bibliothèques système pour changer l'icône du programme. Nous utiliserons Windows comme environnement de démonstration.

Tout d'abord, décrivons les étapes de base que nous devons suivre :

  1. Ouvrez le fichier de ressources du programme (fichier .exe ou .dll) et recherchez sa ressource icône.
  2. Ajoutez de nouvelles ressources d'icônes au fichier de ressources du programme.
  3. Modifiez le fichier .manifest du programme afin qu'il puisse accéder à la nouvelle ressource d'icône.

Ensuite, nous discuterons de la manière de réaliser ces étapes une par une.

Première étape : ouvrez le fichier de ressources et recherchez l'icône de ressource

Dans Golang, nous pouvons utiliser la fonction de la bibliothèque système "syscall" pour ouvrir et lire le fichier. Pour ce faire, nous devons définir quelques variables nécessaires :

package main

import (
    "os"
    "syscall"
    "unsafe"
)

var (
    kernel32DLL                             = syscall.MustLoadDLL("kernel32.dll")
    BeginUpdateResourceProc     = kernel32DLL.MustFindProc("BeginUpdateResourceW")
    UpdateResourceProc              = kernel32DLL.MustFindProc("UpdateResourceW")
    EndUpdateResourceProc       = kernel32DLL.MustFindProc("EndUpdateResourceW")
)
Copier après la connexion

Nous utilisons ici plusieurs fonctions dans l'API Windows, à savoir "BeginUpdateResourceW", "UpdateResourceW" et "EndUpdateResourceW". Ces fonctions peuvent nous aider à exploiter les ressources du fichier de ressources du programme.

Ensuite, nous devons ouvrir le fichier de ressources du programme que nous voulons modifier (il peut s'agir d'un fichier .exe ou .dll) et trouver sa ressource icône. Ici, nous utilisons une fonction appelée "findIconIndex" pour parcourir le fichier de ressources du programme et trouver le numéro d'index où se trouve sa ressource d'icône.

func findIconIndex(exePath string) (int, error) {
    exeFile, err := os.OpenFile(exePath, os.O_RDWR, 0666)
    defer exeFile.Close()
    if err != nil {
        return 0, err
    }
    exeStat, err := exeFile.Stat()
    if err != nil {
        return 0, err
    }
    exeSize := exeStat.Size()

    // DOS header
    dosHeader := new(image.DosHeader)
    err = binary.Read(exeFile, binary.LittleEndian, dosHeader)
    if err != nil {
        return 0, err
    }
    exeFile.Seek(int64(dosHeader.Lfanew), 0)

    // File header and optional header
    fileHeader := new(image.FileHeader)
    err = binary.Read(exeFile, binary.LittleEndian, fileHeader)
    if err != nil {
        return 0, err
    }
    extHeader := make([]byte, fileHeader.SizeOfOptionalHeader-2)
    exeFile.Read(extHeader)

    // Section headers
    sections := make([]image.SectionHeader, fileHeader.NumberOfSections)
    err = binary.Read(exeFile, binary.LittleEndian, sections)
    if err != nil {
        return 0, err
    }

    // Find icon resource
    for _, section := range sections {
        if section.Name == ".rsrc" {
            exeFile.Seek(int64(section.Offset), 0)
            resourceHeader := new(resourceHeader)
            err = binary.Read(exeFile, binary.LittleEndian, resourceHeader)
            if err != nil {
                return 0, err
            }
            stack := []resourceDirectoryEntry{resourceDirectoryEntry{uint32(resourceHeader.RootID), int64(resourceHeader.OffsetToDirectory)}}
            for len(stack) > 0 {
                currentEntry := stack[len(stack)-1]
                stack = stack[:len(stack)-1]
                exeFile.Seek(currentEntry.offset, 0)
                directoryHeader := new(resourceDirectoryHeader)
                err = binary.Read(exeFile, binary.LittleEndian, directoryHeader)
                if err != nil {
                    return 0, err
                }
                entries := make([]resourceDirectoryEntry, directoryHeader.NumNamedEntries+directoryHeader.NumIDEntries)
                for i := range entries {
                    err = binary.Read(exeFile, binary.LittleEndian, &entries[i])
                    if err != nil {
                        return 0, err
                    }
                    if entries[i].nameIsString {
                        nameBytes := make([]byte, entries[i].nameOffset&0x7FFFFFFF)
                        exeFile.Read(nameBytes)
                        entries[i].name = syscall.UTF16ToString(nameBytes)
                    }
                }
                for _, entry := range entries {
                    if entry.ID&^0xFFFF == rtIcon {
                        return int(entry.ID & 0xFFFF), nil
                    } else if entry.name == "ICON" {
                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})
                    } else if entry.name == "#0" && entry.ID&^0xFFFF == rtGroupIcon {
                        groupIconDirHeader := new(resourceGroupIconDirectoryHeader)
                        exeFile.Seek(int64(entry.offset), 0)
                        err = binary.Read(exeFile, binary.LittleEndian, groupIconDirHeader)
                        if err != nil {
                            return 0, err
                        }
                        var largestIcon resourceGroupIconDirectoryEntry
                        for i := 0; i < int(groupIconDirHeader.Count); i++ {
                            groupIconDirEntry := new(resourceGroupIconDirectoryEntry)
                            err = binary.Read(exeFile, binary.LittleEndian, groupIconDirEntry)
                            if err != nil {
                                return 0, err
                            }
                            if groupIconDirEntry.Width > largestIcon.Width || groupIconDirEntry.Height > largestIcon.Height {
                                largestIcon = *groupIconDirEntry
                            }
                        }
                        return int(largestIcon.ID), nil
                    } else if entry.name == "ICONGROUP" {
                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})
                    } else if entry.name == "MAINICON" {
                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})
                    } else {
                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})
                    }
                }
            }
            return 0, fmt.Errorf("Icon not found")
        }
    }
    return 0, fmt.Errorf("Resource not found")
}
Copier après la connexion

Cette fonction parcourt chaque section (.rsrc) du fichier de ressources du programme et trouve l'index de la ressource icône. En règle générale, l'indexation dépend de la taille et du format de la ressource icône. Nous pouvons décider à notre propre discrétion de l'index de la ressource icône à modifier dans le fichier de ressources.

Étape 2 : Ajouter la nouvelle ressource d'icône au fichier de ressources

Pour ajouter la nouvelle ressource d'icône au fichier de ressources du programme, nous devons d'abord l'enregistrer au format de fichier ICO. Nous pouvons utiliser la bibliothèque d'images de Golang pour créer des fichiers ICO.

package main

import (
    "image"
    "image/draw"
    "image/png"
    "os"
)

func writeIcoFile(icon image.Image, filename string) error {
    file, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer file.Close()

    // Create icon file header
    iconSize := icon.Bounds().Size()
    fileHeader := new(resourceIconFileHeader)
    fileHeader.Reserved = 0
    fileHeader.Type = 1
    fileHeader.Count = 1

    // Create icon directory entry
    dirEntry := new(resourceIconDirectoryEntry)
    dirEntry.Width = uint8(iconSize.X)
    dirEntry.Height = uint8(iconSize.Y)
    dirEntry.Colors = 0
    dirEntry.Reserved = 0
    dirEntry.Plane = 1
    dirEntry.BitCount = 32
    dirEntry.SizeInBytes = uint32(40 + 4*iconSize.X*iconSize.Y)
    dirEntry.Offset = 22

    // Create bitmap info header and color mask for bitmap graphics
    colorMask := [12]byte{0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00}
    infoHeader := new(bitmapInfoHeader)
    infoHeader.Size = 40
    infoHeader.Width = int32(iconSize.X)
    infoHeader.Height = int32(2 * iconSize.Y)
    infoHeader.Planes = 1
    infoHeader.BitCount = 32
    infoHeader.Compression = 0
    infoHeader.SizeImage = uint32(4 * iconSize.X * iconSize.Y)
    infoHeader.XPelsPerMeter = 0
    infoHeader.YPelsPerMeter = 0
    infoHeader.ClrUsed = 0
    infoHeader.ClrImportant = 0

    // Write icon file header, directory entry, bitmap info header and color mask
    binary.Write(file, binary.LittleEndian, fileHeader)
    binary.Write(file, binary.LittleEndian, dirEntry)
    binary.Write(file, binary.LittleEndian, infoHeader)
    binary.Write(file, binary.LittleEndian, colorMask)

    // Write bitmap graphics
    rgba := image.NewRGBA(image.Rect(0, 0, iconSize.X, 2*iconSize.Y))
    draw.Draw(rgba, rgba.Bounds(), image.Black, image.ZP, draw.Src)
    draw.Draw(rgba, image.Rect(0, 0, iconSize.X, iconSize.Y), icon, image.ZP, draw.Over)
    draw.Draw(rgba, image.Rect(0, iconSize.Y, iconSize.X, 2*iconSize.Y), image.Transparent, image.ZP, draw.Src)
    err = png.Encode(file, rgba)
    if err != nil {
        return err
    }

    return nil
}
Copier après la connexion

Cette fonction crée un en-tête de fichier ICO et y attache la ressource icône. L'en-tête du fichier ICO contient les informations nécessaires sur les ressources d'icônes dans le fichier ICO.

Ensuite, nous les écrivons dans des fichiers de ressources. Nous devons utiliser les fonctions "BeginUpdateResource", "UpdateResource" et "EndUpdateResource" dans l'API Windows pour ce faire.

func updateIcon(exePath, icoPath string, iconIndex int) error {
    exeFile, err := os.OpenFile(exePath, os.O_RDWR, 0666)
    defer exeFile.Close()
    if err != nil {
        return err
    }

    icoFile, err := os.Open(icoPath)
    defer icoFile.Close()
    if err != nil {
        return err
    }

    // Read ICO file and prepare icon directory entry
    icoData, err := ioutil.ReadAll(icoFile)
    if err != nil {
        return err
    }
    dirEntry := new(resourceIconDirectoryEntry)
    dirEntry.Width = 0
    dirEntry.Height = 0
    dirEntry.Colors = 0
    dirEntry.Reserved = 0
    dirEntry.Plane = 1
    dirEntry.BitCount = 0
    dirEntry.SizeInBytes = uint32(len(icoData))
    dirEntry.Offset = 22

    // Find update handle
    exeHandle, err := syscall.CreateFile(syscall.StringToUTF16Ptr(exePath), syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
    if err != nil {
        return err
    }
    defer syscall.CloseHandle(exeHandle)
    updateHandle, _, err := BeginUpdateResourceProc.Call(uintptr(exeHandle), 0)
    defer syscall.CloseHandle(syscall.Handle(updateHandle))
    if updateHandle == 0 {
        return fmt.Errorf("BeginUpdateResourceW failed")
    }

    // Write resource to update handle
    success, _, err := UpdateResourceProc.Call(uintptr(updateHandle), uintptr(rtIcon), uintptr(iconIndex), 0, uintptr(unsafe.Pointer(&icoData[0])), uintptr(len(icoData)))
    if success == 0 {
        return fmt.Errorf("UpdateResourceW failed")
    }

    // Write updated icon directory entry
    success, _, err = UpdateResourceProc.Call(uintptr(updateHandle), uintptr(rtGroupIcon), uintptr(MAKEINTRESOURCE(iconIndex)), 0, uintptr(unsafe.Pointer(dirEntry)), uintptr(unsafe.Sizeof(*dirEntry)))
    if success == 0 {
        return fmt.Errorf("UpdateResourceW failed")
    }

    // Commit update handle
    success, _, err = EndUpdateResourceProc.Call(updateHandle, 0)
    if success == 0 {
        return fmt.Errorf("EndUpdateResourceW failed")
    }

    return nil
}
Copier après la connexion

Étape 3 : Modifiez le fichier .manifest du programme

Nous devons modifier le fichier .manifest du programme afin qu'il puisse accéder à la nouvelle ressource d'icône. Pour ce faire, nous devons ajouter ce qui suit au fichier .manifest :

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" name="MyApplication" version="1.0.0.0" processorArchitecture="x86" />
  <icon type="group">MyIconResourceIndex</icon>
</assembly>
Copier après la connexion

Cela attribuera un numéro d'index de ressource d'icône au programme afin qu'il puisse utiliser la nouvelle ressource d'icône. Nous pouvons utiliser la bibliothèque os de Golang pour modifier le fichier .manifest.

func updateManifest(manifestPath string, iconIndex int) error {
    manifestData, err := ioutil.ReadFile(manifestPath)
    if err != nil {
        return err
    }

    updatedManifest := strings.Replace(string(manifestData), "</assembly>", "  <icon type="group">"+strconv.Itoa(iconIndex)+"</icon>
</assembly>", 1)

    err = ioutil.WriteFile(manifestPath, []byte(updatedManifest), 0666)
    if err != nil {
        return err
    }

    return nil
}
Copier après la connexion

Maintenant, nous savons comment changer l'icône du programme à l'aide de Golang et des bibliothèques système. En rassemblant ces étapes, nous construisons une fonctionnalité complète. Voici un exemple de code :

package main

import (
    "encoding/binary"
    "encoding/hex"
    "fmt"
    "image"
    "image/png"
    "io/ioutil"
    "os"
    "strconv"
    "strings"
    "syscall"
    "unsafe"
)

const (
    rtIcon        = 14
    rtGroupIcon   = rtIcon + 11
    LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020
)

// Resource header
type resourceHeader struct {
    RootID        uint16
    RootType      uint16
    RootName      [16]uint16
    RootDataSize  uint32
    RootDataVer   uint32
    RootDate      uint32
    RootRMLow     uint16
    RootRMHigh    uint16
    RootLangID    uint16
    RootDataVerOS uint32
}

// Resource directory header
type resourceDirectoryHeader struct {
    Characteristics uint32
    TimeDateStamp   uint32
    VersionMajor    uint16
    VersionMinor    uint16
    NumNamedEntries uint16
    NumIDEntries    uint16
}

// Resource directory entry
type resourceDirectoryEntry struct {
    nameIsString bool
    ID           uint32
    offset       uint32
    nameOffset   uint32
    name         string
}

// Resource icon file header
type resourceIconFileHeader struct {
    Reserved uint16
    Type     uint16
    Count    uint16
}

// Resource icon directory entry
type resourceIconDirectoryEntry struct {
    Width       uint8
    Height      uint8
    Colors      uint8
    Reserved    uint8
    Plane       uint16
    BitCount    uint16
    SizeInBytes uint32
    Offset      uint32
}

// Resource group icon directory header
type resourceGroupIconDirectoryHeader struct {
    Width    uint16
    Height   uint16
    ColorCount uint16
    Reserved uint16
    Planes   uint16
    BitCount uint16
    Count    uint32
}

// Resource group icon directory entry
type resourceGroupIconDirectoryEntry struct {
    Width      uint8
    Height     uint8
    ColorCount uint8
    Reserved   uint8
    Planes     uint16
    BitCount   uint16
    BytesInRes uint32
    ID         uint16
}

// Bitmap header
type bitmapInfoHeader struct {
    Size          uint32
    Width         int32
    Height        int32
    Planes        uint16
    BitCount      uint16
    Compression   uint32
    SizeImage     uint32
    XPelsPerMeter int32
    YPelsPerMeter int32
    ClrUsed       uint32
    ClrImportant  uint32
}

var (
    kernel32DLL                = syscall.MustLoadDLL("kernel32.dll")
    user32DLL                  = syscall.MustLoadDLL("user32.dll")
    autoDetectEncodingProc     = kernel32DLL.MustFindProc("AutoDetectEncoding")
    BeginUpdateResourceProc    = kernel32DLL.MustFindProc("BeginUpdateResourceW")
    LoadImageProc              = user32DLL.MustFindProc("LoadImageW")
    ResourceNotFound         = fmt.Errorf("Resource not found")
    NoIconFound             = fmt.Errorf("Icon not found")
)

func main() {
    exePath := "path/to/program.exe"
    icoPath := "path/to/newicon.png"
    manifestPath := "path/to/program.exe.manifest"
    iconIndex, err := findIconIndex(exePath)
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Quelles sont les vulnérabilités de Debian OpenSSL Quelles sont les vulnérabilités de Debian OpenSSL Apr 02, 2025 am 07:30 AM

OpenSSL, en tant que bibliothèque open source largement utilisée dans les communications sécurisées, fournit des algorithmes de chiffrement, des clés et des fonctions de gestion des certificats. Cependant, il existe des vulnérabilités de sécurité connues dans sa version historique, dont certaines sont extrêmement nocives. Cet article se concentrera sur les vulnérabilités et les mesures de réponse communes pour OpenSSL dans Debian Systems. DebianopenSSL CONNUTS Vulnérabilités: OpenSSL a connu plusieurs vulnérabilités graves, telles que: la vulnérabilité des saignements cardiaques (CVE-2014-0160): cette vulnérabilité affecte OpenSSL 1.0.1 à 1.0.1F et 1.0.2 à 1.0.2 Versions bêta. Un attaquant peut utiliser cette vulnérabilité à des informations sensibles en lecture non autorisées sur le serveur, y compris les clés de chiffrement, etc.

Quelles bibliothèques sont utilisées pour les opérations du numéro de point flottantes en Go? Quelles bibliothèques sont utilisées pour les opérations du numéro de point flottantes en Go? Apr 02, 2025 pm 02:06 PM

La bibliothèque utilisée pour le fonctionnement du numéro de point flottante dans le langage go présente comment s'assurer que la précision est ...

Quel est le problème avec le fil de file d'attente dans GO's Crawler Colly? Quel est le problème avec le fil de file d'attente dans GO's Crawler Colly? Apr 02, 2025 pm 02:09 PM

Problème de threading de file d'attente dans Go Crawler Colly explore le problème de l'utilisation de la bibliothèque Crawler Crawler dans le langage Go, les développeurs rencontrent souvent des problèmes avec les threads et les files d'attente de demande. � ...

Méthode de surveillance postgresql sous Debian Méthode de surveillance postgresql sous Debian Apr 02, 2025 am 07:27 AM

Cet article présente une variété de méthodes et d'outils pour surveiller les bases de données PostgreSQL sous le système Debian, vous aidant à saisir pleinement la surveillance des performances de la base de données. 1. Utilisez PostgreSQL pour reprendre la surveillance Afficher PostgreSQL lui-même offre plusieurs vues pour surveiller les activités de la base de données: PG_STAT_ACTIVITY: affiche les activités de la base de données en temps réel, y compris les connexions, les requêtes, les transactions et autres informations. PG_STAT_REPLIcation: surveille l'état de réplication, en particulier adapté aux grappes de réplication de flux. PG_STAT_DATABASE: Fournit des statistiques de base de données, telles que la taille de la base de données, les temps de validation / recul des transactions et d'autres indicateurs clés. 2. Utilisez l'outil d'analyse de journaux pgbadg

Transformant du développement frontal au développement back-end, est-il plus prometteur d'apprendre Java ou Golang? Transformant du développement frontal au développement back-end, est-il plus prometteur d'apprendre Java ou Golang? Apr 02, 2025 am 09:12 AM

Chemin d'apprentissage du backend: le parcours d'exploration du front-end à l'arrière-end en tant que débutant back-end qui se transforme du développement frontal, vous avez déjà la base de Nodejs, ...

Dans Go, pourquoi les chaînes d'impression avec println et string () ont-elles des effets différents? Dans Go, pourquoi les chaînes d'impression avec println et string () ont-elles des effets différents? Apr 02, 2025 pm 02:03 PM

La différence entre l'impression de chaîne dans le langage go: la différence dans l'effet de l'utilisation de fonctions println et string () est en Go ...

Comment résoudre le problème de conversion de type user_id lors de l'utilisation du flux redis pour implémenter les files d'attente de messages dans le langage Go? Comment résoudre le problème de conversion de type user_id lors de l'utilisation du flux redis pour implémenter les files d'attente de messages dans le langage Go? Apr 02, 2025 pm 04:54 PM

Le problème de l'utilisation de Redessstream pour implémenter les files d'attente de messages dans le langage GO consiste à utiliser le langage GO et redis ...

Comment spécifier la base de données associée au modèle de Beego ORM? Comment spécifier la base de données associée au modèle de Beego ORM? Apr 02, 2025 pm 03:54 PM

Dans le cadre du cadre de beegoorm, comment spécifier la base de données associée au modèle? De nombreux projets Beego nécessitent que plusieurs bases de données soient opérées simultanément. Lorsque vous utilisez Beego ...

See all articles