I'm decompiling some .NET code for diagnosing an issue but the object is very large. To that end, I've been trying to see where .NET would raise the error I'm looking for by resource string as the exception type is fairly generic but the error message is specific to ultimate issue I'm looking into.
Decompiling the code, I see that it uses a string resource manager to pull out the text but without being able to match the resource key to the text, I cannot trace from the error message to the point in decompiled code.
E.g., exceptions are generated like the following in the decompiled code:
throw new ArgumentOutOfRangeException("value", SR.GetString("net_io_timeout_use_ge_zero"));
Where would I find the .NET's localized error text and associated resource key (e.g. "net_io_timeout_use_ge_zero")?
I've tried using ResHacker on System.dll and System.Net.dll (the assembly with the object I'm investigating) but both of these yield nothing. Likewise, while there's a culture subfolder of en-US under %windir%\Microsoft.NET\Framework\v4.0.30319 and the 64 equivalent but these don't show any text bar the assembly details and some icons in the System.dll
This is really PetSerAl's answer (if he posts one, I'll mark it as such) but to find the resource strings you can use ILSpy to load up the assembly and the resources can be found on the Resources node like so;
Going further, while ILSpy does list the resources, it doesn't provide a direct way to search for them. Saving saves out the compiled details which are not easily readable (there's a github request for this). In the meantime, you can select the contents the grid by selecting a single item, CTRL+A to select all, CTRL+C to copy the grid to the clipboard. From there you can paste into the likes of Excel or Notepad and search for the text you need.
Related
I'm working on a C# application, trying to use Excel features. In order to do that, I'm working with Interop as a library. I have an exception in following line of source code:
Range rng_Destination =
xlApp.get_Range(xlWrkSht.Cells[2,1],
xlWrkSht.Cells[xlWrkSht.Cells[1,1].CurrentArray.Rows.Count+1,
dt_main.Columns.Count]);
In order to investigate this, I've tried to add xlWrkSht.Cells[2,1] to Visual Studio's Watch window, but this just shows {System.__ComObject}, which is not very useful.
So, I tried another approach, using this kind of source code:
System.Diagnostics.Debug.WriteLine("xlWrkSht.Cells[2 ,1]: [%s]",
xlWrkSht.Cells[2, 1]);
This, however, causes following Exception:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
HResult=0x80131500
Message=Cannot dynamically invoke method 'WriteLine' because it has
a Conditional attribute
Source=<Cannot evaluate the exception source>
StackTrace:<Cannot evaluate the exception stack trace>
So my question is very simple: how can I debug Interop related objects, like the mentioned xlWrkSht.Cells[2, 1]?
For your information: I already tried unchecking "Just my code" but this did not help until now (I found this somewhere on the internet, I have no idea what it does):
I've been looking for other resources about Interop debugging, but the information was far too general to be useful for my specific case.
I've also seen some posts on the internet, informing about the event viewer but there, I just have some "Information" and at most some "Warning" messages, no "Error" ones (I've been looking in "Windows Logs, Application/Security and System".
Edit after some more investigation
Meanwhile I've seen that I can find the value of that cell, using:
xlWrkSht.Cells[2, 1]
=> Dynamic View
FormulaLocal
That last attribute contains the value.
However, the following issue is that I'll need to get the Excel array this cell belongs to:
xlWrkSht.Cells[2, 1].CurrentArray.
This one seems not to be accessible, even not using "Dynamic view". Any ideas?
I am writing a plugin in C#, in which I have a user control with a linklabel on it that controls a form that shows up like a tooltip and a picturebox next to the label to show the status whether or not the form is visible or hidden.
I have two images that are added as resources by the book via the Visual Studio PludingResources Designer. (I tried setting the Persistence of the images both to Linked at compile time and to embedded to solve the problem.)
The rubber meets the road in the following code:
pictureBox1.Image = SubAsst.PluginResources.SubAsst_Enabled1;
When the code execution hits this line to display the image, I get the
System.Resources.MissingManifestResourceException exception. The exception reads:
"Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "SubAsst.PluginResources.resources" was correctly embedded or linked into assembly "SubtitlingAssistant" at compile time, or that all the satellite assemblies required are loadable and fully signed."
I looked all over on msdn and everywhere else I could but I could not find a solution yet. Except, if I change the code to use the built-in system icons, that works:
pictureBox1.Image = System.Drawing.SystemIcons.Information.ToBitmap();
So that is my workaround so far. However I would like to use my custom images for the plugin.
I suspect that the API does not allow image resources to be used, but this is not documented. I guess this from the fact that an icon can be imported and is displayed on the default button for the plugin.
I would appreciate any advice on this.
Looks like some resource file is missing, check these
MSDN links
You may receive a "System.Resources.MissingManifestResourceException" error message when you access the .resources file of the form at run time
A System.Resources.MissingManifestResourceException exception occurs when you try to access a localized resource
C#: What does MissingManifestResourceException mean and how to fix it?
Here is the solution:
What was missing is the CustomToolNamespace in the properties box:
Build action: Embedded Resource
Copy to Output Directory: Do not copy
Custom Tool: ResXFileCodeGenerator
Custom Tool Namespace: [myapplicationnamespace]
The namespace matches the NameSpace of my application. As soon as I set this and rebuilt the application, the error was gone and the image displayed.
Thanks for the link in Meysam Tolouee's answer, which lead to this "off-topic" answer. Here it is definitely not off-topic, and I wish I found this earlier.
What a great tool this StackOwerflow is!
We meet one issue for loading Mac resource with Xamarin. We have one resource
file named Resource1.resx. It failed when loading one string from this resource
file with below code. Please refer attachment sample to create this issue.
Could you please give some advice to load resource?
If you need any more information, please let me know that. Please check the
codes(in MainWindows.cs) as follow:
partial void loadResourceButtonClicked(MonoMac.Foundation.NSObject sender){
try{
var b = Resources1.ResourceManager;
var name = b.GetString("Name1");
resultLabel.StringValue = name;
}
catch {
resultLabel.StringValue = "Resource load failed.";
}
}
PS.We have attached the test project, please have a check.
Thanks.
Your 'hidden' exception:
Could not find any resources appropriate for the specified culture or
the neutral culture. Make sure
"MacResourceTest.Resources1.resources" was correctly
embedded or linked into assembly "MacResourceTest" at compile time, or
that all the satellite assemblies required are loadable and fully
signed.
The key phase in that exception message is 'Make sure XXXX was correctly embedded or linked into assembly'.
A quick look at your project and the .resx file is flagged incorrectly as a Build Action of BundleResource. OSX/iOS BundleResource's are typically used for binary, xml, text, etc.. but NOT .resx files as they originate via the System.Resources.ResourceManager and need to be added to the CIL assembly in a specific way (mainly due to culture localization).
1) Flag .resx files as a Build Action of EmbeddedResource
2) If your going to 'hide' exceptions and provide a 'user friendly' message, include the actual exception messages in Console debugging messaging, logging, somewhere, etc...
3) In posting questions to StackOverflow, please post the actual exception message / call stack.
I've working on a project where I'm using ResourceManager extensively and this question just crossed my mind.
Can we read from .resx files without using ResourceManager? I mean, is there another way?
ResourceManager is a convenience class, it works very well with the way the build system supports .resx files. No, it is not a strict necessity.
A .NET assembly has the generic capability of embedding arbitrary data into the manifest of the assembly. Just a blob of bytes, it can be anything you want. Directly supported by the build system as well, just add a file to your project and set its Build Action to "Embedded Resource". At runtime, you retrieve the data in that file with Assembly.GetManifestResourceStream().
You can stop right there, but that's just a single file, it doesn't scale very well if you have many small resources you want to embed. Which is where a .resx file starts, it is an XML file that contains resources in a friendly format. One that gives you a fighting chance to recover the source again when the original got lost.
But an XML format is not a very good format for resource data, it is bulky and it is expensive to find data back. So .NET has resgen.exe, a build tool that turns the XML file into a binary file, a .resources file. Compact and easy to find stuff back. And fit to be embedded directly as a single manifest resource.
What you don't want to do is having to read the .resources data yourself. You'll want to use a helper class that can find specific resources back from the blob of bytes. You want use the ResourceReader class, its GetResourceData() lets you specify the resource name and it will spit the resource type and data back out.
You can stop right there, but an app often has a need for different sets of resources. A very common localization need. Which is what satellite assemblies are all about, different assemblies that contain nothing but resources, each for a specific culture. They are separate so you don't pay for the virtual memory that's required to store all the localized resources when you need only one set of them. What's needed here is a helper class that automatically locates and loads the correct satellite assembly and retrieves the resource for you, based on the current culture.
That helper class is ResourceManager.
If you choose to skip the use of the ResourceManager you can let Visual Studio handle code generation for you. Ultimately the generated code uses a ResourceManager, but you're no longer writing that code manually. Additionally, you get compile-time checking since you're referencing a generated static class.
If you add a resource file to your project and double click it from the Solution Explorer, Visual Studio presents you with a dialog where you can enter a name for a resource, and its value. The dialog presents you with options to add resources as strings, images, audio, etc. (look at the dropdowns at the top of the dialog). Next, to get the code generation bit, you need to set the Access Modifier to either "Public" or "Internal". The third option is "No code generation."
For example, add a resource file called "MyResources", then add a string resource with the name Greeting and a value of Hello! With one of the former two options selected for code generation (start off with public to test it, restrict the access as needed), you should now be able to reference the resources from your code via MyResources.Greeting. If you don't see it right away, make sure you've saved the file and try compiling.
string greeting = MyResources.Greeting; // "Hello!"
If you add other resource types (image, audio, etc.) then the return types will differ, of course.
At this point you could inspect the generated .cs file and see that the generated code is using a ResourceManager. The other use for resource files is localization. Let's say you wanted a Spanish version of MyResources. You would add a new file called MyResources.es.resx, where es corresponds to the language code desired (Spanish in this case). Now add the same resource name of Greeting with a Spanish value of Hola!.
If you change the thread culture to Spanish, referencing the resource will now return the Spanish version:
string defaultGreeting = MyResources.Greeting; // "Hello!"
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
string spanishGreeting = MyResources.Greeting; // "Hola!"
Note that you only really need to set the access modifier to one of the code generation options for your default resource file (i.e., MyResources.resx), not for all the other localized versions you add. There's no harm in doing so, but in my opinion it's cleaner to have the main file generated while the others just have the resource values desired without code generation.
Well, Resources are compiled into the assembly. You could try to read the assembly by reading the bytes (or the IL), and extract the resources from there.
ResourceManager does this all for you, so I could not think of any reason you want to do this... Maybe one, if you don't want to load the assembly in memory, you could do it without ResourceManager.
Ref Microsoft: Represents a resource manager that provides convenient access to culture-specific resources at run time.
I expect, I'd you use multi Lang, you will get a more consistent result and better compatibility.
IMHO
I use a *.resx file for the localization purpose. The Name - it's a phrase or word in English. The Value - the translation to another language of that phrase. I choose this approach to have a one localization file for the whole application. And anyone who have this file can make translation by themselves.
But in the Visual Studio 2010 resx editor, each record with name which have spaces in it, have a warning: "The resource name is not a valid identifier."
Though it compiles and works, but please tell me if I am doing something wrong here.
First of all, the idea of the resx files is to have a separate resource file for each culture. You can provide the new translation by creating a new file with different values for the same keys.
For example, you can create Forms.en-GB.resx, Forms.pl-PL.resx, Forms.de-DE.resx and the appropriate file will be picked up based on the current UI culture without you having to do anything (except ensuring relevant culture is set).
Visual Studio will generate a resource class that contains all your key/value pairs from resource file as properties - that makes it easier to use in code. The warning you get means that the keys you've provided in resource file are not a valid identifiers (they contain spaces). You might want to use _ instead of space in the keys.
If you don't want to use the generated class you can ignore this warning - your resx files are fine and can be used directly. You can remove ResXFileCodeGenerator from 'Custom Tool' property of your resx file (properties windows) or set 'Access Modifier' to 'No code generation' in resx file editor if you do not need to generate a class, but you will still get the warning.
The strength of localization with resx files is that the culture on your computer decides what language your application should be in. If you keep to one resx file, according to me, you ignore it's power. Instead, try making a resx file for each language you want to integrate. for example: the default language is english, then you have a default page localization.resx where you only keep english sentences. Say you need a French translation, make another resx file called localization.fr-FR.resx. So users who have the fr-FR culture enabled on there computer will have that language on the program without any code specific work. If someone with a culture not integrated in your application starts the program, it will look for it, and if it doesn't find it, it chooses the default, ie english, one.
So to my opinion, don't use 1 resx file for different languages, but use the powers given in the framework.
I suppose it works, but it's not really the strategy you are supposed to follow.
Take a look here; the basic idea is that you take advantage of the controls in .NET to automatically get the correct localisation themselves, so you kind of don't need to worry about doing the translating.
Though, I don't use this all the time, and I do somewhat do as you do, but I tend to use an identifier, so I may have:
UserWelcome Hey, {name}, thanks for dropping by ...
And then I'll translate that. It's helpful because it allows generality in the languages (say, for example, some languages should be greeted formally, and others not, you don't want to be contrained by a direct translation of, "You", say).
Hope this is clear.
If what you've got works, then I suppose that's something, but it's not the "general" way of doing it.