Click here to Skip to main content
15,879,535 members
Articles / Programming Languages / C#

Flexible Self Extracting Application in C# (ProjectSFX)

Rate me:
Please Sign up or sign in to vote.
4.89/5 (11 votes)
26 Mar 2012CPOL6 min read 42.1K   2.9K   30   3
This project presents a self extracting archive creator using Reflection and codeDOM

Introduction

Self extracting archives have been extensively used from last couple of decades specially in windows. Most of the installers are self extracting archives which are executable files. These executable store files needed for installation in a centralized manner. In computer slang self extracting archives are also abbreviated as SFX.This project is developed in C# language as an open source project. The download-able content involves visual studio code, which can be manipulated according to custom need of deployment scenario. Presently in this application one can pack his or her data in a self extracting archive which will be a windows executable, running this executable stored data can be extracted as and when needed . Ultimate aim of this project was to replace commercial sfx installers for windows with a free .net based tool although at this time this is just a initial concept of a simple and flexible SFX. Let me explain, this is simple because it is not having many features of professional SFX (they are listed at end of code) and flexible because target SFX archive can be designed in a designer of visual studio though it will be compiled at runtime . An important thing to be noted at this time is that this ordinary open source tools relies on codeDOM and Reflection namespaces. One can learn concept of these with the code presented here. Before starting down the article ensure that reader is aware of basic concepts of adding resources in project. Just Google down you will find plethora of helpful articles over adding resources to ypur project.

Background

I started this project because I wanted an Open Source setup application for IT community. Because of studies I was unable to further develop this project. Contribution to this code at http://sourceforge.net/projects/projectsfx/ is welcomed and highy appriciated.

Software Usage

While running from code please run without debugging.  And also remember that some important files like codeFile1.cs, Form2.cs are in Resources folder of  VS (Visual Studio) solution.

when you run this code following form appears :

Image 1

You can drag and drop files and folders for making SFX archive (Or you can use Add file/folder buttons). Next window shows status of application after clicking Finalize button. A save dialog box appears which should be provided with appropriate file name for SFX archive. A message of success appears after successful save of SFX as:

Image 2

Now you can run the SFX archive which you have saved as by double clicking on it. It appears as:

Image 3

If you keep the "Extract to same directory" check box checked this will extract the contents to same directory or else a save folder dialog will ask you the destination of extraction.

Usability and Flexibility of code

I have taken utmost care so that code is reusable and easy to understand by commenting it everywhere. So that you folks can contribute to this code as well as use it for your own applications. An important feature of this code is that you can modify the final sfx in designer. For this just open the designer from solution pane of VS IDE as for CodeFile1.cs or Form2.cs. As shown : 

Image 4

All important functions to encapsulate folders and files are given in namespace SFX which is distributed in CodeFile1.cs as well (i.e some code of this namespace is also at CodeFile1.cs). Since code is sincerely long it would not be possible to discuss it here. Throughout the source, coding is properly commented for easy understanding and usage. While important code snippets are described below in following section.

Working of Code

Project uses CodeDOM for compiling assembly at run time. Please see following code :

C#
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

{

 SFXmaker.cp = new System.CodeDom.Compiler.CompilerParameters();

 //FileStream f1 = new FileStream(@"C:\item_set11.xml", FileMode.Create);

 FileStream f1 = new FileStream(Environment.GetEnvironmentVariable("TEMP")+"item_set11.xml", FileMode.Create);

 string s1 = Environment.GetEnvironmentVariable("TEMP") + "Form2.cs";

 File.WriteAllText(s1, SFX.Resource1.Form2);

 string s2 = Environment.GetEnvironmentVariable("TEMP") + "Fd.cs";

 File.WriteAllText(s2,

 SFX.Resource1.Form2_Designer);

 File.WriteAllText(Environment.GetEnvironmentVariable("TEMP") + "SFX1.cs",

 SFX.Resource1.CodeFile1.ToString());

 string[] itemstring = Summation.itemstostring(listView1.Items);

 int nof = SFXmaker.countfilesonly(itemstring);

 item_set[] iset = new item_set[nof];

 iset.Initialize();

 SFXmaker.lister(itemstring, ref iset);

 XmlSerializer xs = new XmlSerializer(typeof(item_set[]));

 xs.Serialize(f1,iset);

 f1.Close();

 //SFXmaker.ADD1(@"C:\item_set11.xml");

 SFXmaker.ADD1(Environment.GetEnvironmentVariable("TEMP")+"item_set11.xml");

 foreach (item_set i in iset)

 SFXmaker.ADD1(i.detail.FullName);

 string[] sa = { (Environment.GetEnvironmentVariable("TEMP") + "SFX1.cs"), s1, s2 };

 string err =

 //SFXmaker.Compiler1(@"C:\SFX1.exe", @"E:\Icon1.ico", sa);

 SFXmaker.Compiler1(savefilename, "", sa);//"" string for icon i.e. icon not defined

if (!(err == "")) 

 { 

 //textBox1.Text = err;

 MessageBox.Show(err.ToString());

 }

}

One can see in solution that SFX namespace is having numerous functions which are used through out this application. A function backgroundWorker1_DoWork() is executed asynchronously when finalize button of SFXmaker form is clicked. FileStream f1 creates and gets associated with a temporary file "item_set11.xml". We can see in last few lines of above code snippet that "xs.Serialize()" is using this stream to serialize iset. The string s1 buffers contents of Form2.cs from resources of this application and writes it to "Form2.cs file. Similarly designer file is saved in directory associated with "TEMP" enviornment variables of system. Most important File "CodeFile1.cs" is saved with its content with name "SFX1.cs". This files contains the code to be compiled with their designers. So you can edit these files as prototype for self extracting archive which is dynamically generated at runtime by our application. Last screenshot shows editing of Form contained in CodeFile1.cs in designer. Please note that Form2 that we have saved is startup screen for archive. Now comming to iset, it is nothing but an array instance of itemset. Where itemset is a structure shared by target application (archive) and Parent application (archive generator) under namespace Dist. To see it open CodeFile1.cs and go at end of file the following :

C#
public class item_set

{
 public details_of_item detail;
 public int actual_index;
 public string Name;
 public string folder;
 public item_set()
{
  detail = new details_of_item();
  actual_index = 0;
  Name = "";
  folder = "";
 }

}

As seen it contains different fields viz. actual_index, Name, folder. These fields are actually properties of it items we drop in drag-drop window (listView1) in form "Summation.cs". itemset is associated with listView1 with function SFXmaker.lister() , for which itemset is passed with reference. So modification of itemset by this function are directly in effect.

After this SFXmaker.ADD1() is called two times to push these files (files to be extracted by archive  ) over runtime compiled assembly. This is accomplished using following function of CodeDOM namespace.

<p>CompilerParameters.EmbeddedResources.Add()</p>
The following code snippet presents the defination of Compiler1 in SFXmaker.
C#
public static string Compiler1(string savepath, string pathtoicon, string[] compilefrom)

{

StringBuilder sb = new StringBuilder();

//output type and path to icon

if(pathtoicon!="")

cp.CompilerOptions ="/target:winexe"+" "+"/win32icon:"+"\""+pathtoicon+"\"";

else

cp.CompilerOptions = "/target:winexe";

//gen exe

cp.GenerateExecutable = true;

//useless headers

cp.IncludeDebugInformation = false;

cp.OutputAssembly = savepath;

//wastage of memory 

cp.GenerateInMemory = false;

cp.ReferencedAssemblies.Add("System.dll");

cp.ReferencedAssemblies.Add("System.Data.dll");

cp.ReferencedAssemblies.Add("System.Deployment.dll");

cp.ReferencedAssemblies.Add("System.Drawing.dll");

cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");

cp.ReferencedAssemblies.Add("System.Xml.dll");

//dont treat warings as errors

cp.TreatWarningsAsErrors = false;

pr = new CSharpCodeProvider();

CompilerResults cr = pr.CompileAssemblyFromFile(cp,compilefrom);

if (cr.Errors.HasErrors)

{

for (int i = 0; i < cr.Errors.Count; i++)

{

sb.Append("\n" + ((i + 1).ToString()) +

". Error in compiling:"

+ cr.Errors[i].ToString());

}

}

return (sb.ToString());

}

Above code shows the configuration of codeDOM compiler while compiling the target assembly at runtime. In this way one can compile a run time target and programmer can edit that target in designer before running parent application in visual studios. Finally arriving to an important part of this project i.e Reflection of run time assembly. In order make the SFX self aware about its own content, functions provided under Reflection have been very useful following code snippet demonstrates it.

C#
private void Extract_ALL(string rootp)

        {

            string[] a = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();

            int i = 0;

            StringBuilder sb = new StringBuilder();

            

            foreach (string s in a)

            {

                if (s != a[0])

                {

                    sb.Append(rootp + iset[i].folder + iset[i].Name + "\n");

                      // label2.Text = " Extracting:" + a1;  

                    Stream theResource = System.Reflection.Assembly.GetExecutingAssembly()

                       .GetManifestResourceStream(s);

                    BinaryReader br = new BinaryReader(theResource);

                    Directory.CreateDirectory(rootp + iset[i].folder);

                    FileStream fs = new FileStream(rootp + iset[i].folder + iset[i].Name, FileMode.Create);

                    BinaryWriter bw = new BinaryWriter(fs);

                    byte[] bt = new byte[theResource.Length];

                    theResource.Read(bt, 0, bt.Length);

                    bw.Write(bt);

                    br.Close();

                    bw.Close();

                    fs.Close();

                    //this.label1.Text = "Nakulite SFX";

                    //label3.Text ="Click extract to extract" ;

                    i++;

                  }

                

            }

System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames() enlists all the resource names that are contained in running assembly. Remaining code is just for copy & paste of these resources (embedded files) to destination locations.

Applications of this Code for Community

  1. As an application this project could be used to package any kind of computer contents (files and folders). For this purpose just download the SFX.exe as console run it (you need .NET 2.0 framework installed), extract setup files in some directory. Run setup , as such "Nakulite Summation" will get installed. This is an easy GUI program which could be used to make Self extracting executable archive.
  2. You can use this code to test various compression and encryption algorithms which work on single file but you want to test them on directories. For this modify the following in SFXmaker.cs in VS source with your algorithm as
public static void FSI(string[] fileitems)

{ ..............

else

{ .................. 

// Algorithm over file with "name = sitem"

..................

fn[count].realfilename = sitem; count += 1;

} 

..........

}

To decode at archive side modify CodeFile.cs accordingly.

Code modifications needed

Modifications are needed in code as well as documentation. Following enhancements are needed:

  1. Code is to be provided for registering components programmatically (To make this application professional enough to be used as a setup application).
  2. GUI of SFX needs to be more appealing and professional.
  3. A kind of Registry editor needs to be incorporated as all professional one have them.

Please do acknowledge me if you find code helpful in your projects and leave a message for me on the forum below.

Filnally the source code of archive is compiled at runtime with " SFXmaker.Compiler1(savefilename, "", sa);".

License

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


Written By
Student
India India
About Author:

I am specialized with Embedded Systems, my areas of interest are Real-time Programming, RTOS, Intelligent Sensors and Actuators, Low-level firmware. My projects uploaded on CodeProject are very old and I did them at the time of my first year of Bachelor's degree.
Further, I am not in India, I have now moved to Stuttgart, Germany.

Comments and Discussions

 
Questioni couldn't build the project because the pfx files doesn't imported, what is the password for the pfx files? Pin
ysrc264-Dec-14 0:16
ysrc264-Dec-14 0:16 
Questionregarding decompressing SFX CAB archives Pin
pintokeith5-Jun-12 11:25
pintokeith5-Jun-12 11:25 
AnswerRe: regarding decompressing SFX CAB archives Pin
Nakul Vyas10-Jun-12 20:07
Nakul Vyas10-Jun-12 20:07 
No code doesn't support this,This only does embedding of files in an executable,
You first need a code for decompression of required files in some temporary directory and then onwards you can have your things done.
i.e you can use your own decompression algorithm with this code.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.