Agregar Recurso a un archivo EXE [F1]

Iniciado por Maurice_Lupin, 14 Marzo 2015, 23:59 PM

0 Miembros y 1 Visitante están viendo este tema.

Maurice_Lupin

Estoy tratando de agregar un recurso a un ejecutable de vb.net, si alguien tiene info o sugerencia que compartir se lo agradeceria mucho.

No estoy intentando agregar el recurso en un proyecto, aclaro.
Según entiendo tendría que modificar el formato PE del exe, pero si hay algun otro método mejor  ;D.

Saludos.
Un error se comete al equivocarse.

Eleкtro

Si tienes el source del proyecto entonces puedes embedir directamente cualquier archivo a la compilación del exe desde la IDE:



Si no tienes el source, entonces puedes utilizar la herramienta command-line ILMerge de Microsoft, o la GUI ILMerge-GUI, o herramientas de pago cómo .Net Shrink.

Saludos








Maurice_Lupin

Gracias Eleкtro, por responder, pero el método que busco es sin el source del EXE.

Busco automatizar el proceso, es decir, crearme una aplicación que agregue recursos a un EXE .NET

Voy a averiguar sobre ILMerge, si tienes algun info?.
O sino voy a tener que meter mano al formato PE  >:(

Saludos.
Un error se comete al equivocarse.

Eleкtro

#3
Cita de: Maurice_Lupin en 15 Marzo 2015, 17:41 PMBusco automatizar el proceso, es decir, crearme una aplicación que agregue recursos a un EXE .NET

Voy a averiguar sobre ILMerge, si tienes algun info?.

Puedes recurrir a la ayuda integrada en la aplicación (por linea de comandos), o googlear la documentación de los parámetros de la aplicación en MSDN o Technet.
http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx
(fíjate en el hyperlink del .doc que contiene la documentación)

Pero hay un detalle importante, se me olvidó que solo podrás "unir" ensamblados .Net, esa es su limitación, es decir, no podrás interactuar con otro tipo de archivos como un binario de C/C++ que tnega código nativo, o un archivo de texto plano, etc, o al menos eso tengo entendido por lo que especifica Microsoft, pero lo cierto es que nunca lo intenté.

Saludos








Eleкtro

#4
Imagino que cuando dices que quieres automatizar la tarea pretendes hacerlo desde .Net,
No se si esto te servirá por que no estoy muy seguro de lo si esto es lo que realmente buscas, pero ayer me puse a desarrollar un laaaargo Snippet que quizás te sería de utilidad,
la finalidad del siguiente código es crear y gestionar una tabla de recursos .Net, es decir, un archivo .ResX, que no sería más que un archivo XML donde sus nodos contendrían los datos de los recursos.
El único inconveniente es que al ser un archivo de texto plano, los datos serializados de un recurso binario ocuparían más de lo que ocuparía realmente ese archivo binario (al reconstruirlo), espero que se me entienda, jeje.

Una vez hayas creado el archivo .resx y le hayas añadido los recursos que quieras, solo tendrías que embedir este archivo ResX, al ensamblado.

Te muestro un multi-ejemplo de uso con varios tipos de recursos, aunque está escrito en VB.Net y sino recuerdo mal tú experiencia está basada en C#, pero el uso de este código es sencillo, genérico e intuitivo (o eso pretendí conseguir), no te costaría traducirlo a C#:

Código (vbnet) [Seleccionar]
Imports System.IO
Imports System.Text

Public Class Form1

   Private Sub Test() Handles MyBase.Shown

       Dim resX As New ResXManager(Path.Combine(Application.StartupPath, "MyResources.resx"))
       With resX

           ' Create or replace the ResX file.
           .Create(replace:=True)

           ' Add a string resource.
           .AddResource(Of String)("String Resource", "Hello World!", "String Comment")
           ' Add a bitmap resource.
           .AddResource(Of Bitmap)("Bitmap Resource", SystemIcons.Information.ToBitmap, "Bitmap Comment")
           ' Add a binary resource.
           .AddResource(Of Byte())("Binary Resource", File.ReadAllBytes("C:\file.mp3"), "Binary Comment")

       End With

       ' *******************************************************************************************************

       ' Get the string resource.
       Dim stringResource As ResXManager.Resource(Of String) =
           resX.FindResource(Of String)("String Resource", StringComparison.OrdinalIgnoreCase)

       ' Get the bitmap resource.
       Dim bitmapResource As ResXManager.Resource(Of Bitmap) =
           resX.FindResource(Of Bitmap)("Bitmap Resource", StringComparison.OrdinalIgnoreCase)

       ' Get the binary resource.
       Dim binaryResource As ResXManager.Resource(Of Byte()) =
           resX.FindResource(Of Byte())("Binary Resource", StringComparison.OrdinalIgnoreCase)

       ' *******************************************************************************************************

       ' Get the string data.
       Dim stringData As String = stringResource.Data

       ' Get the bitmap data.
       Dim bitmapData As Bitmap = bitmapResource.Data

       ' Get the binary data.
       Dim binaryData As Byte() = binaryResource.Data

       ' *******************************************************************************************************

       ' Get all the resources at once.
       Dim resources As IEnumerable(Of ResXManager.Resource) = resX.Resources

       ' Get all the resources of specific Type at once.
       Dim stringResources As IEnumerable(Of ResXManager.Resource(Of String)) = resX.FindResources(Of String)()

       ' *******************************************************************************************************

       ' Get all the resource datas at once from Resource collection.
       Dim resourceDatas As IEnumerable(Of Object) =
           From res As ResXManager.Resource In resX.Resources
           Select res.Data

       ' Get all the resource datas of specific Type at once from Resource collection.
       Dim stringResourceDatas As IEnumerable(Of String) =
           From res As ResXManager.Resource In resX.Resources
           Where res.Type Is GetType(String)
           Select DirectCast(res.Data, String)

       ' *******************************************************************************************************

       ' Treat the string resource as you like.
       MessageBox.Show(stringData, String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Information)

       ' Treat the bitmap resource as you like.
       Me.Icon = Icon.FromHandle(bitmapData.GetHicon)

       ' Treat the binary resource as you like.
       File.WriteAllBytes("C:\new file.mp3", binaryData)

       ' *******************************************************************************************************

       ' Iterate all the resources.
       For Each res As ResXManager.Resource In resX.Resources

           Dim sb As New StringBuilder

           sb.AppendLine(String.Format("Name...: {0}", res.Name))
           sb.AppendLine(String.Format("Comment: {0}", res.Comment))
           sb.AppendLine(String.Format("Type...: {0}", res.Type.ToString))
           sb.AppendLine(String.Format("Data...: {0}", res.Data.ToString))

           MsgBox(sb.ToString)
       Next

       ' Iterate all the resources of specific Type.
       For Each res As ResXManager.Resource(Of String) In resX.FindResources(Of String)()

           Dim sb As New StringBuilder

           sb.AppendLine(String.Format("Name...: {0}", res.Name))
           sb.AppendLine(String.Format("Comment: {0}", res.Comment))
           sb.AppendLine(String.Format("Type...: {0}", res.Type.ToString))
           sb.AppendLine(String.Format("Data...: {0}", res.Data.ToString))

           MsgBox(sb.ToString)
       Next

       ' *******************************************************************************************************

       ' Remove a resource.
       resX.RemoveResource("Binary Resource")

       '  GC.Collect()

   End Sub

End Class


Este es el código fuente, que obviamente no sería necesario traducirlo a C#, ya que puedes compilarlo a una librería.dll externa o "interna":

Código (vbnet) [Seleccionar]
' ***********************************************************************
' Author   : Elektro
' Modified : 16-March-2015
' ***********************************************************************
' <copyright file="ResXManager.vb" company="Elektro Studios">
'     Copyright (c) Elektro Studios. All rights reserved.
' </copyright>
' ***********************************************************************

#Region " Option Statements "

Option Strict On
Option Explicit On
Option Infer Off

#End Region

#Region " Usage Examples "

#End Region

#Region " Imports "

Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.IO
Imports System.Resources

#End Region

''' <summary>
''' Manages a .Net managed resource file.
''' </summary>
Public NotInheritable Class ResXManager

#Region " Properties "

   ''' <summary>
   ''' Gets the .Net managed resource file path.
   ''' </summary>
   ''' <value>The .Net managed resource filepath.</value>
   Public ReadOnly Property FilePath As String
       Get
           Return Me.filePath1
       End Get
   End Property
   ''' <summary>
   ''' The .Net managed resource file path.
   ''' </summary>
   Private ReadOnly filePath1 As String

   ''' <summary>
   ''' Gets the resources contained in the .Net managed resource file.
   ''' </summary>
   ''' <value>The resources.</value>
   Public ReadOnly Property Resources As IEnumerable(Of Resource)
       Get
           Return GetResources()
       End Get
   End Property

#End Region

#Region " Types "

#Region " Resource "

   ''' <summary>
   ''' Defines a resource of a .Net managed resource file.
   ''' </summary>
   <Serializable>
   Public NotInheritable Class Resource

#Region " Properties "

       ''' <summary>
       ''' Gets the resource name.
       ''' </summary>
       ''' <value>The resource name.</value>
       Public ReadOnly Property Name As String
           Get
               Return Me.name1
           End Get
       End Property
       Private ReadOnly name1 As String

       ''' <summary>
       ''' Gets the resource data.
       ''' </summary>
       ''' <value>The resource data.</value>
       Public ReadOnly Property Data As Object
           Get
               Return Me.data1
           End Get
       End Property
       Private ReadOnly data1 As Object

       ''' <summary>
       ''' Gets the resource type.
       ''' </summary>
       ''' <value>The resource type.</value>
       Public ReadOnly Property Type As Type
           Get
               Return Data.GetType
           End Get
       End Property

       ''' <summary>
       ''' Gets the resource comment.
       ''' </summary>
       ''' <value>The resource comment.</value>
       Public ReadOnly Property Comment As String
           Get
               Return comment1
           End Get
       End Property
       Private ReadOnly comment1 As String

       ''' <summary>
       ''' Represents a <see cref="Resource"/> instance that is <c>Nothing</c>.
       ''' </summary>
       ''' <value><c>Nothing</c></value>
       <EditorBrowsable(EditorBrowsableState.Advanced)>
       Public Shared ReadOnly Property Empty As Resource
           Get
               Return Nothing
           End Get
       End Property

#End Region

#Region " Constructors "

       ''' <summary>
       ''' Initializes a new instance of the <see cref="Resource"/> class.
       ''' </summary>
       ''' <param name="name">The resource name.</param>
       ''' <param name="data">The resource data.</param>
       ''' <param name="comment">The resource comment.</param>
       Public Sub New(ByVal name As String,
                      ByVal data As Object,
                      ByVal comment As String)

           Me.name1 = name
           Me.data1 = data
           Me.comment1 = comment

       End Sub

       ''' <summary>
       ''' Prevents a default instance of the <see cref="Resource"/> class from being created.
       ''' </summary>
       Private Sub New()
       End Sub

#End Region

#Region " Hidden Methods "

       ''' <summary>
       ''' Determines whether the specified System.Object instances are considered equal.
       ''' </summary>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function Equals(ByVal obj As Object) As Boolean
           Return MyBase.Equals(obj)
       End Function

       ''' <summary>
       ''' Serves as a hash function for a particular type.
       ''' </summary>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function GetHashCode() As Integer
           Return MyBase.GetHashCode
       End Function

       ''' <summary>
       ''' Gets the System.Type of the current instance.
       ''' </summary>
       ''' <returns>The exact runtime type of the current instance.</returns>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function [GetType]() As Type
           Return MyBase.GetType
       End Function

       ''' <summary>
       ''' Returns a String that represents the current object.
       ''' </summary>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function ToString() As String
           Return MyBase.ToString
       End Function

#End Region

   End Class

#End Region

#Region " Resource(Of T) "

   ''' <summary>
   ''' Defines a resource of a .Net managed resource file.
   ''' </summary>
   <Serializable>
   Public NotInheritable Class Resource(Of T)

#Region " Properties "

       ''' <summary>
       ''' Gets the resource name.
       ''' </summary>
       ''' <value>The resource name.</value>
       Public ReadOnly Property Name As String
           Get
               Return Me.name1
           End Get
       End Property
       Private ReadOnly name1 As String

       ''' <summary>
       ''' Gets the resource data.
       ''' </summary>
       ''' <value>The resource data.</value>
       Public ReadOnly Property Data As T
           Get
               Return Me.data1
           End Get
       End Property
       Private ReadOnly data1 As T

       ''' <summary>
       ''' Gets the resource type.
       ''' </summary>
       ''' <value>The resource type.</value>
       Public ReadOnly Property Type As Type
           Get
               Return GetType(T)
           End Get
       End Property

       ''' <summary>
       ''' Gets the resource comment.
       ''' </summary>
       ''' <value>The resource comment.</value>
       Public ReadOnly Property Comment As String
           Get
               Return comment1
           End Get
       End Property
       Private ReadOnly comment1 As String

#End Region

#Region " Constructors "

       ''' <summary>
       ''' Initializes a new instance of the <see cref="Resource(Of T)"/> class.
       ''' </summary>
       ''' <param name="name">The resource name.</param>
       ''' <param name="data">The resource data.</param>
       ''' <param name="comment">The resource comment.</param>
       Public Sub New(ByVal name As String,
                      ByVal data As T,
                      ByVal comment As String)

           Me.name1 = name
           Me.data1 = data
           Me.comment1 = comment

       End Sub

       ''' <summary>
       ''' Prevents a default instance of the <see cref="Resource(Of T)"/> class from being created.
       ''' </summary>
       Private Sub New()
       End Sub

#End Region

#Region " Hidden Methods "

       ''' <summary>
       ''' Determines whether the specified System.Object instances are considered equal.
       ''' </summary>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function Equals(ByVal obj As Object) As Boolean
           Return MyBase.Equals(obj)
       End Function

       ''' <summary>
       ''' Serves as a hash function for a particular type.
       ''' </summary>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function GetHashCode() As Integer
           Return MyBase.GetHashCode
       End Function

       ''' <summary>
       ''' Gets the System.Type of the current instance.
       ''' </summary>
       ''' <returns>The exact runtime type of the current instance.</returns>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function [GetType]() As Type
           Return MyBase.GetType
       End Function

       ''' <summary>
       ''' Returns a String that represents the current object.
       ''' </summary>
       <EditorBrowsable(EditorBrowsableState.Never)>
       Public Shadows Function ToString() As String
           Return MyBase.ToString
       End Function

#End Region

   End Class

#End Region

#End Region

#Region " Constructors "

   ''' <summary>
   ''' Initializes a new instance of the <see cref="ResXManager"/> class.
   ''' </summary>
   ''' <param name="resxFilePath">The .Net managed resource filepath.</param>
   Public Sub New(ByVal resxFilePath As String)
       Me.filePath1 = resxFilePath
   End Sub

   ''' <summary>
   ''' Prevents a default instance of the <see cref="ResXManager"/> class from being created.
   ''' </summary>
   Private Sub New()
   End Sub

#End Region

#Region " Public Methods "

   ''' <summary>
   ''' Creates the .Net managed resource file.
   ''' </summary>
   ''' <param name="replace">if set to <c>true</c>, replaces any existent file.</param>
   ''' <exception cref="System.Exception"></exception>
   Public Sub Create(Optional ByVal replace As Boolean = False)

       If Not replace AndAlso File.Exists(Me.filePath1) Then
           Throw New Exception(String.Format("Resource file already exists: {0}", Me.filePath1))
           Exit Sub
       End If

       Dim resXWritter As ResXResourceWriter = Nothing
       Try
           resXWritter = New ResXResourceWriter(Me.filePath1)
           Using resXWritter
               resXWritter.Generate()
           End Using

       Catch ex As Exception
           Throw

       Finally
           If resXWritter IsNot Nothing Then
               resXWritter.Close()
           End If

       End Try

   End Sub

   ''' <summary>
   ''' Adds a resource into the .Net managed resource file.
   ''' </summary>
   ''' <param name="name">The resource name.</param>
   ''' <param name="data">The resource data.</param>
   ''' <param name="comment">The resource comment.</param>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">A resource with the same name already exists in the table.;name</exception>
   Public Sub AddResource(ByVal name As String,
                          ByVal data As Object,
                          Optional ByVal comment As String = Nothing)

       Me.AddResource(replace:=False, name:=name, data:=data, comment:=comment)

   End Sub

   ''' <summary>
   ''' Adds a specified resource of the specified type into the .Net managed resource file.
   ''' </summary>
   ''' <typeparam name="T"></typeparam>
   ''' <param name="name">The resource name.</param>
   ''' <param name="data">The resource data.</param>
   ''' <param name="comment">The resource comment.</param>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">A resource with the same name already exists in the table.;name</exception>
   Public Sub AddResource(Of T)(ByVal name As String,
                                ByVal data As T,
                                Optional ByVal comment As String = Nothing)

       Me.AddResource(replace:=False, name:=name, data:=data, comment:=comment)

   End Sub

   ''' <summary>
   ''' Replaces a resource by the specified name inside the .Net managed resource file.
   ''' </summary>
   ''' <param name="name">The resource name.</param>
   ''' <param name="data">The resource data.</param>
   ''' <param name="comment">The resource comment.</param>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">A resource with the same name already exists in the table.;name</exception>
   Public Sub ReplaceResource(ByVal name As String,
                              ByVal data As Object,
                              Optional ByVal comment As String = Nothing)

       Me.AddResource(replace:=True, name:=name, data:=data, comment:=comment)

   End Sub

   ''' <summary>
   ''' Replaces a resource by the specified name of the specified type inside the .Net managed resource file.
   ''' </summary>
   ''' <typeparam name="T"></typeparam>
   ''' <param name="name">The resource name.</param>
   ''' <param name="data">The resource data.</param>
   ''' <param name="comment">The resource comment.</param>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">A resource with the same name already exists in the table.;name</exception>
   Public Sub ReplaceResource(Of T)(ByVal name As String,
                                    ByVal data As T,
                                    Optional ByVal comment As String = Nothing)

       Me.AddResource(replace:=True, name:=name, data:=data, comment:=comment)

   End Sub

   ''' <summary>
   ''' Finds a resource by the specified name of specified type inside the .Net managed resource file.
   ''' </summary>
   ''' <typeparam name="T"></typeparam>
   ''' <param name="name">The resource name.</param>
   ''' <param name="stringComparison">The <see cref="StringComparison"/> to compare the resource name.</param>
   ''' <returns>The resource.</returns>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">Resource with the specified name is not found.;name</exception>
   ''' <exception cref="System.ArgumentException">The specified Type differs from the resource Type.;T</exception>
   Public Function FindResource(Of T)(ByVal name As String,
                                      Optional ByVal stringComparison As StringComparison =
                                                     StringComparison.OrdinalIgnoreCase) As Resource(Of T)

       If Not File.Exists(Me.filePath1) Then
           Throw New FileNotFoundException("Resource file not found.", Me.filePath1)
           Exit Function
       End If

       ' Read the ResX file.
       Dim resX As ResXResourceReader = Nothing
       Dim res As Resource(Of T) = Nothing
       Try
           resX = New ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}
           Using resX

               For Each entry As DictionaryEntry In resX

                   If entry.Key.ToString.Equals(name, stringComparison) Then

                       Dim node As ResXDataNode = CType(entry.Value, ResXDataNode)

                       res = New Resource(Of T)(name:=node.Name,
                                                data:=DirectCast(node.GetValue(DirectCast(Nothing, ITypeResolutionService)), T),
                                                comment:=node.Comment)
                       Exit For

                   End If

               Next entry

           End Using ' resX

           Return res

       Catch ex As Exception
           Throw

       Finally
           If resX IsNot Nothing Then
               resX.Close()
           End If

       End Try

   End Function

   ''' <summary>
   ''' Finds a resource by the specified name inside the .Net managed resource file.
   ''' </summary>
   ''' <param name="name">The resource name.</param>
   ''' <param name="stringComparison">The <see cref="StringComparison"/> to compare the resource name.</param>
   ''' <returns>The resource.</returns>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">Resource with the specified name is not found.;name</exception>
   ''' <exception cref="System.ArgumentException">The specified Type differs from the resource Type.;T</exception>
   Public Function FindResource(ByVal name As String,
                                Optional ByVal stringComparison As StringComparison =
                                               StringComparison.OrdinalIgnoreCase) As Resource

       If Not File.Exists(Me.filePath1) Then
           Throw New FileNotFoundException("Resource file not found.", Me.filePath1)
           Exit Function
       End If

       ' Read the ResX file.
       Dim resX As ResXResourceReader = Nothing
       Dim res As Resource = Nothing
       Try
           resX = New ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}
           Using resX

               For Each entry As DictionaryEntry In resX

                   If entry.Key.ToString.Equals(name, stringComparison) Then

                       Dim node As ResXDataNode = CType(entry.Value, ResXDataNode)

                       res = New Resource(name:=node.Name,
                                          data:=node.GetValue(DirectCast(Nothing, ITypeResolutionService)),
                                          comment:=node.Comment)
                       Exit For

                   End If

               Next entry

           End Using ' resX

           Return res

       Catch ex As Exception
           Throw

       Finally
           If resX IsNot Nothing Then
               resX.Close()
           End If

       End Try

   End Function

   ''' <summary>
   ''' Finds the resources of the specified type inside the .Net managed resource file.
   ''' </summary>
   ''' <typeparam name="T"></typeparam>
   ''' <returns>The resource.</returns>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">Resource with the specified name is not found.;name</exception>
   ''' <exception cref="System.ArgumentException">The specified Type differs from the resource Type.;T</exception>
   Public Iterator Function FindResources(Of T)() As IEnumerable(Of Resource(Of T))

       If Not File.Exists(Me.filePath1) Then
           Throw New FileNotFoundException("Resource file not found.", Me.filePath1)
           Exit Function
       End If

       ' Read the ResX file.
       Dim resX As ResXResourceReader = Nothing
       Try
           resX = New ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}
           Using resX

               For Each entry As DictionaryEntry In resX

                   Dim node As ResXDataNode = CType(entry.Value, ResXDataNode)

                   If node.GetValue(DirectCast(Nothing, ITypeResolutionService)).GetType Is GetType(T) Then

                       Yield New Resource(Of T)(name:=node.Name,
                                          data:=DirectCast(node.GetValue(DirectCast(Nothing, ITypeResolutionService)), T),
                                          comment:=node.Comment)

                   End If

               Next entry

           End Using ' resX

       Catch ex As Exception
           Throw

       Finally
           If resX IsNot Nothing Then
               resX.Close()
           End If

       End Try

   End Function

   ''' <summary>
   ''' Removes a resource by the specified name from the .Net managed resource file.
   ''' </summary>
   ''' <param name="name">The resource name.</param>
   ''' <param name="stringComparison">The <see cref="StringComparison"/> to compare the resource name.</param>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">Any resource found matching the specified name.;name</exception>
   Public Sub RemoveResource(ByVal name As String,
                             Optional ByVal stringComparison As StringComparison =
                                            StringComparison.OrdinalIgnoreCase)

       If Not File.Exists(Me.filePath1) Then
           Throw New FileNotFoundException("Resource file not found.", Me.filePath1)
           Exit Sub
       End If

       If Me.FindResource(name, stringComparison) Is Nothing Then
           Throw New ArgumentException("Any resource found matching the specified name.", "name")
           Exit Sub
       End If

       Dim resources As New List(Of ResXDataNode)
       Dim resX As ResXResourceReader = Nothing
       Dim resXWritter As ResXResourceWriter = Nothing

       Try
           resX = New ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}
           Using resX

               For Each entry As DictionaryEntry In resX

                   If Not entry.Key.ToString.Equals(name, stringComparison) Then

                       Dim node As ResXDataNode = CType(entry.Value, ResXDataNode)
                       resources.Add(New ResXDataNode(name:=node.Name, value:=node.GetValue(DirectCast(Nothing, ITypeResolutionService))) With {.Comment = node.Comment})

                   End If

               Next entry

           End Using

           ' Add the resource in the ResX file.
           ' Note: This will replace the current ResX file.
           resXWritter = New ResXResourceWriter(Me.filePath1)
           Using resXWritter

               ' Add the retrieved resources into the ResX file.
               If resources IsNot Nothing Then
                   For Each resourceItem As ResXDataNode In resources
                       resXWritter.AddResource(resourceItem)
                   Next resourceItem
               End If

               resXWritter.Generate()

           End Using ' resXWritter

       Catch ex As Exception
           Throw

       Finally
           If resX IsNot Nothing Then
               resX.Close()
           End If

           If resXWritter IsNot Nothing Then
               resXWritter.Close()
           End If

           resources.Clear()

       End Try

   End Sub

#End Region

#Region " Private Methods "

   ''' <summary>
   ''' Adds or replaces a resource into the .Net managed resource file.
   ''' </summary>
   ''' <param name="replace">if set to <c>true</c>, the resource will be replaced.</param>
   ''' <param name="name">The resource name.</param>
   ''' <param name="data">The resource data.</param>
   ''' <param name="comment">The resource comment.</param>
   ''' <exception cref="System.IO.FileNotFoundException">Resource file not found.</exception>
   ''' <exception cref="System.ArgumentException">A resource with the same name already exists in the table.;name</exception>
   Private Sub AddResource(ByVal replace As Boolean,
                           ByVal name As String,
                           ByVal data As Object,
                           ByVal comment As String)

       If Not File.Exists(Me.filePath1) Then
           Throw New FileNotFoundException("Resource file not found.", Me.filePath1)
           Exit Sub
       End If

       Dim resources As New List(Of ResXDataNode)
       Dim resX As ResXResourceReader = Nothing
       Dim resXWritter As ResXResourceWriter = Nothing

       Try
           resX = New ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}
           Using resX

               For Each entry As DictionaryEntry In resX

                   If Not replace AndAlso entry.Key.ToString.Equals(name, StringComparison.OrdinalIgnoreCase) Then
                       Throw New ArgumentException("A resource with the same name already exists in the table.", "name")

                   Else
                       Dim node As ResXDataNode = CType(entry.Value, ResXDataNode)
                       resources.Add(New ResXDataNode(name:=node.Name, value:=node.GetValue(DirectCast(Nothing, ITypeResolutionService))) With {.Comment = node.Comment})

                   End If

               Next entry

           End Using

           ' Add the resource in the ResX file.
           ' Note: This will replace the current ResX file.
           resXWritter = New ResXResourceWriter(Me.filePath1)
           Using resXWritter

               ' Add the retrieved resources into the ResX file.
               If resources IsNot Nothing Then
                   For Each resourceItem As ResXDataNode In resources
                       resXWritter.AddResource(resourceItem)
                   Next resourceItem
               End If

               ' Add the specified resource into the ResX file.
               resXWritter.AddResource(New ResXDataNode(name, data) With {.Name = name, .Comment = comment})
               resXWritter.Generate()

           End Using ' resXWritter

       Catch ex As Exception
           Throw

       Finally
           If resX IsNot Nothing Then
               resX.Close()
           End If

           If resXWritter IsNot Nothing Then
               resXWritter.Close()
           End If

           resources.Clear()

       End Try

   End Sub

   ''' <summary>
   ''' Gets all the resources contained in the .Net managed resource file.
   ''' </summary>
   ''' <returns>IEnumerable(Of Resource).</returns>
   Private Iterator Function GetResources() As IEnumerable(Of Resource)

       ' Read the ResX file.
       Using resX As New Resources.ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}

           For Each entry As DictionaryEntry In resX

               Dim node As ResXDataNode = CType(entry.Value, ResXDataNode)

               Yield New Resource(name:=node.Name,
                                  data:=node.GetValue(DirectCast(Nothing, ITypeResolutionService)),
                                  comment:=node.Comment)

           Next entry

       End Using ' resX

   End Function

#End Region

#Region " Hidden Methods "

   ''' <summary>
   ''' Determines whether the specified System.Object instances are considered equal.
   ''' </summary>
   <EditorBrowsable(EditorBrowsableState.Never)>
   Public Shadows Function Equals(ByVal obj As Object) As Boolean
       Return MyBase.Equals(obj)
   End Function

   ''' <summary>
   ''' Serves as a hash function for a particular type.
   ''' </summary>
   <EditorBrowsable(EditorBrowsableState.Never)>
   Public Shadows Function GetHashCode() As Integer
       Return MyBase.GetHashCode
   End Function

   ''' <summary>
   ''' Gets the System.Type of the current instance.
   ''' </summary>
   ''' <returns>The exact runtime type of the current instance.</returns>
   <EditorBrowsable(EditorBrowsableState.Never)>
   Public Shadows Function [GetType]() As Type
       Return MyBase.GetType
   End Function

   ''' <summary>
   ''' Returns a String that represents the current object.
   ''' </summary>
   <EditorBrowsable(EditorBrowsableState.Never)>
   Public Shadows Function ToString() As String
       Return MyBase.ToString
   End Function

#End Region

End Class


Saludos!








Maurice_Lupin

Gracias por la info, voy a estudiarla, lo voy a hacer Vb.Net.
Luego te comento a donde llegue.

Saludos.
Un error se comete al equivocarse.

Eleкtro

Cita de: Maurice_Lupin en 16 Marzo 2015, 21:40 PMLuego te comento a donde llegue.

¿te rendiste, o buscaste otra alternativa?, jeje.

Te muestro un ejemplo, ya que el hecho de unir requiere dos elementos compilados, lo que hago en este ejemplo es, primero crear la tabla de recursos ResX, luego compilar una dll "vacía" de .Net añadiendo el archivo ResX cómo recurso embedido, y luego ya con esa dll puedes hacer lo que quieras, unirla a un exe, extraer/leer el archivo ResX de la dll, etc.

Código (vbnet) [Seleccionar]
Imports System.CodeDom.Compiler
Imports System.IO
Imports System.Reflection

Public Class Form1

Private Sub Test() Handles MyBase.Shown

    ' Create the ResX file.
    Dim resX As New ResXManager(Path.Combine(Application.StartupPath, "C:\MyResources.resx"))
    With resX
        .Create(replace:=True)
        .AddResource(Of String)("String Resource", "Hello World!", "String Comment")
    End With

    ' Compile an assembly.dll that contains the ResX file as an embedded resource.
    Dim codeProvider As CodeDomProvider = CodeDomProvider.CreateProvider("VB") ' or New VBCodeProvider()
    Dim parameters As CompilerParameters = New CompilerParameters()
    With parameters
        .GenerateExecutable = False
        .OutputAssembly = "C:\Assembly.dll"
        .EmbeddedResources.Add("C:\MyResources.resx")
    End With
    Dim results As CompilerResults = codeProvider.CompileAssemblyFromSource(parameters, "Public class ResourceClass : End Class")

    ' Read the assembly.
    Dim assembly As Assembly = assembly.LoadFile("c:\Assembly.dll")

    ' Extract/read the ResX file from assembly.
    Dim embeddedFileName As String = "MyResources.resx"
    Dim targetFilePath As String = "C:\NewMyResources.resx"
    Using s As Stream = assembly.GetManifestResourceStream(embeddedFileName)
        Dim buffer As Byte() = New Byte(CInt(s.Length - 1)) {}
        Dim read As Integer = s.Read(buffer, 0, CInt(s.Length))
        Using fs As New FileStream(targetFilePath, FileMode.Create)
            fs.Write(buffer, 0, buffer.Length)
        End Using
    End Using

End Sub

End Class


Saludos.








Maurice_Lupin

Hola, Eleкtro

Muchas gracias por compartir. Tu codigo anterior esta bueno pero no era lo que buscaba.
Lo último voy a probarlo si se acomoda a lo que busco.

Toda la semana he estado averiguando sobre el formato PE de .NET, escasa información, pero ya logro leer la estructura PE desde VB.Net, lo malo es que no hay punteros o por lo menos no funcionan como en C++.

Aqui un ejemplo para ilustrar mi problema, no puedo modificar los valores en memoria de "p" (Point) mediante punteros
Código (vbnet) [Seleccionar]

   Public Sub example
    Dim p As Point
        p.x = 1   ' esto no puedo modificarlo mediante un puntero
        p.y = 1
        ' Initialize unmanged memory to hold the struct.
        Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(p))
        Try
            Dim msg As String = ""
            ' Copy the struct to unmanaged memory.
            Marshal.StructureToPtr(p, pnt, false)
           
            msg += ( "first point is " + p.x.ToString + " and " + p.y.ToString + "." & chr(10) )
           
            Dim anotherP As Point  ' Create another point

            ' Set this Point to the value of the
            ' Point in unmanaged memory.
            anotherP = Marshal.PtrToStructure(pnt,p.GetType)
            anotherP.X +=  2  'modifico los valores pero en "p" no se alteran
            anotherP.Y +=  2
           
            msg += ( "New point is " + anotherP.x.ToString + " and " + anotherP.y.ToString + "." & chr(10) )
            msg += ( "first point is " + p.x.ToString + " and " + p.y.ToString + "." )
            msgbox(msg)
        Finally
            ' Free the unmanaged memory.
            Marshal.FreeHGlobal(pnt)
        End Try
    End Sub


Saludos y muchas gracias.
Un error se comete al equivocarse.

Maurice_Lupin

Gracias Elektro.
Ya probe tu ultimo codigo y funciona! asi me libro de liarme más con el formato PE

hice un pequeño cambio para el .net framework 2.0, ahora me agrega un recurso .resources, me toca leerlo desde el asembly  ;D gracias nuevamente

Código (vbnet) [Seleccionar]

Public Sub addResources(ByVal pathRecurso As String, ByVal pathDll As String)
Try
    Dim resX As ResourceWriter
    resX = new ResourceWriter(pathRecurso)
    With resX
        .AddResource("String Resource", "Hello World!" )
    End With    
    resX.Close()
    ' Compile an assembly.dll that contains the ResX file as an embedded resource.
    Dim codeProvider As CodeDomProvider = CodeDomProvider.CreateProvider("VB") ' or New VBCodeProvider()
    Dim parameters As CompilerParameters = New CompilerParameters()
    With parameters
       .GenerateExecutable = False
       .OutputAssembly = pathDll
       .EmbeddedResources.Add(pathRecurso)
    End With
   
    Dim results As CompilerResults = codeProvider.CompileAssemblyFromSource(parameters, "Public class ResourceClass : End Class")    
msgbox("OK!")
Catch ex As Exception
msgbox(ex.Message)
            End Try
End Sub


Una consulta sobre esta parte, entiendo que pasas los parametros de compilación, para que sirve "Public class..." o es que en este caso no es necesario?

Código (vbnet) [Seleccionar]

Dim results As CompilerResults = codeProvider.CompileAssemblyFromSource(parameters, "Public class ResourceClass : End Class")


Public Overridable Function CompileAssemblyFromSource ( _
options As CompilerParameters, _
ParamArray sources As String() _
) As CompilerResults

Parámetros

options
    Tipo: System.CodeDom.Compiler.CompilerParameters
    Objeto CompilerParameters que indica la configuración de compilador para esta compilación.

sources
    Tipo: System.String()
    Matriz de cadenas de código fuente que se van a compilar.




Saludos.
Un error se comete al equivocarse.

Eleкtro

#9
Cita de: Maurice_Lupin en 23 Marzo 2015, 17:42 PMpara que sirve "Public class..." o es que en este caso no es necesario?

Es el código fuente que se va a compilar, es decir, el código que contendrá el ensamblado generado :-/,
"Public class ResourceClass : End Class" solo es una Class pública y vacía con la sintaxis de VB.Net (puesto que uso el proveedor de código de VB para compilar),
lo que escribí solo era para mostrar un ejemplo del valor que debe tomar ese parámetro, pero en realidad no sirve para nada esa Class ya que solo pretendes acceder a los recursos del ensamblado compilado,
puedes dejar el parámetro vacío si lo prefieres, compilará bien igualmente.

EDITO:
Por cierto, sobre la manipulación del PE no se practicamente nada, pero en el pasado me ayudó mucho esta librería para tareas relacionadas, es la librería que utiliza el deofuscador de4dot:
https://github.com/0xd4d/dnlib/
(mírate la class PEImage.cs en el source, aunque no he mirado su contenido, quizás te sirva para algo)

Saludos