41

How do I embed an external executable inside my C# Windows Forms application?

Edit: I need to embed it because it's an external free console application (made in C++) from which I read the output values to use in my program. It would be nice and more professional to have it embedded.

Second reason is a requirement to embed a Flash projector file inside a .NET application.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Josh
  • 13,530
  • 29
  • 114
  • 159
  • 2
    The question is: what do you want to with that "external executable"? if just embedding and getting it out, when "Embedded Resource" – tofi9 Apr 28 '09 at 16:05
  • And if it is just `running it and getting its output` then deploy it side by side. No need for it to be embedded. Likewise the Flash file, your _could_ just deploy it with your program, if that's all you really need. I suspect you have some more **needs** that you haven't bothered to list. :) – Jesse Chisholm Feb 03 '15 at 22:07

8 Answers8

63

Simplest way, leading on from what Will said:

  1. Add the .exe using Resources.resx
  2. Code this:

    string path = Path.Combine(Path.GetTempPath(), "tempfile.exe");  
    File.WriteAllBytes(path, MyNamespace.Properties.Resources.MyExecutable);
    Process.Start(path);
    
Community
  • 1
  • 1
dav_i
  • 27,509
  • 17
  • 104
  • 136
  • 1
    Of course, it is wise to check if the file exists and/or delete the file afterwards as appropriate. – dav_i Nov 06 '12 at 16:04
  • 1
    this can be useful, What is MyExecutable after Properties.Resources.[MyExecutable], is this a defined object for the embeded resource? – digitai May 02 '17 at 21:19
  • Don't forget to set it's `FileType` to `Binary` when you add the file into your resource, Otherwise you'll get an error `cannot convert string to byte[]`. To do that, click on the resource file after you add it and from the properties you'll see the `FileType` and set it to `Binary`. – Polar Aug 09 '19 at 02:46
25

Here is some sample code that would roughly accomplish this, minus error checking of any sort. Also, please make sure that the license of the program to be embedded allows this sort of use.

// extracts [resource] into the the file specified by [path]
void ExtractResource( string resource, string path )
{
    Stream stream = GetType().Assembly.GetManifestResourceStream( resource );
    byte[] bytes = new byte[(int)stream.Length];
    stream.Read( bytes, 0, bytes.Length );
    File.WriteAllBytes( path, bytes );
}

string exePath = "c:\temp\embedded.exe";
ExtractResource( "myProj.embedded.exe", exePath );
// run the exe...
File.Delete( exePath );

The only tricky part is getting the right value for the first argument to ExtractResource. It should have the form "namespace.name", where namespace is the default namespace for your project (find this under Project | Properties | Application | Default namespace). The second part is the name of the file, which you'll need to include in your project (make sure to set the build option to "Embedded Resource"). If you put the file under a directory, e.g. Resources, then that name becomes part of the resource name (e.g. "myProj.Resources.Embedded.exe"). If you're having trouble, try opening your compiled binary in Reflector and look in the Resources folder. The names listed here are the names that you would pass to GetManifestResourceStream.

Charlie
  • 44,214
  • 4
  • 43
  • 69
  • 3
    Ahem. GMRS is the OLD way to do this. You can just embed the .exe in the assembly as a byte array which is accessible as a property. Two steps to get it and save it to disk, instead of the monstrosity with magic strings you've suggested. [Here's a page on how to create strongly typed resources in VS.](http://msdn.microsoft.com/en-us/library/t69a74ty(VS.90).aspx) –  Aug 17 '10 at 12:40
  • 35
    Sorry, clearly this isn't the most up-to-date answer, but I'm not sure it really deserves to be called a "monstrosity". – Charlie Aug 19 '10 at 21:35
  • Don't forget to set it's `FileType` to `Binary` when you add the file into your resource, Otherwise you'll get an error `cannot convert string to byte[]`. To do that, click on the resource file after you add it and from the properties you'll see the `FileType` and set it to `Binary`. – Polar Aug 09 '19 at 02:47
14

Just add it to your project and set the build option to "Embedded Resource"

scottm
  • 27,829
  • 22
  • 107
  • 159
8

This is probably the simplest:

byte[] exeBytes = Properties.Resources.myApp;
string exeToRun = Path.Combine(Path.GetTempPath(), "myApp.exe");

using (FileStream exeFile = new FileStream(exeToRun, FileMode.CreateNew))
    exeFile.Write(exeBytes, 0, exeBytes.Length);

Process.Start(exeToRun);
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • 1
    what is myApp after Properties.Resources? Is this a custmo class for the embeded resource? – digitai May 02 '17 at 21:20
  • @datelligence myApp is your custom resource name. The one you have added/embedded to your resources file. In my case it is an executable with .exe extension. – nawfal May 03 '17 at 03:00
4

Here's my version: Add the file to the project as an existing item, change the properties on the file to "Embedded resource"

To dynamically extract the file to a given location: (this example doesn't test location for write permissions etc)

    /// <summary>
    /// Extract Embedded resource files to a given path
    /// </summary>
    /// <param name="embeddedFileName">Name of the embedded resource file</param>
    /// <param name="destinationPath">Path and file to export resource to</param>
    public static void extractResource(String embeddedFileName, String destinationPath)
    {
        Assembly currentAssembly = Assembly.GetExecutingAssembly();
        string[] arrResources = currentAssembly.GetManifestResourceNames();
        foreach (string resourceName in arrResources)
            if (resourceName.ToUpper().EndsWith(embeddedFileName.ToUpper()))
            {
                Stream resourceToSave = currentAssembly.GetManifestResourceStream(resourceName);
                var output = File.OpenWrite(destinationPath);
                resourceToSave.CopyTo(output);
                resourceToSave.Close();
            }
    }
Fred B
  • 175
  • 1
  • 3
  • 11
4

Is the executable a managed assembly? If so you can use ILMerge to merge that assembly with yours.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
1
  1. Add File to VS Project
  2. Mark as "Embedded Resource" -> File properties
  3. Use name to resolve: [Assembly Name].[Name of embedded resource] like "MyFunkyNTServcice.SelfDelete.bat"

Your code has resource bug (file handle not freed!), please correct to:

public static void extractResource(String embeddedFileName, String destinationPath)
    {
        var currentAssembly = Assembly.GetExecutingAssembly();
        var arrResources = currentAssembly.GetManifestResourceNames();
        foreach (var resourceName in arrResources)
        {
            if (resourceName.ToUpper().EndsWith(embeddedFileName.ToUpper()))
            {
                using (var resourceToSave = currentAssembly.GetManifestResourceStream(resourceName))
                {
                    using (var output = File.OpenWrite(destinationPath))
                        resourceToSave.CopyTo(output);
                    resourceToSave.Close();
                }
            }
        }
    }
Martin.Martinsson
  • 1,894
  • 21
  • 25
0

Extract something as string, if needed:

public static string ExtractResourceAsString(String embeddedFileName)
    {
        var currentAssembly = Assembly.GetExecutingAssembly();
        var arrResources = currentAssembly.GetManifestResourceNames();
        foreach (var resourceName in arrResources)
        {
            if (resourceName.ToUpper().EndsWith(embeddedFileName.ToUpper()))
            {
                using (var resourceToSave = currentAssembly.GetManifestResourceStream(resourceName))
                {
                    using (var output = new MemoryStream())
                    {
                        resourceToSave.CopyTo(output);
                        return Encoding.ASCII.GetString(output.ToArray());
                    }
                }
            }
        }

        return string.Empty;
    }
Martin.Martinsson
  • 1,894
  • 21
  • 25