How to embed multilanguage *.resx (or *.resources) files in single EXE? - c#

There are plenty of tutorials how to create multilanguage RESX files and how to create satellite assemblies with AL.exe, but I haven't found working example how to embed RESX/Resources/satellite-DLL files in single EXE file and distribute whole multilanguage app as such EXE.
I tried to use ilmerge.exe, but it looks like it doesn't work for multiple DLLs with the same name (culture satellite DLLs have identical names, originally residing in different subdirs named after culture).
I also don't know how to create ResourceManager instance to work with embedded resources.
My goals is to enable dynamical switching between closed, pre-defined set of languages. I need class/method which will get culture string (i.e. "de-DE"), resource name (i.e. "CancelText") and return translated text based on embedded resx/resource/dll.
I'm using VS2008, please note what setting for "build action" is needed in resx/resource files properties sheet. Working code sample or link to tutorial project would be the best.

My solution: program contains only one default language resource file (resx). All other languages are compiled from .resx to .resources and embedded as resource file. Important! I have changed extension because ".resources" is recognized as a special type of resource, so my French files is named "PIAE.LangResources.fr".
Here is simple code to retrieve translated string (it should be improved with caching values from resource):
internal static string GetString(string str, string lang)
{
if (string.IsNullOrEmpty(str)) throw new ArgumentNullException("empty language query string");
if (string.IsNullOrEmpty(lang)) throw new ArgumentNullException("no language resource given");
// culture-specific file, i.e. "LangResources.fr"
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("PIAE.LangResources."+lang);
// resource not found, revert to default resource
if (null == stream)
{
stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("PIAE.Properties.LangResources.resources");
}
ResourceReader reader = new ResourceReader(stream);
IDictionaryEnumerator en= reader.GetEnumerator();
while (en.MoveNext())
{
if (en.Key.Equals(str))
{
return en.Value.ToString();
}
}
// string not translated, revert to default resource
return LangResources.ResourceManager.GetString(str);
}

You didn't find it because it's not the way the .NET framework works. .NET expects satellite DLLs in specifically named location (iow directories named after the language of the resources it contains. eg. de, de-DE, chs,...). If you don't work that way, .NET won't be able to apply its magic (which is to automatically pick the correct resource according to the current UI culture: Thread.CurrentThread.CurrentUICulture).

Use this program, it Works with me: EXEPack
You just need to do manually everytime you compile, not sure if there is a command tool.

I used the GetString approach above. The article Can't load a manifest resource with GetManifestResourceStream() describes how to correctly retrieve your resource as a stream object. After that, everything worked.

Related

Embed a file into an external exe with C#

So I've made an interpreted programming language, and everything is going fine except one thing: I want to make a "compiler" that will embed the user's code into a copy of the interpreter, that way all the user needs to do is double click the executable with the code embedded into it and it would run.
So the question is: how can I embed a file into an already compiled executable? I do have access to the executable before it's compiled, but the embedding process must happen after.
I would prefer the solution to be in C# but I'm desperate and could use C++ or VB.NET, or even a batch file
So after some intense googling I found a library called Mono.Cecil which does exactly what I want. I was able to inject a file into an executable file by using the following code:
string fileName = "Interpreter.exe"; // The file which will have toInject injected in it
string outputName = "Compiled.exe"; // The output file to compile
string toInject = "program.txt"; // The file we will be injecting into fileName
string resourceName = "program.txt"; // The name of the file once it's inside fileName
var module = ModuleDefinition.ReadModule(filename);
var file = new EmbeddedResource(
resourceName,
ManifestResourceAttributes.Private,
File.ReadAllBytes(toInject));
module.Resources.Add(file);
module.Write(outputName);

Xamarin.Forms Can not Read Text file from Resources Returned Null

I am using Xamarin.Forms, and I am trying to read text file from Resources, Code Below Returned Null value when trying to fetch text file.
var assembly = typeof(BookPage).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream("AboutResources.txt");
//assembly here return null value, I can not find Text Resources
My Code under the following Class Inherited From ContentPage On PLC Project
public class BookPage : ContentPage
//First get the list of all resources available for debugging purpose
assembly.GetManifestResourceNames()
This will list all the (fully qualified names) of all resources embedded in the assembly your code is written in.
Link: http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getmanifestresourcenames(v=vs.110).aspx
Check if it has "AboutResources.txt" that you are expecting.
Check if you have incorrectly embedded the resource file, it will not show up in the list returned by the call to GetManifestResourceNames(). Make sure you you match the case of the name.
The following steps working fine for me:
1-First of all I added resource text file to same project
2-The file path must be like "Your Project name.your custom folder.filename".
var fileName = "MySampleProject.XMLData.rawxmldata.xml".
3-Make sure that Build Action is EmbeddedResource.

Read .txt embedded as resource

I have embedded a resource into my code, I want to read the text and apply the text to some string variables. I have worked out how to do that when I use an external file but I only want the .exe
string setting_file = "config.txt";
string complete = File.ReadAllText(setting_file);
string Filename = complete.Split('#').Last(); //"Test.zip";
string URL = complete.Split('#').First();
How can I read the resource config.txt
(Preferably without new procedures)
The File class is only used for accessing the file system whereas your file is no longer in the system so this line needs to change. As others have hinted with linked answers you need to get the stream for the resource and then read that. The below method can be called to replace your File.ReadAllText method call.
private static string GetTextResourceFile(string resourceName)
{
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
using (var sr = new StreamReader(stream))
{
return sr.ReadToEnd();
}
}
The resourceName will be something along the lines of MyNamespace.Myfile.txt. If you are having problems finding your resourcename then the method GetManifestResourceNames on the assembly will help you identify it while debugging.
Also of note is the above method will throw an exception if the resource isn't found. This should be handled in real code but I didn't want to confuse the above sample with standard error handling code.
See also How to read embedded resource text file for a different question with the same answer (that differs in that it asks only about streams but in fact streams seem to be the only way to access embedded resource files anyway).
This is how you can use embedded files Properties.Resources.yourfilename

Accessing Resources at Runtime

I have an XML file included as part of my Silverlight 4.0 project that I'd like to access at runtime. I have the file saved in a directory named Resources with the Build Action set to "Content" and the Copy to Output Directory set to "Do not copy". If I decompress the XAP file, I see the XML file in the location I expect it to be, but I'm not sure how to reference it from code. I currently have the following:
Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(#"/AssemblyName;component/Resources/MyFile.xml")
Unfortunately, stream is null after running the code above. In addition to the path mentioned above, I've tried "/Resources/MyFile.xml", "/MyFile.xml" and "MyFile.xml", but they all experience the same behavior.
What is the correct way to access an XML file embedded as a resource in a Silverlight application?
A resource with build action "Content" just gets embedded into the xap file, with the same relative directory structure as the application. It does not get embedded as a resource in the assembly.
When set to build action "Content", you should be able to just load the file using something like (or whatever suits your needs):
XElement.Load(<relative directory>/<file>)
The method you're using currently (using a resource stream) is for embedded resources (which have their build action set to "Resource"). And for those, although I haven't tried yet if your method works, usually you'll get the resources using
Application.GetResourceStream
I have used the code snip below to get access to drawables. Not sure it's completely relevant, but hoping this will give you a hint one way or another ...
Resources res = getResources();
spec = tabHost.newTabSpec("groups").setIndicator("Groups", res.getDrawable(R.drawable.ic_tab_groups)).setContent(intent);
As was mentioned by Willem van Rumpt, "content" resources are not usual resources (they aren't stored in assembly). I've checked out this article and could't found at all that you could reference resource, marked as "content" from other assembly.
So, you have two options:
Define XML as embedded resource
Define XML as resource
In first case stream request looks like:
var a = Assembly.Load("AssemblyName");
var s = a.GetManifestResourceStream(#"DefaultNamespace.Resources.XMLFile2.xml");
In second case:
var a = Assembly.Load("AssemblyName");
var rm = new ResourceManager("AssemblyName.g", a);
using (var set = rm.GetResourceSet(CultureInfo.CurrentCulture, true, true))
{
var ums = (UnmanagedMemoryStream)set.GetObject(#"Resources/XMLFile1.xml", true);
}
Hope this helps.

Problem with creating ResXResourceSet object from the embedded resource file

I am trying to open a resx file that is a resource in my C# project. I need to create a ResXResourceSet object. However at runtime an "Illegal characters in path" exception is thrown. This is the code I am trying to use.
var resX = new ResXResourceSet(Project.Properties.Resources.ResXFile);
The ResXResourceSet class has only two constructors (from stream and from file name). How can I create an object of the ResXResourceSet class in this situation?
Use Project.Properties.Resources.ResourceManager.GetStream("ResXFile");
If I understand correctly, the value in ResXFile is a string with the complete contents of the ResX, and not a file path, which is what ResXResourceSet expects when you pass it a string. You'll need to wrap a stream around it.
See this question for getting a stream from a string: how to generate a stream from a string?
Also, if you make the resource file into a project item, like the main resources, you can access its ResourceSet through its ResourceManager: ResXFile.ResourceManager.GetResourceSet()
You can add a ResX to your project by rightclicking on the project > Add > New Item > Resources File.

Categories

Resources