none
Modificar ícone de um .net RRS feed

  • Discussão Geral

  • Olá

    Gente, reabrindo tópico. Preciso de um console ou código para alterar o ícone de um arquivo .net. Tenho uma ferramenta simples que cria um executável e o ícone deve ser personalizado conforme escolhido pelo usuário.

    Não quero Resource Hacker ou outro editor de recursos, pois meu software é bem leve, e tem que ser feito tudo automaticamente.

    Achei na net um código, mas não funciona com alguns executáveis:

    Imports System.Runtime.InteropServices
    Imports System.Security
    Public Class __
    
        <SuppressUnmanagedCodeSecurity()>
            Private Class NativeMethods
                <DllImport("kernel32")>
                Public Shared Function BeginUpdateResource(
                ByVal fileName As String,
                <MarshalAs(UnmanagedType.Bool)> ByVal deleteExistingResources As Boolean) As IntPtr
                End Function
    
                <DllImport("kernel32")>
                Public Shared Function UpdateResource(
                ByVal hUpdate As IntPtr,
                ByVal type As IntPtr,
                ByVal name As IntPtr,
                ByVal language As Short,
                <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=5)>
                ByVal data() As Byte,
                ByVal dataSize As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
                End Function
    
                <DllImport("kernel32")>
                Public Shared Function EndUpdateResource(
                ByVal hUpdate As IntPtr,
                <MarshalAs(UnmanagedType.Bool)> ByVal discard As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
                End Function
            End Class
            <StructLayout(LayoutKind.Sequential)>
            Private Structure ICONDIR
                Public Reserved As UShort
                Public Type As UShort
                Public Count As UShort
            End Structure
            <StructLayout(LayoutKind.Sequential)>
            Private Structure ICONDIRENTRY
                Public Width As Byte
                Public Height As Byte
                Public ColorCount As Byte
                Public Reserved As Byte
                Public Planes As UShort
                Public BitCount As UShort
                Public BytesInRes As Integer
                Public ImageOffset As Integer
            End Structure
            <StructLayout(LayoutKind.Sequential)>
            Private Structure BITMAPINFOHEADER
                Public Size As UInteger
                Public Width As Integer
                Public Height As Integer
                Public Planes As UShort
                Public BitCount As UShort
                Public Compression As UInteger
                Public SizeImage As UInteger
                Public XPelsPerMeter As Integer
                Public YPelsPerMeter As Integer
                Public ClrUsed As UInteger
                Public ClrImportant As UInteger
            End Structure
    
            <StructLayout(LayoutKind.Sequential, Pack:=2)>
            Private Structure GRPICONDIRENTRY
                Public Width As Byte
                Public Height As Byte
                Public ColorCount As Byte
                Public Reserved As Byte
                Public Planes As UShort
                Public BitCount As UShort
                Public BytesInRes As Integer
                Public ID As UShort
            End Structure
    
            Public Shared Sub InjectIcon(ByVal exeFileName As String, ByVal iconFileName As String)
                InjectIcon(exeFileName, iconFileName, 1, 1)
            End Sub
    
            Public Shared Sub InjectIcon(ByVal exeFileName As String, ByVal iconFileName As String, ByVal iconGroupID As UInteger, ByVal iconBaseID As UInteger)
                Const RT_ICON = 3UI
                Const RT_GROUP_ICON = 14UI
                Dim iconFile As IconFile = IconFile.FromFile(iconFileName)
                Dim hUpdate = NativeMethods.BeginUpdateResource(exeFileName, False)
                Dim data = iconFile.CreateIconGroupData(iconBaseID)
                NativeMethods.UpdateResource(hUpdate, New IntPtr(RT_GROUP_ICON), New IntPtr(iconGroupID), 0, data, data.Length)
                For i = 0 To iconFile.ImageCount - 1
                    Dim image = iconFile.ImageData(i)
                    NativeMethods.UpdateResource(hUpdate, New IntPtr(RT_ICON), New IntPtr(iconBaseID + i), 0, image, image.Length)
                Next
                NativeMethods.EndUpdateResource(hUpdate, False)
            End Sub
    
            Private Class IconFile
    
                Private iconDir As New ICONDIR
                Private iconEntry() As ICONDIRENTRY
                Private iconImage()() As Byte
    
                Public ReadOnly Property ImageCount() As Integer
                    Get
                        Return iconDir.Count
                    End Get
                End Property
    
                Public ReadOnly Property ImageData(ByVal index As Integer) As Byte()
                    Get
                        Return iconImage(index)
                    End Get
                End Property
    
                Private Sub New()
                End Sub
    
                Public Shared Function FromFile(ByVal filename As String) As IconFile
                    Dim instance As New IconFile
                    Dim fileBytes() As Byte = IO.File.ReadAllBytes(filename)
                    Dim pinnedBytes = GCHandle.Alloc(fileBytes, GCHandleType.Pinned)
                    instance.iconDir = DirectCast(Marshal.PtrToStructure(pinnedBytes.AddrOfPinnedObject, GetType(ICONDIR)), ICONDIR)
                    instance.iconEntry = New ICONDIRENTRY(instance.iconDir.Count - 1) {}
                    instance.iconImage = New Byte(instance.iconDir.Count - 1)() {}
                    Dim offset = Marshal.SizeOf(instance.iconDir)
                    Dim iconDirEntryType = GetType(ICONDIRENTRY)
                    Dim size = Marshal.SizeOf(iconDirEntryType)
                    For i = 0 To instance.iconDir.Count - 1
                        Dim entry = DirectCast(Marshal.PtrToStructure(New IntPtr(pinnedBytes.AddrOfPinnedObject.ToInt64 + offset), iconDirEntryType), ICONDIRENTRY)
                        instance.iconEntry(i) = entry
                        instance.iconImage(i) = New Byte(entry.BytesInRes - 1) {}
                        Buffer.BlockCopy(fileBytes, entry.ImageOffset, instance.iconImage(i), 0, entry.BytesInRes)
                        offset += size
                    Next
                    pinnedBytes.Free()
                    Return instance
                End Function
    
                Public Function CreateIconGroupData(ByVal iconBaseID As UInteger) As Byte()
                    Dim sizeOfIconGroupData As Integer = Marshal.SizeOf(GetType(ICONDIR)) + Marshal.SizeOf(GetType(GRPICONDIRENTRY)) * ImageCount
                    Dim data(sizeOfIconGroupData - 1) As Byte
                    Dim pinnedData = GCHandle.Alloc(data, GCHandleType.Pinned)
                    Marshal.StructureToPtr(iconDir, pinnedData.AddrOfPinnedObject, False)
                    Dim offset = Marshal.SizeOf(iconDir)
                    For i = 0 To ImageCount - 1
                        Dim grpEntry As New GRPICONDIRENTRY
                        Dim bitmapheader As New BITMAPINFOHEADER
                        Dim pinnedBitmapInfoHeader = GCHandle.Alloc(bitmapheader, GCHandleType.Pinned)
                        Marshal.Copy(ImageData(i), 0, pinnedBitmapInfoHeader.AddrOfPinnedObject, Marshal.SizeOf(GetType(BITMAPINFOHEADER)))
                        pinnedBitmapInfoHeader.Free()
                        grpEntry.Width = iconEntry(i).Width
                        grpEntry.Height = iconEntry(i).Height
                        grpEntry.ColorCount = iconEntry(i).ColorCount
                        grpEntry.Reserved = iconEntry(i).Reserved
                        grpEntry.Planes = bitmapheader.Planes
                        grpEntry.BitCount = bitmapheader.BitCount
                        grpEntry.BytesInRes = iconEntry(i).BytesInRes
                        grpEntry.ID = CType(iconBaseID + i, UShort)
                        Marshal.StructureToPtr(grpEntry, New IntPtr(pinnedData.AddrOfPinnedObject.ToInt64 + offset), False)
                        offset += Marshal.SizeOf(GetType(GRPICONDIRENTRY))
                    Next
                    pinnedData.Free()
                    Return data
                End Function
    
            End Class
    
    End Class

    Se alguém puder me ajudar.

    OBS.: Para criar o exe eu uso " File.AppendAllText(sd.FileName, Codigo)". Talvez tenha como definir o ícone pelo "AppendAllText"?


    • Editado Eliseu5 quinta-feira, 11 de fevereiro de 2016 00:24
    • Tipo Alterado Marcos SJ quarta-feira, 17 de fevereiro de 2016 13:09 Solicitação de código/How to
    quinta-feira, 11 de fevereiro de 2016 00:14

Todas as Respostas

  • Olá

    Gente, alguém sabe como (através do vb.net), substituir ícones de arquivos executáveis? Encontrei uma classe na internet denominada "IconInjector", mas ela não funciona com todos os executáveis, como por exemplo em arquivos auto extraíveis (SFX) do Winrar.

    Sei que existem Editores de Recursos como ResHacker, mas eu preciso de algo automático e silencioso, como console.

    Desde já agradeço.

    • Tipo Alterado Marcos SJ segunda-feira, 4 de janeiro de 2016 16:28 Todas as threads de "How to" serão modificadas para discussão geral
    • Mesclado Marcos SJ quarta-feira, 17 de fevereiro de 2016 13:08 thread duplicada
    segunda-feira, 4 de janeiro de 2016 16:18
  • Olá, Eliseu!

    Você pode correr o ResHacker via CMD em modo silencioso:

    Veja como :

    http://www.angusj.com/resourcehacker/

    http://stackoverflow.com/questions/5165594/using-resource-hacker-for-changing-the-icon-after-the-build

    No VB.NET você pode correr usando o Shell:

        Private Sub Button_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim dirResHacker As String = "C:\ResHacker.exe"
            Dim dirIco As String = "C:\arquivoIcon.ico"
            Dim dirArquivo As String = "C:\Programa.exe"
            Dim dirNovoArquivo As String = "C:\ProgramaNovo.exe"
            Dim a As String = """" 'Aspa
    
            'ResHacker.exe -addoverwrite "Project.exe", "Project.exe", "ProgramIcon.ico", ICONGROUP, MAINICON, 0
            Shell(a & dirResHacker & a & " -addoverwrite " & a & dirArquivo & a & ", " _
                  & a & dirNovoArquivo & a & a & dirIco & a & ",bitmap,ENCLOSURE", AppWinStyle.Hide, True)
        End Sub

    Espero ter ajudado!


    C#.NET / VB.NET
    Aulas de VB.NET

    Não se esqueça! Se uma resposta/post te foi útil, é generoso reconhece-lo clicando em votar e se uma resposta foi fundamental para o desenrolar dum problema marque como resposta, você ajuda(visitantes) e motiva(quem te respondeu)!


    domingo, 10 de janeiro de 2016 00:02
  • Olá André

    Agradeço seu interesse em me ajudar.

    Mas desta forma se tornaria muito pesado, pois além de meu próprio app teria que anexar o ResHacker junto. Mas mesmo assim agradeço.

    terça-feira, 12 de janeiro de 2016 23:34
  • Bom dia Eliseu,

    Veja se o link abaixo te ajuda:

    http://stackoverflow.com/questions/32976691/change-exe-icon-based-on-define-c-sharp

    Abs.

    Bruno Destro


    Dicas de programação em .net, C# e SQL - http://smcode.com.br/

    quinta-feira, 11 de fevereiro de 2016 09:50
  • Olá Bruno

    Agradeço pelo seu interesse em me ajudar, no entanto o conteúdo do link que sugeriu não me ajuda. Ele demonstra como alterar o ícone do projeto, ou seja, do próprio .net ao compilar.

    Meu aplicativo compila/cria outro aplicativo em tempo de execução, então, não resolve.

    quinta-feira, 11 de fevereiro de 2016 10:19