i recently implemented the following code in order to programatically build a project/exe. In this exe build, i wanted to store a bunch of "actual files" inside of resources, as streams.
Here's how i'm adding the files into the resource file (singular), and then embedding that resource file into the compiler parameters:
List<string> UserFiles = new List<string>();
UserFiles.AddRange(Helpers.GetFilesInFolder(this.txt_Publish_Folder.Text));
string folder = this.txt_Package_Location.Text;
folder = folder + "\\Package_" + DateTime.Now.ToLongTimeString().Replace(":", "_").Replace(".", "_");
Directory.CreateDirectory(folder);
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = true;
parameters.IncludeDebugInformation = true;
parameters.GenerateInMemory = false;
parameters.WarningLevel = 3;
parameters.CompilerOptions = "/optimize";
parameters.OutputAssembly = folder + "\\Install_" + this.txt_AppName.Text + ".exe";
parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("System.Data.dll");
parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
parameters.ReferencedAssemblies.Add("System.Xml.dll");
parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
if (codeProvider.Supports(GeneratorSupport.Resources))
{
string temp = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
//create temp file first, because we want to append to it so as to have a single resource file with multiple stream entries...
File.WriteAllText(temp, null);
for (int i = 0; i < UserFiles.Count; i++ )
{
byte[] FileBytes = File.ReadAllBytes(UserFiles[i]);
using (FileStream stream = new FileStream(temp, FileMode.Append))
{
using (ResourceWriter writer = new ResourceWriter(stream))
{
writer.AddResource(Path.GetFileName(UserFiles[i]), FileBytes);
}
}
}
parameters.EmbeddedResources.Add(temp);
}
CompilerResults res = codeProvider.CompileAssemblyFromFile(parameters, @"C:\HIDDENPATH\Program.cs");
This works great, doesn't yield any errors, and i can actually get the embedded resource file out in the Console Application i built (the one referenced above as Prorgam.cs) through the code below. The problem i am having however is with "Loading" this resource file into the application assembly / getting its values out somehow... here's the code i have so far to do that:
static void Main(string[] args)
{
Console.WriteLine("Checking for resources... please wait...");
Assembly thisExe;
thisExe = Assembly.GetExecutingAssembly();
List<string> resources = thisExe.GetManifestResourceNames().ToList();
if(resources.Count >= 1)
{
try
{
string baseName = resources[0];
ResourceManager mgr = new ResourceManager(baseName, thisExe);
Console.WriteLine("retrieved manager...");
Console.ReadLine();
ResourceSet set = mgr.GetResourceSet(Thread.CurrentThread.CurrentCulture, true, true);
int count = set.Cast<object>().Count();
Console.WriteLine("Found [" + count.ToString() + "] embedded resources. Would you like to enumerate them?");
ConsoleKeyInfo input = Console.ReadKey();
if (input.Key == ConsoleKey.Y)
{
// Build the string of resources.
foreach (string resource in resources)
Console.WriteLine(resource);
}
}
catch (Exception ex)
{
Console.Write(ex.Message);
Console.ReadLine();
}
}
Console.ReadLine();
}
Whenever i run the built exe, i get the following result:
Checking for resources... please wait... retrieved manager... Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "tmpCC59.tmp.resources" was correctly embedded or linked into assembly "Install_testing" at compile time, or that all the satellite assemblies required are loadable and fully signed.
Can someone please tell me why this is happenning? i've tried all different culture sets i could think of and still nothing comes out. Is the problem related to how i'm "Embedding" or how i'm "Loading" ?