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 (http://es.wikipedia.org/wiki/Portable_Executable) del exe, pero si hay algun otro método mejor ;D.
Saludos.
Si tienes el source del proyecto entonces puedes embedir directamente cualquier archivo a la compilación del exe desde la IDE:
(http://i.imgur.com/QRzXJRZ.png)
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
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.
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
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#:
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":
' ***********************************************************************
' 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!
Gracias por la info, voy a estudiarla, lo voy a hacer Vb.Net.
Luego te comento a donde llegue.
Saludos.
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.
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.
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
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.
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
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?
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.
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