I am working on the HealthVault SDK from Microsoft, I am trying to include a few translations for the text resources provided with SDK.
This is a piece of resource file used
resources.restext
# Used in many files
ListSeparator=,
ListFormat=, {0}
GroupSeparator=;
GroupFormat=; {0}
Range={0} - {1}
DateRange={0} to {1}
This is the code that initializes the Resource manager.
private static ResourceManager InitRMWithAssembly(
string baseName,
Assembly assemblyToUse,
Type usingResourceSet)
{
ResourceManager rm = null;
if (usingResourceSet != null &&
baseName != null &&
assemblyToUse != null)
{
rm =
new ResourceManager(
baseName,
assemblyToUse,
usingResourceSet);
}
else if (usingResourceSet != null &&
baseName == null &&
assemblyToUse == null)
{
rm = new ResourceManager(usingResourceSet);
}
else if (usingResourceSet == null &&
baseName != null &&
assemblyToUse != null)
{
rm = new ResourceManager(baseName, assemblyToUse);
}
else
{
throw new ArgumentException("assemblyToUse cannot be null", "assemblyToUse");
}
return rm;
}
where baseName is resources, assemblyToUse is Assembly.GetCallingAssembly().
The default strings are present in a text file named resources.restext. I wish to translate a few strings to Swedish and I added resources.sv-se.restext and made the translations. When I built the project, Satellite assembles were created in the bin folder inside a folder named sv-se. But the strings are still taken from the default resource file. I modified the default file and the changes are reflected immediately.
I tried loading the dll manually and the manifest names consisted of a name Microsoft.Health.ItemTypes.resources.sv-se.resources. I initialized the ResourceManager with that name and the same assembly.
var rm = new ResourceManager("Microsoft.Health.ItemTypes.resources.sv-se.resources", assembly);
rm.GetString("Key"); // Causes MissingManifestResourceException
However, I tried and was able to get the key by using the following
var rm = new ResourceManager("Microsoft.Health.ItemTypes.resources.sv-se", assembly); // manifest name - trailing resources
rm.GetString("Key"); // works!
My question is this:
What is the correct way to use ResourceManger? Should the satellite assembly be passed to the RM constructor? and how must be the resource files named, so that I do not have to edit the manifest name to create the resource manager instance?
Solved.
In the .csproj for the project, the logical name of the resource was changed.
Changing the csproj to following solved my issues
<ItemGroup>
<EmbeddedResource Include="resources.restext">
<LogicalName>resources.resources</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="resources.sv-se.restext">
<LogicalName>resources.sv-se.resources</LogicalName>
</EmbeddedResource>
</ItemGroup>
Related
I am unable to get Costura to load a Native dll that my project needs to run. This is a full native dll so it is not a reference in the project.
I have added the dll to the costura32 folder in my project and set it as an embedded resource.
When I run the project I can see that costura has extracted the dll to %temp%\costura\1D5629B8D94FC3E9B53C7AB358A0E123\32\native.dll
The project is still unable to find the file with the error Unable to load DLL
When looking in procmon I can see that it looks for the file in the local folder then in %temp%\costura\1D5629B8D94FC3E9B53C7AB358A0E123\native.dll and cannot find it. It doesn't seem to be looking for it in the "32" folder.
I have tried several options in the config file Unmanaged32Assemblies, PreloadOrder but they all have the same result.
I cannot see what I am doing wrong here.
In my case I tried to access temp path for setting library path with below code and it worked.
private bool SetupSevenZipLibrary()
{
string costuraExtractionPath = null;
try
{
DirectoryInfo di = null;
string costuraTempPath = Path.Combine(
Path.GetTempPath(),
"Costura" //ex: Costura
);
di = new DirectoryInfo(costuraTempPath);
if (!di.Exists)
return false;
costuraExtractionPath = di.GetDirectories().First().FullName;
if (!Directory.Exists(costuraExtractionPath))
throw new Exception();
string sevenZipPath = Path.Combine(
costuraExtractionPath,
Environment.Is64BitProcess ? "64" : "32", "7z.dll"
);
if (!File.Exists(sevenZipPath))
throw new Exception();
SevenZipBase.SetLibraryPath(sevenZipPath);
return true;
}
catch { return false; }
}
why always get null get resource embedded file in my project 'Kriptografi'. My folder is sfx. I tried file in build action 'embedded resource'. Anyone can resolve it ?
Thanks
void test()
{
var ConfigXml = "Kriptografi.sfx.Config.xml";
Stream cfg = Assembly.GetExecutingAssembly().GetManifestResourceStream(ConfigXml);
if (cfg == null)
{
MessageBox.Show("Nothing");
}
else
{
MessageBox.Show("Exist");
}
}
I have a Resource project I use for various parts of our products. To make it more flexible I decided to place the .resx externally from the dll processed with the resgen tool, to allow users to add their own language files on the fly. Since the project will be accessed from various places, web, service or stand-alone winForm, how can I get the path of where the .dll is located so that I can supply the correct path for
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
temp = ResourceManager.CreateFileBasedResourceManager("Resources", cwd, null);
resourceMan = temp;
}
return resourceMan;
}
}
I can hardcode the path and it works great, though I would rather have it figure out the path at runtime.
I tried something like this, however it did not work
string fullPath = System.Reflection.Assembly.GetAssembly(typeof(Resources)).Location;
//get the folder that's in
string theDirectory = Path.GetDirectoryName(fullPath); ResourceManager temp =
"Could not find any resources appropriate for the specified culture (or the neutral culture) on disk.
baseName: Resources locationInfo: fileName: Resources.resources"
Found the following to work from
How do I get the path of the assembly the code is in?
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
var path = Uri.UnescapeDataString(uri.Path);
var theDirectory = Path.GetDirectoryName(path);
I have a simple Windows Forms (C#, .NET 2.0) application, built with Visual Studio 2008.
I would like to support multiple UI languages, and using the "Localizable" property of the form, and culture-specific .resx files, the localization aspect works seamlessly and easily. Visual Studio automatically compiles the culture-specific resx files into satellite assemblies, so in my compiled application folder there are culture-specific subfolders containing these satellite assemblies.
I would like to have the application be deployed (copied into place) as a single assembly, and yet retain the ability to contain multiple sets of culture-specific resources.
Using ILMerge (or ILRepack), I can merge the satellite assemblies into the main executable assembly, but the standard .NET ResourceManager fallback mechanisms do not find the culture-specific resources that were compiled into the main assembly.
Interestingly, if I take my merged (executable) assembly and place copies of it into the culture-specific subfolders, then everything works! Similarly, I can see the main and culture-specific resources in the merged assemby when I use Reflector (or ILSpy). But copying the main assembly into culture-specific subfolders defeats the purpose of the merging anyway - I really need there to be just a single copy of the single assembly...
I'm wondering whether there is any way to hijack or influence the ResourceManager fallback mechanisms to look for the culture-specific resources in the same assembly rather than in the GAC and culture-named subfolders. I see the fallback mechanism described in the following articles, but no clue as to how it would be modified: BCL Team Blog Article on ResourceManager.
Does anyone have any idea? This seems to be a relatively frequent question online (for example, another question here on Stack Overflow: "ILMerge and localized resource assemblies"), but I have not found any authoritative answer anywhere.
UPDATE 1: Basic Solution
Following casperOne's recommendation below, I was finally able to make this work.
I'm putting the solution code here in the question because casperOne provided the only answer, I don't want to add my own.
I was able to get it to work by pulling the guts out of the Framework resource-finding fallback mechanisms implemented in the "InternalGetResourceSet" method and making our same-assembly search the first mechanism used. If the resource is not found in the current assembly, then we call the base method to initiate the default search mechanisms (thanks to #Wouter's comment below).
To do this, I derived the "ComponentResourceManager" class, and overrode just one method (and re-implemented a private framework method):
class SingleAssemblyComponentResourceManager :
System.ComponentModel.ComponentResourceManager
{
private Type _contextTypeInfo;
private CultureInfo _neutralResourcesCulture;
public SingleAssemblyComponentResourceManager(Type t)
: base(t)
{
_contextTypeInfo = t;
}
protected override ResourceSet InternalGetResourceSet(CultureInfo culture,
bool createIfNotExists, bool tryParents)
{
ResourceSet rs = (ResourceSet)this.ResourceSets[culture];
if (rs == null)
{
Stream store = null;
string resourceFileName = null;
//lazy-load default language (without caring about duplicate assignment in race conditions, no harm done);
if (this._neutralResourcesCulture == null)
{
this._neutralResourcesCulture =
GetNeutralResourcesLanguage(this.MainAssembly);
}
// if we're asking for the default language, then ask for the
// invariant (non-specific) resources.
if (_neutralResourcesCulture.Equals(culture))
culture = CultureInfo.InvariantCulture;
resourceFileName = GetResourceFileName(culture);
store = this.MainAssembly.GetManifestResourceStream(
this._contextTypeInfo, resourceFileName);
//If we found the appropriate resources in the local assembly
if (store != null)
{
rs = new ResourceSet(store);
//save for later.
AddResourceSet(this.ResourceSets, culture, ref rs);
}
else
{
rs = base.InternalGetResourceSet(culture, createIfNotExists, tryParents);
}
}
return rs;
}
//private method in framework, had to be re-specified here.
private static void AddResourceSet(Hashtable localResourceSets,
CultureInfo culture, ref ResourceSet rs)
{
lock (localResourceSets)
{
ResourceSet objA = (ResourceSet)localResourceSets[culture];
if (objA != null)
{
if (!object.Equals(objA, rs))
{
rs.Dispose();
rs = objA;
}
}
else
{
localResourceSets.Add(culture, rs);
}
}
}
}
To actually use this class, you need to replace the System.ComponentModel.ComponentResourceManager in the "XXX.Designer.cs" files created by Visual Studio - and you will need to do this every time you change the designed form - Visual Studio replaces that code automatically. (The problem was discussed in "Customize Windows Forms Designer to use MyResourceManager", I did not find a more elegant solution - I use fart.exe in a pre-build step to auto-replace.)
UPDATE 2: Another Practical Consideration - more than 2 languages
At the time I reported the solution above, I was actually only supporting two languages, and ILMerge was doing a fine job of merging my satellite assembly into the final merged assembly.
Recently I started working on a similar project where there are multiple secondary languages, and therefore multiple satellite assemblies, and ILMerge was doing something very strange: Instead of merging the multiple satellite assemblies I had requested, it was merging the first satellite assembly in multiple times!
eg command-line:
"c:\Program Files\Microsoft\ILMerge\ILMerge.exe" /t:exe /out:%1SomeFinalProg.exe %1InputProg.exe %1es\InputProg.resources.dll %1fr\InputProg.resources.dll
With that command-line, I was getting the following sets of resources in the merged assembly (observed with ILSpy decompiler):
InputProg.resources
InputProg.es.resources
InputProg.es.resources <-- Duplicated!
After some playing around, I ended up realizing this is just a bug in ILMerge when it encounters multiple files with the same name in a single command-line call. The solution is simply to merge each satellite assembly in a different command-line call:
"c:\Program Files\Microsoft\ILMerge\ILMerge.exe" /t:exe /out:%1TempProg.exe %1InputProg.exe %1es\InputProg.resources.dll
"c:\Program Files\Microsoft\ILMerge\ILMerge.exe" /t:exe /out:%1SomeFinalProg.exe %1TempProg.exe %1fr\InputProg.resources.dll
When I do this, the resulting resources in the final assembly are correct:
InputProg.resources
InputProg.es.resources
InputProg.fr.resources
So finally, in case this helps clarify, here's a complete post-build batch file:
"%ProgramFiles%\Microsoft\ILMerge\ILMerge.exe" /t:exe /out:%1TempProg.exe %1InputProg.exe %1es\InputProg.resources.dll
IF %ERRORLEVEL% NEQ 0 GOTO END
"%ProgramFiles%\Microsoft\ILMerge\ILMerge.exe" /t:exe /out:%1SomeFinalProg.exe %1TempProg.exe %1fr\InputProg.resources.dll
IF %ERRORLEVEL% NEQ 0 GOTO END
del %1InputProg.exe
del %1InputProg.pdb
del %1TempProg.exe
del %1TempProg.pdb
del %1es\*.* /Q
del %1fr\*.* /Q
:END
UPDATE 3: ILRepack
Another quick note - One of the things that bothered me with ILMerge was that it is an additional proprietary Microsoft tool, not installed by default with Visual Studio, and therefore an extra dependency that makes it that little bit harder for a third party to get started with my open-source projects.
I recently discovered ILRepack, an open-source (Apache 2.0) equivalent that so far works just as well for me (drop-in replacement), and can be freely distributed with your project sources.
I hope this helps someone out there!
The only way I can see this working is by creating a class that derives from ResourceManager and then overriding the InternalGetResourceSet and GetResourceFileName methods. From there, you should be able to override where resources are obtained, given a CultureInfo instance.
A different approach:
1) add your resource.DLLs as embededed resources in your project.
2) add an event handler for AppDomain.CurrentDomain.ResourceResolve
This handler will fire when a resource cannot be found.
internal static System.Reflection.Assembly CurrentDomain_ResourceResolve(object sender, ResolveEventArgs args)
{
try
{
if (args.Name.StartsWith("your.resource.namespace"))
{
return LoadResourcesAssyFromResource(System.Threading.Thread.CurrentThread.CurrentUICulture, "name of your the resource that contains dll");
}
return null;
}
catch (Exception ex)
{
return null;
}
}
3) Now you have to implement LoadResourceAssyFromResource something like
private Assembly LoadResourceAssyFromResource( Culture culture, ResourceName resName)
{
//var x = Assembly.GetExecutingAssembly().GetManifestResourceNames();
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resName))
{
if (stream == null)
{
//throw new Exception("Could not find resource: " + resourceName);
return null;
}
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
var ass = Assembly.Load(assemblyData);
return ass;
}
}
Posted as answer since comments didn't provide enough space:
I couldn't find resources for neutral cultures (en instead of en-US) with the OPs solution. So I extended InternalGetResourceSet with a lookup for neutral cultures which did the job for me. With this you can now also locate resources which do not define the region. This is actually the same behaviour that the normal resourceformatter will show when not ILMerging the resource files.
//Try looking for the neutral culture if the specific culture was not found
if (store == null && !culture.IsNeutralCulture)
{
resourceFileName = GetResourceFileName(culture.Parent);
store = this.MainAssembly.GetManifestResourceStream(
this._contextTypeInfo, resourceFileName);
}
This results in the following code for the SingleAssemblyComponentResourceManager
class SingleAssemblyComponentResourceManager :
System.ComponentModel.ComponentResourceManager
{
private Type _contextTypeInfo;
private CultureInfo _neutralResourcesCulture;
public SingleAssemblyComponentResourceManager(Type t)
: base(t)
{
_contextTypeInfo = t;
}
protected override ResourceSet InternalGetResourceSet(CultureInfo culture,
bool createIfNotExists, bool tryParents)
{
ResourceSet rs = (ResourceSet)this.ResourceSets[culture];
if (rs == null)
{
Stream store = null;
string resourceFileName = null;
//lazy-load default language (without caring about duplicate assignment in race conditions, no harm done);
if (this._neutralResourcesCulture == null)
{
this._neutralResourcesCulture =
GetNeutralResourcesLanguage(this.MainAssembly);
}
// if we're asking for the default language, then ask for the
// invariant (non-specific) resources.
if (_neutralResourcesCulture.Equals(culture))
culture = CultureInfo.InvariantCulture;
resourceFileName = GetResourceFileName(culture);
store = this.MainAssembly.GetManifestResourceStream(
this._contextTypeInfo, resourceFileName);
//Try looking for the neutral culture if the specific culture was not found
if (store == null && !culture.IsNeutralCulture)
{
resourceFileName = GetResourceFileName(culture.Parent);
store = this.MainAssembly.GetManifestResourceStream(
this._contextTypeInfo, resourceFileName);
}
//If we found the appropriate resources in the local assembly
if (store != null)
{
rs = new ResourceSet(store);
//save for later.
AddResourceSet(this.ResourceSets, culture, ref rs);
}
else
{
rs = base.InternalGetResourceSet(culture, createIfNotExists, tryParents);
}
}
return rs;
}
//private method in framework, had to be re-specified here.
private static void AddResourceSet(Hashtable localResourceSets,
CultureInfo culture, ref ResourceSet rs)
{
lock (localResourceSets)
{
ResourceSet objA = (ResourceSet)localResourceSets[culture];
if (objA != null)
{
if (!object.Equals(objA, rs))
{
rs.Dispose();
rs = objA;
}
}
else
{
localResourceSets.Add(culture, rs);
}
}
}
}
I have a suggestion for part of your problem. Specifically, a solution to the step of updating .Designer.cs files to replace ComponentResourceManager with SingleAssemblyComponentResourceManager.
Move the InitializeComponent() method out of .Designer.cs and into the implementation file (include the #region). Visual Studio will continue to auto generate that section, with no problems as far as I can tell.
Use a C# alias at the top of the implementation file so that ComponentResourceManager is aliased to SingleAssemblyComponentResourceManager.
Unfortunately, I didn't get to test this fully. We found a different solution to our problem and so moved on. I hope it helps you though.
Just a thought.
You did the step and created your SingleAssemblyComponentResourceManager
So why do you take the pain to include your satellite assemblies in the ilmerged Assembly?
You could add the ResourceName.es.resx itself as a binary file to another resource in your project.
Than you could rewrite your code
store = this.MainAssembly.GetManifestResourceStream(
this._contextTypeInfo, resourceFileName);
//If we found the appropriate resources in the local assembly
if (store != null)
{
rs = new ResourceSet(store);
with this code (not tested but should work)
// we expect the "main" resource file to have a binary resource
// with name of the local (linked at compile time of course)
// which points to the localized resource
var content = Properties.Resources.ResourceManager.GetObject("es");
if (content != null)
{
using (var stream = new MemoryStream(content))
using (var reader = new ResourceReader(stream))
{
rs = new ResourceSet(reader);
}
}
This should render the effort to include the sattelite assembiles in the ilmerge process obsolete.
How to read the string from .resx file in c#? please send me guidelines . step by step
ResourceManager shouldn't be needed unless you're loading from an external resource.
For most things, say you've created a project (DLL, WinForms, whatever) you just use the project namespace, "Resources" and the resource identifier. eg:
Assuming a project namespace: UberSoft.WidgetPro
And your resx contains:
You can just use:
Ubersoft.WidgetPro.Properties.Resources.RESPONSE_SEARCH_WILFRED
This example is from the MSDN page on ResourceManager.GetString():
// Create a resource manager to retrieve resources.
ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly());
// Retrieve the value of the string resource named "welcome".
// The resource manager will retrieve the value of the
// localized resource using the caller's current culture setting.
String str = rm.GetString("welcome");
Try this, works for me.. simple
Assume that your resource file name is "TestResource.resx", and you want to pass key dynamically then,
string resVal = TestResource.ResourceManager.GetString(dynamicKeyVal);
Add Namespace
using System.Resources;
Open .resx file and set "Access Modifier" to Public.
var <Variable Name> = Properties.Resources.<Resource Name>
Assuming the .resx file was added using Visual Studio under the project properties, there is an easier and less error prone way to access the string.
Expanding the .resx file in the Solution Explorer should show a .Designer.cs file.
When opened, the .Designer.cs file has a Properties namespace and an internal class. For this example assume the class is named Resources.
Accessing the string is then as easy as:
var resourceManager = JoshCodes.Core.Testing.Unit.Properties.Resources.ResourceManager;
var exampleXmlString = resourceManager.GetString("exampleXml");
Replace JoshCodes.Core.Testing.Unit with the project's default namespace.
Replace "exampleXml" with the name of your string resource.
Followed by #JeffH answer, I recommend to use typeof() than string assembly name.
var rm = new ResourceManager(typeof(YourAssembly.Properties.Resources));
string message = rm.GetString("NameOfKey", CultureInfo.CreateSpecificCulture("ja-JP"));
If for some reason you can't put your resources files in App_GlobalResources, then you can open resources files directly using ResXResourceReader or an XML Reader.
Here's sample code for using the ResXResourceReader:
public static string GetResourceString(string ResourceName, string strKey)
{
//Figure out the path to where your resource files are located.
//In this example, I'm figuring out the path to where a SharePoint feature directory is relative to a custom SharePoint layouts subdirectory.
string currentDirectory = Path.GetDirectoryName(HttpContext.Current.Server.MapPath(HttpContext.Current.Request.ServerVariables["SCRIPT_NAME"]));
string featureDirectory = Path.GetFullPath(currentDirectory + "\\..\\..\\..\\FEATURES\\FEATURENAME\\Resources");
//Look for files containing the name
List<string> resourceFileNameList = new List<string>();
DirectoryInfo resourceDir = new DirectoryInfo(featureDirectory);
var resourceFiles = resourceDir.GetFiles();
foreach (FileInfo fi in resourceFiles)
{
if (fi.Name.Length > ResourceName.Length+1 && fi.Name.ToLower().Substring(0,ResourceName.Length + 1) == ResourceName.ToLower()+".")
{
resourceFileNameList.Add(fi.Name);
}
}
if (resourceFileNameList.Count <= 0)
{ return ""; }
//Get the current culture
string strCulture = CultureInfo.CurrentCulture.Name;
string[] cultureStrings = strCulture.Split('-');
string strLanguageString = cultureStrings[0];
string strResourceFileName="";
string strDefaultFileName = resourceFileNameList[0];
foreach (string resFileName in resourceFileNameList)
{
if (resFileName.ToLower() == ResourceName.ToLower() + ".resx")
{
strDefaultFileName = resFileName;
}
if (resFileName.ToLower() == ResourceName.ToLower() + "."+strCulture.ToLower() + ".resx")
{
strResourceFileName = resFileName;
break;
}
else if (resFileName.ToLower() == ResourceName.ToLower() + "." + strLanguageString.ToLower() + ".resx")
{
strResourceFileName = resFileName;
break;
}
}
if (strResourceFileName == "")
{
strResourceFileName = strDefaultFileName;
}
//Use resx resource reader to read the file in.
//https://msdn.microsoft.com/en-us/library/system.resources.resxresourcereader.aspx
ResXResourceReader rsxr = new ResXResourceReader(featureDirectory + "\\"+ strResourceFileName);
//IDictionaryEnumerator idenumerator = rsxr.GetEnumerator();
foreach (DictionaryEntry d in rsxr)
{
if (d.Key.ToString().ToLower() == strKey.ToLower())
{
return d.Value.ToString();
}
}
return "";
}
I added the .resx file via Visual Studio. This created a designer.cs file with properties to immediately return the value of any key I wanted. For example, this is some auto-generated code from the designer file.
/// <summary>
/// Looks up a localized string similar to When creating a Commissioning change request, you must select valid Assignees, a Type, a Component, and at least one (1) affected unit..
/// </summary>
public static string MyErrorMessage {
get {
return ResourceManager.GetString("MyErrorMessage", resourceCulture);
}
}
That way, I was able to simply do:
string message = Errors.MyErrorMessage;
Where Errors is the Errors.resx file created through Visual Studio and MyErrorMessage is the key.
Once you add a resource (Name: ResourceName and Value: ResourceValue) to the solution/assembly, you could simply use "Properties.Resources.ResourceName" to get the required resource.
I added my resource file to my project directly, and so I was able to access the strings inside just fine with the resx file name.
Example: in Resource1.resx, key "resourceKey" -> string "dataString".
To get the string "dataString", I just put Resource1.resourceKey.
There may be reasons not to do this that I don't know about, but it worked for me.
The easiest way to do this is:
Create an App_GlobalResources system folder and add a resource file to it e.g. Messages.resx
Create your entries in the resource file e.g. ErrorMsg = This is an error.
Then to access that entry: string errormsg = Resources.Messages.ErrorMsg
The Simplest Way to get value from resource file.
Add Resource file in the project.
Now get the string where you want to add like in my case it was text block(SilverLight).
No need to add any namespace also.Its working fine in my case
txtStatus.Text = Constants.RefractionUpdateMessage;
Constants is my resource file name in the project.
Create a resource manager to retrieve resources.
ResourceManager rm = new ResourceManager("param1",Assembly.GetExecutingAssembly());
String str = rm.GetString("param2");
param1 = "AssemblyName.ResourceFolderName.ResourceFileName"
param2 = name of the string to be retrieved from the resource file
This works for me.
say you have a strings.resx file with string ok in it. to read it
String varOk = My.Resources.strings.ok
ResourceFileName.ResourceManager.GetString(ResourceFileName.Name)
2.return Resource.ResponseMsgSuccess;