为什么 resourceReader.GetResourceData return 类型 "ResourceTypeCode.Stream" 的数据偏移 4
Why resourceReader.GetResourceData return Data of type "ResourceTypeCode.Stream" that is offset by 4
在我的函数 GetAssemblyResourceStream(下面的代码)中,我使用 "assembly.GetManifestResourceStream" 和 "resourceReader.GetResourceData" 从 Dll 中读取资源。
当我从资源的字节数组设置内存流时,我必须包含 4 个字节的偏移量:
const int OFFSET = 4;
resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);
偏移的原因是什么?它来自哪里?
末尾的示例
另外:我制作了一个测试应用程序以更好地了解资源。该应用程序显示了我遇到的偏移问题。我的小测试应用程序可在 Github (VS 2015)
更新 2015-10-05 10h28 由于答案非常少,我怀疑是一个错误 and/or 未记录的行为。我在 Connect.Microsoft.com 报告了一个错误,将会看到结果。
更新 2015-10-07 我删除了这个错误。我仍然认为它没有很好的记录 and/or 可以被视为一个错误,但我高度怀疑他们会在不做任何事情的情况下关闭我的请求。我希望没有人会遇到我遇到的同样问题。
代码:
// ******************************************************************
/// <summary>
/// The path separator is '/'. The path should not start with '/'.
/// </summary>
/// <param name="asm"></param>
/// <param name="path"></param>
/// <returns></returns>
public static Stream GetAssemblyResourceStream(Assembly asm, string path)
{
// Just to be sure
if (path[0] == '/')
{
path = path.Substring(1);
}
// Just to be sure
if (path.IndexOf('\') == -1)
{
path = path.Replace('\', '/');
}
Stream resStream = null;
string resName = asm.GetName().Name + ".g.resources"; // Ref: Thomas Levesque Answer at:
//
using (var stream = asm.GetManifestResourceStream(resName))
{
using (var resReader = new System.Resources.ResourceReader(stream))
{
string dataType = null;
byte[] data = null;
try
{
resReader.GetResourceData(path.ToLower(), out dataType, out data);
}
catch (Exception ex)
{
DebugPrintResources(resReader);
}
if (data != null)
{
switch (dataType) // COde from
{
// Handle internally serialized string data (ResourceTypeCode members).
case "ResourceTypeCode.String":
BinaryReader reader = new BinaryReader(new MemoryStream(data));
string binData = reader.ReadString();
Console.WriteLine(" Recreated Value: {0}", binData);
break;
case "ResourceTypeCode.Int32":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToInt32(data, 0));
break;
case "ResourceTypeCode.Boolean":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToBoolean(data, 0));
break;
// .jpeg image stored as a stream.
case "ResourceTypeCode.Stream":
////const int OFFSET = 4;
////int size = BitConverter.ToInt32(data, 0);
////Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
////Console.WriteLine(" Recreated Value: {0}", value1);
const int OFFSET = 4;
resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);
break;
// Our only other type is DateTimeTZI.
default:
////// No point in deserializing data if the type is unavailable.
////if (dataType.Contains("DateTimeTZI") && loaded)
////{
//// BinaryFormatter binFmt = new BinaryFormatter();
//// object value2 = binFmt.Deserialize(new MemoryStream(data));
//// Console.WriteLine(" Recreated Value: {0}", value2);
////}
////break;
break;
}
// resStream = new MemoryStream(resData);
}
}
}
return resStream;
}
要了解数据偏移,了解数据流的基础知识很重要:
What is a byte stream actually?
以及它们的一些用途:Transmission Control Protocol
数据偏移量是流中为除
实际数据。它们是赋予数据格式的字节值。
所以需要包含偏移量,这样这 4 个字节就不会被读取为数据。这是一个指令
告诉编译器如何读取字节。
对于未压缩的图像数据,偏移量为 4。
Pixels are packed into bytes and arranged as scan lines. Each scan
line must end on a 4-byte boundary, so one, two, or three bytes of
padding may follow each scan line.
所有编码数据都以 0 开头。
编码位图数据将以不作为位图数据读取的代码字节开始,
而是解释以下数据采用的格式。
Bytes of 04 AA 表示有4个字节的值为AA或AA AA AA AA的解码数据
如果解码字节数为奇数,运行 将以填充 00 开始和结束。
所以00 03 AA 00会被解码为AA AA AA
00 00 是表示扫描线结束的标记
00 01 是位图数据结束的标记
运行 偏移标记(也称为增量或矢量代码)是 4 个字节。
如果存在,则以以下值开头:
00 02 XX YY 后跟两个字节,X 和 Y 值。
前两个字节00 02是说明
-> 即以下两个字节
是位置,光标应该移动到哪里才能读取下一行数据。
This run offset marker indicates the location in the bitmap where the
next decoded run of pixels should be written. For example, a run
offset marker value of 00 02 05 03 would indicate that the offset of
the bitmap cursor should move five pixels down the scan line, three
rows forward, and write out the next run. The cursor then continues
writing decoded data from its new position moving forward.
我的大部分信息来源于和引用自:
Image and Data Compression
在
Microsoft Windows 位图文件格式摘要
反馈后编辑,不只是图片
基本上19种数据类型只能有一种。对于 Stream,添加偏移量,因为假设文件类型可能具有编码标记,以描述文件 type/format。由于 Stream 可能被编码,在这种情况下无法按原样读取数据,因此需要对其进行解码,这就是那些偏移字节中提供的内容。
你可能会争辩说 xml 是一个字符串类型,但如果它被检测为一个 Stream,会有一些嵌入的标记表明它不是一个字符串,而是一个编码的 Stream。
在 bmps 的情况下,保留偏移量为 4,但 4 个字节并不总是被填充,这些字节指示编译器下一步去哪里或如何解释下一个可读字节,以及何时该指令已完成(即使小于 4),读取将继续。
这是一个警告,不要将这些第一个字节作为数据读取!开头的 00 是一个标志。与读取 int 类型中的 00 并将其转换为 int 不同。
xml 文件可以嵌入标记,bmp 也是如此。
Chunk-based formats
In this kind of file structure, each piece
of data is embedded in a container that somehow identifies the data.
The container's scope can be identified by start- and end-markers of
some kind, by an explicit length field somewhere, or by fixed
requirements of the file format's definition.
这是资源 reader 背后的代码,我发现它很有用。如果你看一下这个,你会看到只有 19 种数据类型。
reference source Microsoft resourcereader
我希望这提供了一些清晰度。
我不认为这是一个错误。
为清楚起见,编辑以添加更多解释
找到StreamWrapper Class的时候其实是代码类型Stream
else if (type == typeof(StreamWrapper))
return ResourceTypeCode.Stream;
来自 MSDN 文档。
This class wraps an IStream interface into a System.IO.Stream class.
Since this code is for a classifier, there's no need to write to the
provided stream since the pipeline only provides read-only streams to
classifiers. Thus, the methods that modify the stream are not
implemented.
希望这已经回答了您的问题
byte[]开头的4个字节是size后面的数据的大小。但它完全没用,因为它是 byte[] 的一部分,并且 byte[] 的大小是已知的。此外,流的内容只是一个项目,其中 4 个字节的偏移量无法用于指示第一个项目相对于后续项目的大小,因为没有任何项目。
阅读后 ResourceReader.GetResourceData Method documentation : 我尝试了 BinaryReader 和 BinaryFormatter 都没有成功。我将继续按照之前的方式读取资源的内容(绕过大小并使用 BitConverter 直接转换为流)。
感谢 "Hey you" 让我想到了那个方向。
仅供参考。这是我的代码,但它可能不如它应该的那样准确......它适用于我但没有经过深入测试。只是一个开始。
// ******************************************************************
/// <summary>
/// Will load resource from any assembly that is part of the application.
/// It does not rely on Application which is specific to a (UI) frameowrk.
/// </summary>
/// <param name="uri"></param>
/// <param name="asm"></param>
/// <returns></returns>
public static Stream LoadResourceFromUri(Uri uri, Assembly asm = null)
{
Stream stream = null;
if (uri.Authority.StartsWith("application") && uri.Scheme == "pack")
{
string localPath = uri.GetComponents(UriComponents.Path, UriFormat.UriEscaped);
int indexLocalPathWithoutAssembly = localPath.IndexOf(";component/");
if (indexLocalPathWithoutAssembly == -1)
{
indexLocalPathWithoutAssembly = 0;
}
else
{
indexLocalPathWithoutAssembly += 11;
}
if (asm != null) // Take the provided assembly, do not check for the asm in the uri.
{
stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
}
else
{
if (uri.Segments.Length > 1)
{
if (uri.Segments[0] == "/" && uri.Segments[1].EndsWith(";component/"))
{
int index = uri.Segments[1].IndexOf(";");
if (index > 0)
{
string assemblyName = uri.Segments[1].Substring(0, index);
foreach (Assembly asmIter in AppDomain.CurrentDomain.GetAssemblies())
{
if (asmIter.GetName().Name == assemblyName)
{
stream = GetAssemblyResourceStream(asmIter, localPath.Substring(indexLocalPathWithoutAssembly));
break;
}
}
}
}
}
if (stream == null)
{
asm = Assembly.GetCallingAssembly();
stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
}
}
}
return stream;
}
// ******************************************************************
/// <summary>
/// The path separator is '/'. The path should not start with '/'.
/// </summary>
/// <param name="asm"></param>
/// <param name="path"></param>
/// <returns></returns>
public static Stream GetAssemblyResourceStream(Assembly asm, string path)
{
// Just to be sure
if (path[0] == '/')
{
path = path.Substring(1);
}
// Just to be sure
if (path.IndexOf('\') == -1)
{
path = path.Replace('\', '/');
}
Stream resStream = null;
string resName = asm.GetName().Name + ".g.resources"; // Ref: Thomas Levesque Answer at:
//
using (var stream = asm.GetManifestResourceStream(resName))
{
using (var resReader = new System.Resources.ResourceReader(stream))
{
string dataType = null;
byte[] data = null;
try
{
resReader.GetResourceData(path.ToLower(), out dataType, out data);
}
catch (Exception)
{
DebugPrintResources(resReader);
}
if (data != null)
{
switch (dataType) // COde from
{
// Handle internally serialized string data (ResourceTypeCode members).
case "ResourceTypeCode.String":
BinaryReader reader = new BinaryReader(new MemoryStream(data));
string binData = reader.ReadString();
Console.WriteLine(" Recreated Value: {0}", binData);
break;
case "ResourceTypeCode.Int32":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToInt32(data, 0));
break;
case "ResourceTypeCode.Boolean":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToBoolean(data, 0));
break;
// .jpeg image stored as a stream.
case "ResourceTypeCode.Stream":
////const int OFFSET = 4;
////int size = BitConverter.ToInt32(data, 0);
////Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
////Console.WriteLine(" Recreated Value: {0}", value1);
const int OFFSET = 4;
resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);
break;
// Our only other type is DateTimeTZI.
default:
////// No point in deserializing data if the type is unavailable.
////if (dataType.Contains("DateTimeTZI") && loaded)
////{
//// BinaryFormatter binFmt = new BinaryFormatter();
//// object value2 = binFmt.Deserialize(new MemoryStream(data));
//// Console.WriteLine(" Recreated Value: {0}", value2);
////}
////break;
break;
}
// resStream = new MemoryStream(resData);
}
}
}
return resStream;
}
我遇到了同样的问题,决定不使用 GetResourceData 方法。
我找到了其他解决方案,例如:
public static byte[] GetResource(string resourceName)
{
try
{
var asm = Assembly.LoadFrom("YOUR_ASSEMBLY");
Stream str = asm.GetManifestResourceStream($@"YOUR_ASSEMBLY.Properties.Resources.resources");
using (var reader = new ResourceReader(str))
{
var res = reader.GetEnumerator();
while (res.MoveNext())
{
if (res.Key.ToString() == resourceName)
{
if(res.Value is byte[])
return res.Value as byte[];
else if (res.Value is string)
return Encoding.UTF8.GetBytes(res.Value as string);
// TODO other types
}
}
return null;
}
}
catch (Exception ex)
{
// message
return null;
}
}
在我的函数 GetAssemblyResourceStream(下面的代码)中,我使用 "assembly.GetManifestResourceStream" 和 "resourceReader.GetResourceData" 从 Dll 中读取资源。
当我从资源的字节数组设置内存流时,我必须包含 4 个字节的偏移量:
const int OFFSET = 4;
resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);
偏移的原因是什么?它来自哪里?
末尾的示例另外:我制作了一个测试应用程序以更好地了解资源。该应用程序显示了我遇到的偏移问题。我的小测试应用程序可在 Github (VS 2015)
更新 2015-10-05 10h28 由于答案非常少,我怀疑是一个错误 and/or 未记录的行为。我在 Connect.Microsoft.com 报告了一个错误,将会看到结果。
更新 2015-10-07 我删除了这个错误。我仍然认为它没有很好的记录 and/or 可以被视为一个错误,但我高度怀疑他们会在不做任何事情的情况下关闭我的请求。我希望没有人会遇到我遇到的同样问题。
代码:
// ******************************************************************
/// <summary>
/// The path separator is '/'. The path should not start with '/'.
/// </summary>
/// <param name="asm"></param>
/// <param name="path"></param>
/// <returns></returns>
public static Stream GetAssemblyResourceStream(Assembly asm, string path)
{
// Just to be sure
if (path[0] == '/')
{
path = path.Substring(1);
}
// Just to be sure
if (path.IndexOf('\') == -1)
{
path = path.Replace('\', '/');
}
Stream resStream = null;
string resName = asm.GetName().Name + ".g.resources"; // Ref: Thomas Levesque Answer at:
//
using (var stream = asm.GetManifestResourceStream(resName))
{
using (var resReader = new System.Resources.ResourceReader(stream))
{
string dataType = null;
byte[] data = null;
try
{
resReader.GetResourceData(path.ToLower(), out dataType, out data);
}
catch (Exception ex)
{
DebugPrintResources(resReader);
}
if (data != null)
{
switch (dataType) // COde from
{
// Handle internally serialized string data (ResourceTypeCode members).
case "ResourceTypeCode.String":
BinaryReader reader = new BinaryReader(new MemoryStream(data));
string binData = reader.ReadString();
Console.WriteLine(" Recreated Value: {0}", binData);
break;
case "ResourceTypeCode.Int32":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToInt32(data, 0));
break;
case "ResourceTypeCode.Boolean":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToBoolean(data, 0));
break;
// .jpeg image stored as a stream.
case "ResourceTypeCode.Stream":
////const int OFFSET = 4;
////int size = BitConverter.ToInt32(data, 0);
////Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
////Console.WriteLine(" Recreated Value: {0}", value1);
const int OFFSET = 4;
resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);
break;
// Our only other type is DateTimeTZI.
default:
////// No point in deserializing data if the type is unavailable.
////if (dataType.Contains("DateTimeTZI") && loaded)
////{
//// BinaryFormatter binFmt = new BinaryFormatter();
//// object value2 = binFmt.Deserialize(new MemoryStream(data));
//// Console.WriteLine(" Recreated Value: {0}", value2);
////}
////break;
break;
}
// resStream = new MemoryStream(resData);
}
}
}
return resStream;
}
要了解数据偏移,了解数据流的基础知识很重要:
What is a byte stream actually?
以及它们的一些用途:Transmission Control Protocol
数据偏移量是流中为除 实际数据。它们是赋予数据格式的字节值。
所以需要包含偏移量,这样这 4 个字节就不会被读取为数据。这是一个指令 告诉编译器如何读取字节。
对于未压缩的图像数据,偏移量为 4。
Pixels are packed into bytes and arranged as scan lines. Each scan line must end on a 4-byte boundary, so one, two, or three bytes of padding may follow each scan line.
所有编码数据都以 0 开头。 编码位图数据将以不作为位图数据读取的代码字节开始, 而是解释以下数据采用的格式。
Bytes of 04 AA 表示有4个字节的值为AA或AA AA AA AA的解码数据 如果解码字节数为奇数,运行 将以填充 00 开始和结束。
所以00 03 AA 00会被解码为AA AA AA
00 00 是表示扫描线结束的标记 00 01 是位图数据结束的标记
运行 偏移标记(也称为增量或矢量代码)是 4 个字节。 如果存在,则以以下值开头:
00 02 XX YY 后跟两个字节,X 和 Y 值。
前两个字节00 02是说明
-> 即以下两个字节
是位置,光标应该移动到哪里才能读取下一行数据。
This run offset marker indicates the location in the bitmap where the next decoded run of pixels should be written. For example, a run offset marker value of 00 02 05 03 would indicate that the offset of the bitmap cursor should move five pixels down the scan line, three rows forward, and write out the next run. The cursor then continues writing decoded data from its new position moving forward.
我的大部分信息来源于和引用自:
Image and Data Compression 在 Microsoft Windows 位图文件格式摘要
反馈后编辑,不只是图片
基本上19种数据类型只能有一种。对于 Stream,添加偏移量,因为假设文件类型可能具有编码标记,以描述文件 type/format。由于 Stream 可能被编码,在这种情况下无法按原样读取数据,因此需要对其进行解码,这就是那些偏移字节中提供的内容。
你可能会争辩说 xml 是一个字符串类型,但如果它被检测为一个 Stream,会有一些嵌入的标记表明它不是一个字符串,而是一个编码的 Stream。
在 bmps 的情况下,保留偏移量为 4,但 4 个字节并不总是被填充,这些字节指示编译器下一步去哪里或如何解释下一个可读字节,以及何时该指令已完成(即使小于 4),读取将继续。
这是一个警告,不要将这些第一个字节作为数据读取!开头的 00 是一个标志。与读取 int 类型中的 00 并将其转换为 int 不同。
xml 文件可以嵌入标记,bmp 也是如此。
Chunk-based formats
In this kind of file structure, each piece of data is embedded in a container that somehow identifies the data. The container's scope can be identified by start- and end-markers of some kind, by an explicit length field somewhere, or by fixed requirements of the file format's definition.
这是资源 reader 背后的代码,我发现它很有用。如果你看一下这个,你会看到只有 19 种数据类型。
reference source Microsoft resourcereader
我希望这提供了一些清晰度。
我不认为这是一个错误。
为清楚起见,编辑以添加更多解释
找到StreamWrapper Class的时候其实是代码类型Stream
else if (type == typeof(StreamWrapper))
return ResourceTypeCode.Stream;
来自 MSDN 文档。
This class wraps an IStream interface into a System.IO.Stream class. Since this code is for a classifier, there's no need to write to the provided stream since the pipeline only provides read-only streams to classifiers. Thus, the methods that modify the stream are not implemented.
希望这已经回答了您的问题
byte[]开头的4个字节是size后面的数据的大小。但它完全没用,因为它是 byte[] 的一部分,并且 byte[] 的大小是已知的。此外,流的内容只是一个项目,其中 4 个字节的偏移量无法用于指示第一个项目相对于后续项目的大小,因为没有任何项目。
阅读后 ResourceReader.GetResourceData Method documentation : 我尝试了 BinaryReader 和 BinaryFormatter 都没有成功。我将继续按照之前的方式读取资源的内容(绕过大小并使用 BitConverter 直接转换为流)。
感谢 "Hey you" 让我想到了那个方向。
仅供参考。这是我的代码,但它可能不如它应该的那样准确......它适用于我但没有经过深入测试。只是一个开始。
// ******************************************************************
/// <summary>
/// Will load resource from any assembly that is part of the application.
/// It does not rely on Application which is specific to a (UI) frameowrk.
/// </summary>
/// <param name="uri"></param>
/// <param name="asm"></param>
/// <returns></returns>
public static Stream LoadResourceFromUri(Uri uri, Assembly asm = null)
{
Stream stream = null;
if (uri.Authority.StartsWith("application") && uri.Scheme == "pack")
{
string localPath = uri.GetComponents(UriComponents.Path, UriFormat.UriEscaped);
int indexLocalPathWithoutAssembly = localPath.IndexOf(";component/");
if (indexLocalPathWithoutAssembly == -1)
{
indexLocalPathWithoutAssembly = 0;
}
else
{
indexLocalPathWithoutAssembly += 11;
}
if (asm != null) // Take the provided assembly, do not check for the asm in the uri.
{
stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
}
else
{
if (uri.Segments.Length > 1)
{
if (uri.Segments[0] == "/" && uri.Segments[1].EndsWith(";component/"))
{
int index = uri.Segments[1].IndexOf(";");
if (index > 0)
{
string assemblyName = uri.Segments[1].Substring(0, index);
foreach (Assembly asmIter in AppDomain.CurrentDomain.GetAssemblies())
{
if (asmIter.GetName().Name == assemblyName)
{
stream = GetAssemblyResourceStream(asmIter, localPath.Substring(indexLocalPathWithoutAssembly));
break;
}
}
}
}
}
if (stream == null)
{
asm = Assembly.GetCallingAssembly();
stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
}
}
}
return stream;
}
// ******************************************************************
/// <summary>
/// The path separator is '/'. The path should not start with '/'.
/// </summary>
/// <param name="asm"></param>
/// <param name="path"></param>
/// <returns></returns>
public static Stream GetAssemblyResourceStream(Assembly asm, string path)
{
// Just to be sure
if (path[0] == '/')
{
path = path.Substring(1);
}
// Just to be sure
if (path.IndexOf('\') == -1)
{
path = path.Replace('\', '/');
}
Stream resStream = null;
string resName = asm.GetName().Name + ".g.resources"; // Ref: Thomas Levesque Answer at:
//
using (var stream = asm.GetManifestResourceStream(resName))
{
using (var resReader = new System.Resources.ResourceReader(stream))
{
string dataType = null;
byte[] data = null;
try
{
resReader.GetResourceData(path.ToLower(), out dataType, out data);
}
catch (Exception)
{
DebugPrintResources(resReader);
}
if (data != null)
{
switch (dataType) // COde from
{
// Handle internally serialized string data (ResourceTypeCode members).
case "ResourceTypeCode.String":
BinaryReader reader = new BinaryReader(new MemoryStream(data));
string binData = reader.ReadString();
Console.WriteLine(" Recreated Value: {0}", binData);
break;
case "ResourceTypeCode.Int32":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToInt32(data, 0));
break;
case "ResourceTypeCode.Boolean":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToBoolean(data, 0));
break;
// .jpeg image stored as a stream.
case "ResourceTypeCode.Stream":
////const int OFFSET = 4;
////int size = BitConverter.ToInt32(data, 0);
////Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
////Console.WriteLine(" Recreated Value: {0}", value1);
const int OFFSET = 4;
resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);
break;
// Our only other type is DateTimeTZI.
default:
////// No point in deserializing data if the type is unavailable.
////if (dataType.Contains("DateTimeTZI") && loaded)
////{
//// BinaryFormatter binFmt = new BinaryFormatter();
//// object value2 = binFmt.Deserialize(new MemoryStream(data));
//// Console.WriteLine(" Recreated Value: {0}", value2);
////}
////break;
break;
}
// resStream = new MemoryStream(resData);
}
}
}
return resStream;
}
我遇到了同样的问题,决定不使用 GetResourceData 方法。 我找到了其他解决方案,例如:
public static byte[] GetResource(string resourceName)
{
try
{
var asm = Assembly.LoadFrom("YOUR_ASSEMBLY");
Stream str = asm.GetManifestResourceStream($@"YOUR_ASSEMBLY.Properties.Resources.resources");
using (var reader = new ResourceReader(str))
{
var res = reader.GetEnumerator();
while (res.MoveNext())
{
if (res.Key.ToString() == resourceName)
{
if(res.Value is byte[])
return res.Value as byte[];
else if (res.Value is string)
return Encoding.UTF8.GetBytes(res.Value as string);
// TODO other types
}
}
return null;
}
}
catch (Exception ex)
{
// message
return null;
}
}