How can I extract a file from an embedded resource and save it to disk?

104k Views Asked by At

I'm trying to compile the code below using CSharpCodeProvider. The file is successfully compiled, but when I click on the generated EXE file, I get an error (Windows is searching for a solution to this problem) and nothing happens.

When I compile the code below using CSharpCodeProvider, I've added the MySql.Data.dll as an embedded resource file using this line of code:

if (provider.Supports(GeneratorSupport.Resources))
    cp.EmbeddedResources.Add("MySql.Data.dll");

The file is successfully embedded (because I noticed the file size increased).

In the code below, I try to extract the embedded DLL file and save it to System32, but the code below doesn't work for some reason.

namespace ConsoleApplication1
{
    class Program
    {
        public static void ExtractSaveResource(String filename, String location)
        {
            //Assembly assembly = Assembly.GetExecutingAssembly();
            Assembly a = .Assembly.GetExecutingAssembly();
            //Stream stream = assembly.GetManifestResourceStream("Installer.Properties.mydll.dll"); // or whatever
            //string my_namespace = a.GetName().Name.ToString();
            Stream resFilestream = a.GetManifestResourceStream(filename);
            if (resFilestream != null)
            {
                BinaryReader br = new BinaryReader(resFilestream);
                FileStream fs = new FileStream(location, FileMode.Create); // Say
                BinaryWriter bw = new BinaryWriter(fs);
                byte[] ba = new byte[resFilestream.Length];
                resFilestream.Read(ba, 0, ba.Length);
                bw.Write(ba);
                br.Close();
                bw.Close();
                resFilestream.Close();
            }
            // this.Close();
        }

        static void Main(string[] args)
        {
            try
            {
                string systemDir = Environment.SystemDirectory;
                ExtractSaveResource("MySql.Data.dll", systemDir);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
            }
        }
    }
}

How can I extract the DLL file that is embedded as a resource and save it to System32?

8

There are 8 best solutions below

5
On BEST ANSWER

I have found that the easiest way to do this is to use Properties.Resources and File. Here is the code I use (requires using System.IO)...

For Binary files: File.WriteAllBytes(fileName, Properties.Resources.file);

For Text files: File.WriteAllText(fileName, Properties.Resources.file);

0
On

This works perfectly!

public static void Extract(string nameSpace, string outDirectory, string internalFilePath, string resourceName)
{
    //nameSpace = the namespace of your project, located right above your class' name;
    //outDirectory = where the file will be extracted to;
    //internalFilePath = the name of the folder inside visual studio which the files are in;
    //resourceName = the name of the file;
    Assembly assembly = Assembly.GetCallingAssembly();

    using (Stream s = assembly.GetManifestResourceStream(nameSpace + "." + (internalFilePath == "" ? "" : internalFilePath + ".") + resourceName))
    using (BinaryReader r = new BinaryReader(s))
    using (FileStream fs = new FileStream(outDirectory + "\\" + resourcename, FileMode.OpenOrCreate))
    using (BinaryWriter w = new BinaryWriter(fs))
    {
        w.Write(r.ReadBytes((int)s.Length));
    }
}

Example of usage:

public static void ExtractFile()
{
    String local = Environment.CurrentDirectory; //gets current path to extract the files

    Extract("Geral", local, "Arquivos", "bloquear_vbs.vbs");
}    

If this still doesn't help, try this video out: https://www.youtube.com/watch?v=_61pLVH2qPk

0
On

Try reading your target assembly into a MemoryStream and then saving to a FileStream like this (please bear in mind that this code isn't tested):

//Imports
using System;
using System.IO;
using System.Reflection;

    Assembly assembly = Assembly.GetExecutingAssembly();
    using (var target = assembly.GetManifestResourceStream("MySql.Data.dll"))
    {
        var size = target.CanSeek ? Convert.ToInt32(target.Length) : 0;

        // read your target assembly into the MemoryStream
        MemoryStream output = null;
        using (output = new MemoryStream(size))
        {
            int len;
            byte[] buffer = new byte[2048];

            do
            {
                len = target.Read(buffer, 0, buffer.Length);
                output.Write(buffer, 0, len);
            } 
            while (len != 0);
        }

        // now save your MemoryStream to a flat file
        using (var fs = File.OpenWrite(@"c:\Windows\System32\MySql.Data.dll"))
        {
            output.WriteTo(fs);
            fs.Flush();
            fs.Close();
        }
    }
0
On

I've been using this (tested) method:

OutputDir: Location where you want to copy the resource

ResourceLocation: Namespace (+ dirnames)

Files: List of files within the resourcelocation, you want to copy.

    private static void ExtractEmbeddedResource(string outputDir, string resourceLocation, List<string> files)
    {
        foreach (string file in files)
        {
            using (System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceLocation + @"." + file))
            {
                using (System.IO.FileStream fileStream = new System.IO.FileStream(System.IO.Path.Combine(outputDir, file), System.IO.FileMode.Create))
                {
                    for (int i = 0; i < stream.Length; i++)
                    {
                        fileStream.WriteByte((byte)stream.ReadByte());
                    }
                    fileStream.Close();
                }
            }
        }
    }
0
On

No need to complicate. First, add assembly as an embedded resource.

    private void ExtractAssembly(string dll)
    {
         if (!File.Exists(dll))
             File.WriteAllBytes(dll, Resources.MyDLL);
    }

This has perfectly work for me.

0
On

Or using an extension method...

 /// <summary>
 /// Retrieves the specified [embedded] resource file and saves it to disk.  
 /// If only filename is provided then the file is saved to the default 
 /// directory, otherwise the full filepath will be used.
 /// <para>
 /// Note: if the embedded resource resides in a different assembly use that
 /// assembly instance with this extension method.
 /// </para>
 /// </summary>
 /// <example>
 /// <code>
 ///       Assembly.GetExecutingAssembly().ExtractResource("Ng-setup.cmd");
 ///       OR
 ///       Assembly.GetExecutingAssembly().ExtractResource("Ng-setup.cmd", "C:\temp\MySetup.cmd");
 /// </code>
 /// </example>
 /// <param name="assembly">The assembly.</param>
 /// <param name="resourceName">Name of the resource.</param>
 /// <param name="fileName">Name of the file.</param>
 public static void ExtractResource(this Assembly assembly, string filename, string path=null)
 {
     //Construct the full path name for the output file
     var outputFile = path ?? $@"{Directory.GetCurrentDirectory()}\{filename}";

     // If the project name contains dashes replace with underscores since 
     // namespaces do not permit dashes (underscores will be default to).
     var resourceName = $"{assembly.GetName().Name.Replace("-","_")}.{filename}";

     // Pull the fully qualified resource name from the provided assembly
     using (var resource = assembly.GetManifestResourceStream(resourceName))
     {
         if (resource == null)
             throw new FileNotFoundException($"Could not find [{resourceName}] in {assembly.FullName}!");

         using (var file = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
         {
             resource.CopyTo(file);
         }
     }
 }
1
On
string roamingfolder = System.IO.Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName
                                                                                                                 + "\\Roaming\\hah";
string roamingfile = System.IO.Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName
                                                                                                                     + "\\Roaming\\hah\\image1.jpg";
Assembly asmbly = Assembly.GetExecutingAssembly();
const string NAME = "image_open2.Resources.Billi1609482658k220y8154.jpg";
if (File.Exists(roamingfile))
    File.Delete(roamingfile);
if (!Directory.Exists(roamingfolder))
    Directory.CreateDirectory(roamingfolder);
using (Stream stream = asmbly.GetManifestResourceStream(NAME))
{
    using (FileStream fileStream = new FileStream(roamingfile, FileMode.Create))
    {
         for (int i = 0; i < stream.Length; i++)
         {
              fileStream.WriteByte((byte)stream.ReadByte());
         }
         fileStream.Close();
    }
 }
4
On

I'd suggest doing it easier. I assume that the resource exists and the file is writable (this might be an issue if we're speaking about system directories).

public void WriteResourceToFile(string resourceName, string fileName)
{
    using(var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    {
        using(var file = new FileStream(fileName, FileMode.Create, FileAccess.Write))
        {
            resource.CopyTo(file);
        } 
    }
}