Click here to Skip to main content
15,113,225 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am using the methods below to embed any number of files inside an executable

C#
    private void EmbedFiles(IEnumerable<string> files)
    {
        const string exePath = @"C:\SimpleApp.exe";

        foreach (var file in files)
            ResourceUpdate.WriteFileToResource(exePath, file);
    }

[DllImport("kernel32.dll", EntryPoint = "BeginUpdateResourceW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    internal static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);
    [DllImport("kernel32.dll", EntryPoint = "UpdateResourceW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    internal static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, short wLanguage, byte[] lpData, int cbData);
    [DllImport("kernel32.dll", EntryPoint = "EndUpdateResourceW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    internal static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
    internal static void WriteFileToResource(string path, string file)
    {
       // var resourceName = Path.GetFileNameWithoutExtension(file);
        var resourceName = Path.GetFileName(file);
        using (var binaryStream = new FileStream(file, FileMode.Open, FileAccess.Read))
        {
            byte[] data = null;
            var resourceLanguage = MakeLanguageID();
            try
            {
                data = new byte[binaryStream.Length];
                binaryStream.Read(data, 0, (int)binaryStream.Length);
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Error reading {0}: {1}", file, ex.Message), ex);
            }

            var h = BeginUpdateResource(path, false);
            Write(h, "File", resourceName, resourceLanguage, data);
        }
    }
    internal static void Write(
        IntPtr h,
        string resourceType,
        string resourceName,
        short resourceLanguage,
        byte[] buffer)
    {
        try
        {
            if (UpdateResource(h, resourceType, resourceName, resourceLanguage, buffer, buffer.Length))
                EndUpdateResource(h, false);
            else
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        catch (Exception ex)
        {
            throw new Exception(string.Format("Error writing {0}: {1}", resourceName, ex.Message), ex);
        }
    }

    static short MakeLanguageID()
    {
        return (short)CultureInfo.CurrentUICulture.LCID;
    }


In the code below what I am trying to do is to extract the embedded files from the target exe in order to save them in a selected directory but I am not able to find the embedded resources knowing that they are there and I can see them using a tool like Resource Hacker.

C#
    var assembly = Assembly.GetExecutingAssembly();

    var names = Assembly.GetExecutingAssembly().GetManifestResourceNames();

    foreach (string filename in names)
    {
        MessageBox.Show(filename);
        //var stream = assembly.GetManifestResourceStream(filename);
        //var rawFile = new byte[stream.Length];

        //stream.Read(rawFile, 0, (int)stream.Length);

        //using (var fs = new FileStream(filename, FileMode.Create))
        //{
        //    fs.Write(rawFile, 0, (int)stream.Length);
        //}
    }
}


I created a sample project to show the problem. Please find it here

Any advice or help would be much appreciated.
Posted
Comments
Maciej Los 30-Mar-13 8:33am
   
What error?
Fadi F 30-Mar-13 8:52am
   
GetManifestResourceNames() cannot find the embedded resources
   
It means that it does not have those resources...
—SA
Fadi F 1-Apr-13 15:02pm
   
But I can see my resources using Resource hacker or other tools and the size of the executable exceeds by the total size of the embedded files.
   
This method only shows .NET resources; each name corresponds to on *.resx; the generated resource name is derived from such file name...
Try to create such resources; and you will see.
Also, are you sure that the resources are in executing assembly? They can be in entry assembly, some other assembly of the process...
—SA
Fadi F 1-Apr-13 15:35pm
   
Yes, the resources are in the executing assembly. Here is a sample project and a screenshot of the resource hacker showing my embedded files: http://sdrv.ms/11Tz5FD
Is there any way I can extract the files out from an executing assembly?
   
Are they *.resx resources, or something else?
What do you got in

var names = Assembly.GetExecutingAssembly().GetManifestResourceNames();

?

Is it empty array, or what?
—SA
Fadi F 1-Apr-13 15:52pm
   
No, they are normal files. I am trying to implement a self extracting archive for maintenance purposes that can include any kind of file.
   
I have no idea what's the "normal file"... Assemblies usually use *.resx :-)
—SA
Fadi F 1-Apr-13 16:27pm
   
I was able to use BeginUpdateResource/UpdateResource/EndUpdateResource methods to embed .exe and .dll files in my executable.
   
Do you embed executable files in other executable? Wow! Why? But still, you can do it using *.resx, "Add existing file". It would solve your problem.
—SA
Fadi F 1-Apr-13 16:50pm
   
I didn't get the idea, do you mean I can just rename the files to .resx before embedding them?
Please note that my intention is to create a tool that can embed .exe, .sql and .ddl files at runtime
   
No, of course not. Do you know how to add resources .NET way, as *.resx? Add the resource, use "Add existing file" for file of any nature... resources will be embedded into an executable module, then you can access them during runtime... Do you need help with that?
—SA
Fadi F 1-Apr-13 17:41pm
   
That way I have to make a new build each time I want to embed new files which is not my case. Actually, I am building a utility application that allows certain users(developers), to select files and embed them in other executable that is to be delivered to other users(support people) that can execute it on client machines.
   
Wait a second. Do you want to embed resources to an already built assembly during runtime? I would like to know the goal of it; to me it looks like an extreme abuse. Resources are not designed for such things.
—SA
Fadi F 2-Apr-13 6:39am
   
Why do you feel it is an abuse. I think it is how self extracting or decrypting archive works.
Here are a couple of links that explain the same
http://stackoverflow.com/questions/4939513/creating-a-pgp-sda-in-c-sharp-using-the-bouncy-castle-api#
http://www.codeproject.com/Articles/39/Creating-a-Self-Extracting-Executable
   
Because resources are designed to be read-only. As to .NET assemblies, it's recommended to sign them. If you modify a file of a signed assembly, it won't load, because the signing is, among other things, also a protection against modification. Everything is designed to have modules immutable...

Anyway, thank you for information, I'll take a look.
—SA
   
Wait a second. The article is about self-extracting executables. I don't see where the resources are modified during runtime. Above, I asked for your confirmation: are you going to modify already built assembly? Maybe, there is a misanderstanding...
—SA
Fadi F 2-Apr-13 9:26am
   
Yes I want to modify already built executable assembly to include my files in its resources section and retrieve them later.
   
Then it's different from self-extracting executables. I explained why this is the abuse. Please, do yourself a favor and don't do it. All the programming paradigm, since early computing history, is based on non-modifiable executables. Don't get into trouble...
—SA
   
By the way, do you understand that if some executable module is loaded, it's impossible to modify it?
Anyway, I would close the discussion. I doubt anyone will help you. If you try to motivate such technique, I would be curious to listed to it, hardly more than that...
—SA
   
You can find some short overview here:
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/1dc2b719-55ef-49ba-832a-1a6a14e36e38/
Fadi F 1-Apr-13 16:00pm
   
I think as you mentioned above this works only for .resx files
   
That's the point...
AnotherKen 17-Apr-13 3:05am
   
one thing that tripped me up on this originally was that I learned belatedly that you have to set the resource file's build attribute to "embedded resource" to get a valid assembly reference to it. This is easy enough to do with the Visual Studio IDE, it should be possible to do this directly from the code too.

The extraction code that works for me is based on this:

Assembly assembly = Assembly.GetCallingAssembly();
string resourceName = assembly.GetName().Name + "." + rName.Replace(" ", "_").Replace("\\", ".").Replace("/", ".");
Stream keyStream = assembly.GetManifestResourceStream(resourceName);

in that example, rName was defined earlier and in this case is just the name of the embedded text file.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900