Visual Studio comes up with a user interface tool to manage resources. The Resource Designer allows you to add/edit resources in an assembly at design-time. But, the resources might not be available at design-time: consider a scenario where the user provides some pictures to be embedded into a slideshow application. In that case, the Resource Designer is helpless. When you need to add resources at runtime, you are just alone.
This article shows how to embed resources at runtime by creating dynamic assemblies. It also shows how to compress files using the .NET Framework.
Why embed resources into an existing executable file at runtime? I was working on a script-driven testing tool. The tool is used both by advanced users and by validation users. Advanced users edit script files and validation users run scripts. To make the job of validation users easier, advanced users should be able to deploy their scripts as standalone executables.
I decided to package the script file and all its dependencies into the executable script engine as embedded resources. I finally came up with the solution described in this article. I found the result interesting enough to share it with you. Since the script-driven testing tool is not a suitable demonstration application, I looked for something else and the self-extractor compiler is the first idea that came across my mind.
The code is organized in three parts:
ArchiveCompiler.Demo namespace contains the demo project.
SelfExtractor class in ArchiveCompiler.cs contains the logic to build a standalone executable with selected files embedded as resource.
- The SelfExtractor.cs file contains the source code built by the
SelfExtractor class to generate the standalone executable.
1. Demo App
The self-extracted archive compiler (see screenshot above) is provided as an example. It demonstrates the dynamic creation of assemblies with embedded resources. Drop some files on the form and click the bottom-right button to create a self-extracted archive:
using (SelfExtractor archive = new SelfExtractor())
foreach (IconFileInfo file in files)
The 'Run first item after extraction' option defines the
RUN_1ST_ITEM symbol that enables a piece of code in the SelfExtractor.cs file. After extraction, the self-extracted archive starts a new process with the first embedded file (e.g., open a readme file, run post-extraction action...).
2. SelfExtractor Class
SelfExtractor class exposes two methods,
CompileArchive. Call the
AddFile method for each file to be included into the self-extracted archive. The file is compressed using the
System.IO.Compression.GZipStream class. A temporary file is created with a '.gz' extension in the same directory as the selected file. The temporary compressed filename is added to the list of files ready to be embedded into the self-extracted archive.
SelfExtractor class implements the
IDisposable interface. The
Dispose method is used to release unmanaged resources held by an instance of the class. Disposing a
SelfExtractor object deletes all temporary compressed files created by the
public void AddFile(string filename)
using (Stream file = File.OpenRead(filename))
byte buffer = new byte[file.Length];
if (file.Length != file.Read(buffer, 0, buffer.Length))
throw new IOException("Unable to read " + filename);
using (Stream gzFile = File.Create(filename + ".gz"))
using (Stream gzip = new GZipStream
gzip.Write(buffer, 0, buffer.Length);
filenames.Add(filename + ".gz");
CompileArchive method contains the logic to build the self-extracted archive at runtime. It is based on the
Microsoft.CSharp.CSharpCodeProvider class. It compiles an assembly from the source code contained in the SelfExtractor.cs file. The temporary compressed files are embedded as resource using the
EmbeddedResources property of the
To keep things simple, the SelfExtractor.cs file is deployed side by side with the assembly containing the
public void CompileArchive(string archiveFilename, bool run1stItem, string iconFilename)
CodeDomProvider csc = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = true;
cp.OutputAssembly = archiveFilename;
cp.CompilerOptions = "/target:winexe";
cp.CompilerOptions += " /define:RUN_1ST_ITEM";
cp.CompilerOptions += " /win32icon:" + iconFilename;
CompilerResults cr = csc.CompileAssemblyFromFile(cp, sourceName);
if (cr.Errors.Count > 0)
string msg = "Errors building " + cr.PathToAssembly;
foreach (CompilerError ce in cr.Errors)
msg += Environment.NewLine + ce.ToString();
throw new ApplicationException(msg);
The SelfExtractor.cs file is the source code file compiled at runtime by the
SelfExtractor class. It builds a simple Windows Forms application with a single hidden form. The job is done in the handler of the form
Load event. First, it prompts the user for the output location. Then, embedded files are retrieved from resources and decompressed in the target directory. If the SelfExtractor.cs file has been compiled with the
RUN_1ST_ITEM symbol, a new process is started with the first extracted file.
private void Form1_Load(object sender, EventArgs e)
Visible = false;
ShowInTaskbar = false;
FolderBrowserDialog fbd = new FolderBrowserDialog();
fbd.Description = "Please, select a destination folder.";
if (fbd.ShowDialog() == DialogResult.OK)
Assembly ass = Assembly.GetExecutingAssembly();
string res = ass.GetManifestResourceNames();
foreach (string name in res)
Stream rs = ass.GetManifestResourceStream(name);
using (Stream gzip = new GZipStream
(rs, CompressionMode.Decompress, true))
string path = Path.Combine(fbd.SelectedPath,
using (Stream file = File.Create(path))
for (int b = gzip.ReadByte();
b != -1; b = gzip.ReadByte())
if (res.Length > 0)
catch (Exception ex)
MessageBox.Show(this, ex.Message, ass.GetName().Name,
In this article, we saw how to compress files with the
System.IO.Compression namespace. We also saw how to dynamically create an assembly with embedded resources.
As mentioned in the Background section, creating a self-extracted archive compiler is not our primary objective. To keep the code as simple as possible, I deliberately ignore some issues. First, the original directory structure is not preserved. Secondly, write permission is required in every directory of the archived files in order to create the temporary compressed files.
An alternative to the dynamic creation of assemblies could be the
UpdateResource Win32 API with P/Invoke. It allows you to add/edit resources in an existing executable file. This API can be an option if the assembly cannot be built at runtime (too complex to build, source code not available...).
I chose the
System.IO.Compression namespace for compression because it does not require additional reference. If you need to preserve the original directory structure, you should use a different solution such as a third-party ZIP library, the java.utils.zip utility from J#, or the
System.IO.Packaging namespace if you are using .NET Framework 3.0.
- December 03, 2008 - Original article.
- July 30, 2009
- Self-extracting EXE prompts for output location.
- Custom icon support for self-extracting EXE.