In visual studio, I have a file with build action set to 'Embedded Resource'. I would like to extract this file during runtime but I could not get the filename:
// returns null
Assembly.GetExecutingAssembly().GetManifestResourceInfo(resourceName).FileName
Note that the manifest resource names do include the original file name and project-relative subdirectory.
The key piece of information missing from the other answer (making that answer much less than useful) is that the project name and any folder/directory in which the original file was contained are represented as components in the resource name. That whole manifest resource name is delimited into those components using the '.'
character.
With that knowledge in hand, you should be able to correctly process your resources. In particular, you'll want to remove the first component of the name (which is just the project name), and then treat all but the last component of the name as directory names.
This is a little tricky, due to the fact that a) your file name probably has an extension (and so already has a '.'
character in it), and b) the compiler will escape (in a rudimentary way) any '.'
characters found in folder/subdirectory names.
Here is a code example that shows the basic approach:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(string.Join(Environment.NewLine,
Assembly.GetEntryAssembly().GetManifestResourceNames()));
Assembly assembly = Assembly.GetEntryAssembly();
string exeDirectory = Path.GetDirectoryName(assembly.Location);
foreach (string resourceName in assembly.GetManifestResourceNames())
{
string fileName = _GetFileNameFromResourceName(resourceName),
directory = Path.GetDirectoryName(fileName);
if (!string.IsNullOrEmpty(directory))
{
Directory.CreateDirectory(directory);
}
using (Stream outputStream =
File.OpenWrite(Path.Combine(exeDirectory, fileName)))
{
assembly.GetManifestResourceStream(resourceName).CopyTo(outputStream);
}
}
}
private static string _GetFileNameFromResourceName(string resourceName)
{
// NOTE: this code assumes that all of the file names have exactly one
// extension separator (i.e. "dot"/"period" character). I.e. all file names
// do have an extension, and no file name has more than one extension.
// Directory names may have periods in them, as the compiler will escape these
// by putting an underscore character after them (a single character
// after any contiguous sequence of dots). IMPORTANT: the escaping
// is not very sophisticated; do not create folder names with leading
// underscores, otherwise the dot separating that folder from the previous
// one will appear to be just an escaped dot!
StringBuilder sb = new StringBuilder();
bool escapeDot = false, haveExtension = false;
for (int i = resourceName.Length - 1; i >= 0 ; i--)
{
if (resourceName[i] == '_')
{
escapeDot = true;
continue;
}
if (resourceName[i] == '.')
{
if (!escapeDot)
{
if (haveExtension)
{
sb.Append('\\');
continue;
}
haveExtension = true;
}
}
else
{
escapeDot = false;
}
sb.Append(resourceName[i]);
}
string fileName = Path.GetDirectoryName(sb.ToString());
fileName = new string(fileName.Reverse().ToArray());
return fileName;
}
}
Create a new project with the above code, and then add embedded resources to the project, in project folders or not as you like, to see the result.
NOTE: you may find that it's useful to filter the resource names list. For example, you'll get a resource named something like MyProjectName.Resources.resources
if your project has traditional resources that you've added using the Designer (i.e. showing the project properties, then clicking on the "Resources" tab and adding resources there instead of explicitly as embedded resources). Otherwise, you will get literally every single manifest resource.
NOTE: keep in mind that to write to the directory where the executable is running from, you might need higher level of privileges than the current process has. E.g. if the user copies your EXE to a directory in the "Program Files" directory as admin, but then tries to run the program as a limited user. As commenter Luaan intimates above under your question, it does seem like you would be better off just implementing some sort of installer. (Visual Studio provides free access to the basic Install Shield product, or you can use e.g. WiX…it's not actually necessary to write an installer from scratch to implement an installer).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With