see - summary example c#
Use C#exe para modificar recursos de un C#exe diferente (1)
En función de sus suposiciones, puede actualizar / agregar recursos de su ejecutable utilizando la biblioteca Mono.Cecil
Aquí hay tres métodos esenciales para la manipulación de recursos usando Mono.Cecil:
public static void ReplaceResource(string path, string resourceName, byte[] resource)
{
var definition =
AssemblyDefinition.ReadAssembly(path);
for (var i = 0; i < definition.MainModule.Resources.Count; i++)
if (definition.MainModule.Resources[i].Name == resourceName)
{
definition.MainModule.Resources.RemoveAt(i);
break;
}
var er = new EmbeddedResource(resourceName, ManifestResourceAttributes.Public, resource);
definition.MainModule.Resources.Add(er);
definition.Write(path);
}
public static void AddResource(string path, string resourceName, byte[] resource)
{
var definition =
AssemblyDefinition.ReadAssembly(path);
var er = new EmbeddedResource(resourceName, ManifestResourceAttributes.Public, resource);
definition.MainModule.Resources.Add(er);
definition.Write(path);
}
public static MemoryStream GetResource(string path, string resourceName)
{
var definition =
AssemblyDefinition.ReadAssembly(path);
foreach (var resource in definition.MainModule.Resources)
if (resource.Name == resourceName)
{
var embeddedResource =(EmbeddedResource) resource;
var stream = embeddedResource.GetResourceStream();
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
var memStream = new MemoryStream();
memStream.Write(bytes,0,bytes.Length);
memStream.Position = 0;
return memStream;
}
return null;
}
Puede usar el método GetResource
para recuperar el flujo de recursos actual (Writable),
utilizando las clases ResourceWriter
, ResourceReader
o ResourceEditor
puede leer / escribir o modificar el recurso actual o crear un nuevo recurso, y luego simplemente ponerlo de nuevo en el ejecutable llamando a ReplaceResource
o agregarlo como uno nuevo llamando a AddResource
Aquí hay un ejemplo de cómo reemplazar una imagen en un recurso (creando un nuevo recurso desde cero):
var ms = new MemoryStream();
var writer = new ResourceWriter(ms);
writer.AddResource("good_luck",new Bitmap("good_luck.png"));
writer.Generate();
ReplaceResource(@"my executale.exe", "ResourceTest.Properties.Resources.resources",ms.ToArray());
puede obtener Cecil a través de PM> Install-Package Mono.Cecil
nuget.
Resuelto Vea abajo.
Tengo 2 aplicaciones de C #. La aplicación a se supone que modifica los recursos internos de la aplicación b. Se supone que la aplicación b hace algo con sus recursos (modificados) cuando se ejecuta.
¿Cómo puedo lograr eso?
Esto es lo que intenté:
public static void addFileToResources(string dest, string src)
{
Assembly a_dest = Assembly.LoadFile(dest);
using (Stream s_dest = a_dest.GetManifestResourceStream("Elevator.Properties.Resources.resources"))
{
using (ResourceWriter rw = new ResourceWriter(s_dest))
{
byte[] b_src = File.ReadAllBytes(src);
rw.AddResource("target", b_src);
}
}
}
Obtengo una System.ArgumentException
con The stream is readonly.
en System.Resources.ResourceWriter..ctor(Stream stream)
EDITAR
Dado que eso no parece ser posible con los recursos de .net: ¿Hay alguna otra manera?
Quiero producir un solo archivo (es decir, el exe de la aplicación b
) que sea ejecutable y pueda trabajar con los datos (almacenados en el exe) que se proporcionan antes de la ejecución desde la aplicación a
. Preferiblemente sin tener que compilar realmente b
para darle los datos.
Supuestos para que sea un poco más fácil:
-
a
siempre se ejecuta antes deb
-
a
solo se ejecuta una vez - ambas aplicaciones están escritas por mí
Editar - Sollución
Como no es posible lograr eso a través de los recursos, utilicé la siguiente solución alternativa:
Aparentemente puedes agregar CUALQUIER COSA a un archivo exe y aún será ejecutable, así que esto es lo que se me ocurrió:
public class Packer : IDisposable
{
// chosen quite arbitrarily; can be anything you''d like but should be reasonably unique
private static byte[] MAGIC_NUMBER = { 0x44, 0x61, 0x6c, 0x65, 0x6b, 0x4c, 0x75, 0x63 };
private Stream inStream;
public Packer(string filename, bool openReadonly = false)
{
// The FileAccess.Read is necessary when I whant to read from the file that is being executed.
// Hint: To get the path for the executing file I used:
// System.Reflection.Assembly.GetExecutingAssembly().Location
inStream = File.Open(filename, FileMode.Open, openReadonly ? FileAccess.Read : FileAccess.ReadWrite, openReadonly ? FileShare.Read : FileShare.None);
}
public byte[] ReadData(int index)
{
byte[] mn_buf = new byte[MAGIC_NUMBER.Length];
byte[] len_buf = new byte[sizeof(Int32)];
int data_len = 0;
inStream.Seek(0, SeekOrigin.End);
for (int i = 0; i <= index; ++i)
{
// Read the last few bytes
inStream.Seek(-MAGIC_NUMBER.Length, SeekOrigin.Current);
inStream.Read(mn_buf, 0, MAGIC_NUMBER.Length);
inStream.Seek(-MAGIC_NUMBER.Length, SeekOrigin.Current);
for (int j = 0; j < MAGIC_NUMBER.Length; ++j)
{ // Check if the last bytes are equals to my MAGIC_NUMBER
if (mn_buf[j] != MAGIC_NUMBER[j])
{
throw new IndexOutOfRangeException("Not enough data.");
}
}
inStream.Seek(-sizeof(Int32), SeekOrigin.Current);
inStream.Read(len_buf, 0, sizeof(Int32));
inStream.Seek(-sizeof(Int32), SeekOrigin.Current);
// Read the length of the data
data_len = BitConverter.ToInt32(len_buf, 0);
inStream.Seek(-data_len, SeekOrigin.Current);
}
byte[] data = new byte[data_len];
// Read the actual data and return it
inStream.Read(data, 0, data_len);
return data;
}
public void AddData(byte[] data)
{
// append it
inStream.Seek(0, SeekOrigin.End);
inStream.Write(data, 0, data.
inStream.Write(BitConverter.GetBytes(data.Length), 0, sizeof(Int32));
inStream.Write(MAGIC_NUMBER, 0, MAGIC_NUMBER.Length);
}
public void Dispose()
{
inStream.Dispose();
}
}
Si desea utilizar este fragmento, siga adelante, pero tenga en cuenta que si agrega datos a un archivo, los índices están en orden inverso al recuperarlos:
Digamos que usted escribe el conjunto de datos A primero y luego el conjunto de datos B, si lee los datos más tarde B tendrá el índice 0 y A el índice 1.