Solved! See below.
I have 2 C# applications. Application a is supposed to modify the internal resources of application b. Application b is supposed to do something with its (modified) resources when executed.
How can I accomplish that?
Here is what I tried:
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);
}
}
}
I get a System.ArgumentException
with The stream is readonly.
on System.Resources.ResourceWriter..ctor(Stream stream)
EDIT
Since that does not seem to be possible with .net resources: Is there any other way?
I want to produce a single file (namely the exe of application b
) which is executable and can work with the data (stored in the exe) that is given prior to execution from application a
. Preferably without having to actually compile b
in order to give it the data.
Assumptions in order to make it a little easier:
a
is always executed beforeb
a
is only executed once- both applications are written by me
Edit - Sollution
Since it is not possible to accomplish that via resources I used the following workaround:
Apparently you can append ANYTHING to an exe file and it will still be executable, so here is what I came up with:
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();
}
}
If you want to use this snippet go ahead but note that if you add data to a file the indexes are in reverse order when retrieving:
Let's say you write data set A first and then data set B, if you read the data later B will have the index 0 and A the index 1.