Issue with the Resource File Conversion - c#

Here is the requirement:
Migrate the project resource file from one version to another version using Resourcefile converter utility.(ConvertResx)
I have created a simple windows application project. Set the localization property in the design time. In the .resx file localizable property entry has been set with 'MetaData' attribute. During the resource file conversion it convert all the entries in .resx file,but the localizable property attribute set with 'Data' attribute instead of 'Metadata' attribute.
UseResxDataNodes' class placed both the data and metadata attribute entries in the same collection.
ResXResourceReader reader = new ResXResourceReader(path0);
reader.UseResXDataNodes = true;
In order to retrieve the metadata collection entries, i have used the below code
iDictionaryEnumerator7 = reader.GetMetadataEnumerator();
But unable to read the metadata properties (localizable) with 'Metadata' attribute tag. it has been set with 'Data' tag in the resx file after resource file conversion.
Could you please help me on this issue, how to read the metadata attributes (design-time property attributes from the .resx file and migrate the referred assemblies to the latest version and write it into the .resx file ) how to migrate the metadata attribute entries in the .resx files.
Regards,
Sivaguru s

I encountered the same problem trying to write out a resource file to the same format as the original. After some searching and trial/error, I came up with the following solution to properly write out the metadata nodes.
ResXResourceReader readerData = new ResXResourceReader(new StringReader(sw.ToString()));
ResXResourceReader readerMetaData = new ResXResourceReader(new StringReader(sw.ToString()));
//Flag to read nodes as ResXDataNode, instead of key/value pairs, to preserve Comments.
readerData.UseResXDataNodes = true;
ResXResourceWriter writer = new ResXResourceWriter(this.FilePath);
foreach (DictionaryEntry resEntry in readerData)
{
ResXDataNode node = resEntry.Value as ResXDataNode;
if (node != null)
{
DictionaryEntry metaDataEntry;
//Check if node is metadata. The reader does not distinguish between
//data and metadata when UseResXDataNodes flags is set to true.
//http://connect.microsoft.com/VisualStudio/feedback/details/524508/resxresourcereader-does-not-split-data-and-metadata-entries-when-useresxdatanodes-is-true
if (IsMetaData(readerMetaData, resEntry, out metaDataEntry))
{
writer.AddMetadata(metaDataEntry.Key.ToString(), metaDataEntry.Value);
}
else
{
writer.AddResource(node);
}
}
}
writer.Generate(); //write to the file
writer.Close();
readerData.Close();
readerMetaData.Close();
/// <summary>
/// Check if resource data is metadata. If so, return the metadata node.
/// </summary>
/// <param name="metaDataReader"></param>
/// <param name="resEntry"></param>
/// <param name="metaData"></param>
/// <returns></returns>
private static bool IsMetaData(ResXResourceReader metaDataReader, DictionaryEntry resEntry, out DictionaryEntry metaData)
{
IDictionaryEnumerator metadataEnumerator = metaDataReader.GetMetadataEnumerator();
while (metadataEnumerator.MoveNext())
{
if (metadataEnumerator.Entry.Key.Equals(resEntry.Key))
{
metaData = metadataEnumerator.Entry;
return true;
}
}
return false;
}

Related

Accessing Images from resources.resx file not working with Image.FromFile method

I have an Image array, and I want to set an image in that array to be an image from Resources.resx file, I wrote this code here and gave me the exception that the image wasn't found.
string path = "PeanutToTheDungeon.Properties.Resources.ScaredMeter1"
imageArray[0] = Image.FromFile(path);
Does anyone know how to access local files using a path?
Also, the file does exist and it is named correctly too.
EmbeddedResources are not files, they are binary data encoded into the assembly itself. There are multiple ways to read them, the most common being to use the generated code from the resx (e.g., Resources.MyImageName).
The easiest way is just to do that. Find the .resx file in Visual Studio and look for the Resources.Designer.cs file. Inside that, you will find the generated property "ScaredMeter1", and it will likely be of type Bitmap (which derives from Image). To use it, you would have this code:
imageArray[0] = PeanutToTheDungeon.Properties.Resources.ScaredMeter1;
You can also create the image yourself like this:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
internal static class EmbeddedResourceHelper
{
/// <summary>
/// Creates a new <see cref="System.Drawing.Image"/> by reading a <see cref="Stream"/> from an embedded resource.
/// </summary>
/// <param name="assembly">Assembly containing the embedded resource.</param>
/// <param name="resourceName">Name of the resource.</param>
/// <returns>The created <see cref="Image"/>.</returns>
/// <exception cref="ArgumentNullException">One of the arguments was <c>null</c>.</exception>
/// <exception cref="KeyNotFoundException">A resource named <paramref name="resourceName"/> was not found in <paramref name="assembly"/>.</exception>
public static Image ReadEmbeddedResourceImage(Assembly assembly, string resourceName)
{
if (assembly is null)
{
throw new ArgumentNullException(nameof(assembly));
}
if (resourceName is null)
{
throw new ArgumentNullException(nameof(resourceName));
}
using Stream stream = assembly.GetManifestResourceStream(resourceName)
?? throw new KeyNotFoundException($"{resourceName} is not a valid resource in {assembly.FullName}");
var image = Image.FromStream(stream);
return image;
}
}

DotNetZip: Add Files to Dynamically Created Archive Directory

I can't imagine this is hard to do, but I haven't been able to get it to work. I have a files class that just stores the location, directory, and name of the files I want to zip. The files I'm zipping exist on disk so the FileLocation is the full path. ZipFileDirectory doesn't exist on disk. If I have two items in my files list,
{ FileLocation = "path/file1.doc", ZipFileDirectory = #"\", FileName = "CustomName1.doc" },
{ FileLocation = "path/file2.doc", ZipFileDirectory = #"\NewDirectory", FileName = "CustomName2.doc" }
I would expect to see MyCustomName1.doc in the root, and a folder named NewDirectory containing MyCustomName2.doc, but what happens is they both end up in the root using this code:
using (var zip = new Ionic.Zip.ZipFile())
{
foreach (var file in files)
{
zip.AddFile(file.FileLocation, file.ZipFileDirectory).FileName = file.FileName;
}
zip.Save(HttpContext.Current.Response.OutputStream);
}
If I use this:
zip.AddFiles(files.Select(o => o.FileLocation), false, "NewDirectory");
Then it creates the new directory and puts all of the files inside, as expected, but then I lose the ability to use the custom naming with this method, and it also introduces more complexities that the first method would handle perfectly.
Is there a way I can get the first method (AddFile()) to work as I expect?
On further inspection, since posting a comment a few minutes ago, I suspect that setting FileName is erasing the archive path.
Testing confirms this.
Setting the name to #"NewDirectory\CustomName2.doc" will fix the problem.
You can also use #"\NewDirectory\CustomName2.doc"
Not sure if this exactly suites your needs but thought I would share. It is a method that is part of a helper class that I created to make working with DotNetZip a bit easier for my dev team. The IOHelper class is another simple helper class that you can ignore.
/// <summary>
/// Create a zip file adding all of the specified files.
/// The files are added at the specified directory path in the zip file.
/// </summary>
/// <remarks>
/// If the zip file exists then the file will be added to it.
/// If the file already exists in the zip file an exception will be thrown.
/// </remarks>
/// <param name="filePaths">A collection of paths to files to be added to the zip.</param>
/// <param name="zipFilePath">The fully-qualified path of the zip file to be created.</param>
/// <param name="directoryPathInZip">The directory within the zip file where the file will be placed.
/// Ex. specifying "files\\docs" will add the file(s) to the files\docs directory in the zip file.</param>
/// <param name="deleteExisting">Delete the zip file if it already exists.</param>
public void CreateZipFile(ICollection<FileInfo> filePaths, string zipFilePath, string directoryPathInZip, bool deleteExisting)
{
if (deleteExisting)
{
IOHelper ioHelper = new IOHelper();
ioHelper.DeleteFile(zipFilePath);
}
using (ZipFile zip = new ZipFile(zipFilePath))
{
foreach (FileInfo filePath in filePaths)
{
zip.AddFile(filePath.FullName, directoryPathInZip);
}
zip.Save();
}
}

Get all strings from resourcemanager

I need to write a program, that reads all string resources from dll and insert them into some table. I have the method, that reads resources:
private static IEnumerable<KeyValuePair<string,string>> getAllResources(ResourceManager resourceManager,
Language language)
{
ResourceSet resourceSet = resourceManager.GetResourceSet(getCulture(language), true, true);
IDictionaryEnumerator dictNumerator = resourceSet.GetEnumerator();
// Get all string resources
while (dictNumerator.MoveNext())
{
// Only string resources
if (dictNumerator.Value is string)
{
var key = (string)dictNumerator.Key;
var value = (string)dictNumerator.Value;
yield return new KeyValuePair<string, string>(key, value);
}
}
}
But when I started using it, I noticed that it also reads the resources, that added like a file (reads file content)
How can I ignore resources that are added as a "file", and read only strings?
There is no way of doing that.
Have a look to the resource section of you assembly through Reflector, for instance. Your text file is saved as String. There is no difference between String value and Text File value.
Binary files, however, won't be a problem, as for binary file types you'll have byte[] as value and not string.

GetPrintCapabilities will not return all page sizes

PrintCapabilities printCapabilites = SelectedPrinter.GetPrintCapabilities();
IEnumerable pagesizeList = printCapabilites.PageMediaSizeCapability;
The above code does not list all the page sizes that the printer driver supports and this is my problem.
As an example if you use the Microsoft XPS printer driver you will find that pagesizeList (above) will be missing some page sizes. "Letter Small" is one of the missing page sizes (MS Word will successfully list this page size though).
As a quick check I dumped the Printer capabilities to xml as below:
long gpCLen = _selectedPrinter.GetPrintCapabilitiesAsXml().Length;
FileStream fs = File.OpenWrite(#"c:\test.txt");
MemoryStream ms = _selectedPrinter.GetPrintCapabilitiesAsXml();
byte[] b = new byte[gpCLen];
ms.Read(b, 0, (int)gpCLen);
fs.Write(b, 0, (int)gpCLen);
fs.Close();
The PageMediaSize node in the xml file produced does indeed have all the page sizes, AND the missing ones.
Displayed pages seem to have their name start psk:
<psf:Option name="psk:ISOA4" constrained="psk:None">
but undisplayed pages seem to have:
<psf:Option name="ns0000:LETTERSMALL" constrained="psk:None">
Undisplayed Epson print driver pages are similar:
<psf:Option name="epns200:IndexCard5x8" constrained="psk:None">
Basically a page whos name starts 'psk' PageMediaSizeCapability displays, but if it's manufacture custom ie epns200, ns0000, it doesn't list. Any ideas why and how to fix this please? The nodes/Pages are there but PageMediaSizeCapability doesn't like it!
Thanks in advance
EDIT:
As MS state 'A PrintCapabilities object is an easy-to-work-with representation of a certain type of XML document called a PrintCapabilities document.' But the document has more info than the object Full description
you have to save the paper name that you read from PrintCapabilities xml, and the use it to create a PrintTicket xml (PrintTicket has a constructor that accepts a xml stream), and then use the PrintTicket. Here is an example of PrintTicket XML (ns0000:User0000000257 is hte name of a custom paper size that i created):
<psf:PrintTicket xmlns:psf="http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:psk="http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords"
xmlns:ns0000="http://schemas.microsoft.com/windows/printing/oemdriverpt/Samsung_CLP-310 Series/5.1.2600.2180/" version="1">
<psf:Feature name="psk:PageMediaSize">
<psf:Option name="ns0000:User0000000257"></psf:Option>
</psf:Feature>
</psf:PrintTicket>
Even though this was an older thread, it was helpful in pointing us in the right direction when we needed to read and update custom properties.
The code below was adapted from this thread: XPS Printing, Tray selection and InputBinCapability (InputBin) = Problem: http://www.windows-tech.info/14/29c7cf575646cb39.php. Jo0815's answer at the bottom had most of what you see below, especially the XPath expressions that pointed us in the right direction.
Also, update the PrintQueue.UserPrintTicket with your changes, NOT the DefaultPrintTicket.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Printing;
using System.Text;
using System.Windows;
using System.Xml;
// Adapted
// From: XPS Printing, Tray selection and InputBinCapability (InputBin) = Problem
// Link: http://www.windows-tech.info/14/29c7cf575646cb39.php - last answer at bottom by Jo0815
namespace WpfApplication1
{
public static class WpfPrinterUtilities
{
#region GetPrintQueues
/// <summary>
/// Gets a dictionary of print queues where Key = print queue name
/// and Value = the print queue object.
/// </summary>
/// <param name="printQueueTypes">EnumeratedPrintQueueTypes params array of the types of print queues being requested.</param>
/// <returns>Dictionary of requested print queues where Key = print queue name and Value = the print queue object itself.</returns>
public static Dictionary<string, PrintQueue> GetPrintQueues(params EnumeratedPrintQueueTypes[] printQueueTypes)
{
var server = new PrintServer();
return server.GetPrintQueues(printQueueTypes).ToDictionary(pq => pq.ShareName != null ? pq.ShareName : pq.Name);
}
#endregion
#region GetInputBins
/// <summary>
/// Reads print queue configuration xml to retrieve the current list of input bins.
/// </summary>
/// <param name="printQueue">The print queue to query.</param>
/// <returns></returns>
public static Dictionary<string, string> GetInputBins(PrintQueue printQueue)
{
Dictionary<string, string> inputBins = new Dictionary<string, string>();
// Get the print queue PrintCapabilities.
XmlDocument xmlDoc = null;
using (MemoryStream stream = printQueue.GetPrintCapabilitiesAsXml())
{
// Read the JobInputBins out of the PrintCapabilities.
xmlDoc = new XmlDocument();
xmlDoc.Load(stream);
}
// Create NamespaceManager and add PrintSchemaFrameWork-Namespace (should be on DocumentElement of the PrintTicket).
// Prefix: psf NameSpace: xmlDoc.DocumentElement.NamespaceURI = "http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework"
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace(xmlDoc.DocumentElement.Prefix, xmlDoc.DocumentElement.NamespaceURI);
// Select all job input bins.
XmlNodeList nodeList = xmlDoc.SelectNodes("//psf:Feature[#name='psk:JobInputBin']/psf:Option/psf:Property", manager);
// Load the Dictionary with the bin values and names. The names will be used to modify the print ticket if necessary.
foreach (XmlNode node in nodeList)
{
inputBins.Add(node.LastChild.InnerText, node.ParentNode.Attributes[0].Value);
}
return inputBins;
}
#endregion
#region ModifyPrintTicket
/// <summary>
/// Modifes a print ticket xml after updating a feature value.
///
/// Sample usage:
/// Get Dictionary with Inputbins by calling the other method
/// and get "value" for the desired inputbin you'd like to use...
/// ...
/// desiredTray is then something like "NS0000:SurpriseOption7" for example.
/// defaultPrintTicket is the (Default)PrintTicket you want to modify from the PrintQueue for example
/// PrintTicket myPrintTicket = WpfPrinterUtils.ModifyPrintTicket(defaultPrintTicket, "psk:JobInputBin", desiredTray);
/// </summary>
/// <param name="ticket"></param>
/// <param name="featureName"></param>
/// <param name="newValue"></param>
/// <param name="printQueueName">Optional - If provided, a file is created with the print ticket xml. Useful for debugging.</param>
/// <param name="folder">Optional - If provided, the path for a file is created with the print ticket xml. Defaults to c:\. Useful for debugging.</param>
/// <param name="displayMessage">Optional - True to display a dialog with changes. Defaults to false. Useful for debugging.</param>
/// <returns></returns>
public static PrintTicket ModifyPrintTicket(PrintTicket ticket, string featureName, string newValue, string printQueueName = null, string folder = null, bool displayMessage = false)
{
if (ticket == null)
{
throw new ArgumentNullException("ticket");
}
// Read Xml of the PrintTicket xml.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ticket.GetXmlStream());
// Create NamespaceManager and add PrintSchemaFrameWork-Namespace hinzufugen (should be on DocumentElement of the PrintTicket).
// Prefix: psf NameSpace: xmlDoc.DocumentElement.NamespaceURI = "http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework"
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace(xmlDoc.DocumentElement.Prefix, xmlDoc.DocumentElement.NamespaceURI);
// Search node with desired feature we're looking for and set newValue for it
string xpath = string.Format("//psf:Feature[#name='{0}']/psf:Option", featureName);
XmlNode node = xmlDoc.SelectSingleNode(xpath, manager);
if (node != null)
{
if (node.Attributes["name"].Value != newValue)
{
if (displayMessage)
{
System.Windows.MessageBox.Show(string.Format("OldValue: {0}, NewValue: {1}", node.Attributes["name"].Value, newValue), "Input Bin");
}
node.Attributes["name"].Value = newValue;
}
}
// Create a new PrintTicket out of the XML.
PrintTicket modifiedPrintTicket = null;
using (MemoryStream stream = new MemoryStream())
{
xmlDoc.Save(stream);
stream.Position = 0;
modifiedPrintTicket = new PrintTicket(stream);
}
// For testing purpose save the print ticket to a file.
if (!string.IsNullOrWhiteSpace(printQueueName))
{
if (string.IsNullOrWhiteSpace(folder))
{
folder = "c:\\";
}
// Colons are not valid in a file name.
newValue = newValue.Replace(':', ';');
printQueueName = string.Format("{0} PrintTicket {1}.xml", Path.Combine(folder, printQueueName), newValue);
if (File.Exists(printQueueName))
{
File.Delete(printQueueName);
}
if (!Directory.Exists(Path.GetDirectoryName(printQueueName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(printQueueName));
}
using (FileStream stream = new FileStream(printQueueName, FileMode.CreateNew, FileAccess.ReadWrite))
{
modifiedPrintTicket.GetXmlStream().WriteTo(stream);
}
}
return modifiedPrintTicket;
}
#endregion
}
}

how to get file from resources as a stream? (.net)

I've got few files in resources (xsd files) that i use for validating received xml messages. The resource file i use is named AppResources.resx and it contains a file called clientModels.xsd. When i try to use the file like this: AppResources.clientModels, i get a string with the file's content. i would like to get a stream instead.
i do not wish to use assembly.GetManifestResourceStream as i had bad experiences with it (using these streams to archive files with SharpZipLib didn't work for some reason).
is there any other way to do it? i've heard about ResourceManager - is it anything that could help me?
Could you feed the string you get into a System.IO.StringReader, perhaps? That may do what you want. You may also want to check out MemoryStream.
here is the code from the link
//Namespace reference
using System;
using System.Resources;
#region ReadResourceFile
/// <summary>
/// method for reading a value from a resource file
/// (.resx file)
/// </summary>
/// <param name="file">file to read from</param>
/// <param name="key">key to get the value for</param>
/// <returns>a string value</returns>
public string ReadResourceValue(string file, string key)
{
//value for our return value
string resourceValue = string.Empty;
try
{
// specify your resource file name
string resourceFile = file;
// get the path of your file
string filePath = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
// create a resource manager for reading from
//the resx file
ResourceManager resourceManager = ResourceManager.CreateFileBasedResourceManager(resourceFile, filePath, null);
// retrieve the value of the specified key
resourceValue = resourceManager.GetString(key);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
resourceValue = string.Empty;
}
return resourceValue;
}
#endregion
I did not write the code it came from
http://www.dreamincode.net/code/snippet1683.htm
HTH
bones
I have a zip file loaded as a resource, and referencing it directly from the namespace gives me bytes, not a string. Right-click on your file in the resources designer, and change the filetype from text to binary. Then you will get a bytearray, which you could load into a MemoryStream.

Categories

Resources