I have a dll which stores image resources , font resources etc...
I have a class in the assembly which has a return method that I want to be able to pull resources from the dll and return them as an abject which I can then convert to its respective type .
here is the code I have so far.
public class GetResource
{
public static T LoadDllResource<T>(string ResourceFolder, string resourceName, string Extension, int width = 10, int height = 10)
{
Assembly myAssembly = Assembly.GetExecutingAssembly();
Stream myStream = myAssembly.GetManifestResourceStream(myAssembly.GetName().Name + "." + ResourceFolder + "." + resourceName + "." + Extension);
// convert stream to object by doing something like this (I'm not sure)
//return (T)Convert.ChangeType(EndResultOFStreamConversion, typeof(object));
}
}
and use it this way
Font SomeFont1= GetResource.LoadDllResource<Font>("Resources","Splash","ttf")
UnityEngine.Texture2D SomeImage2= GetResource.LoadDllResource<UnityEngine.Texture2D>("Resources","SnowImage","png")
Let me know if there is a problem with the question. Thanks for any help !
I am working in the Unity Engine which does not nicely support mixed assemblies using System.Drawing
You can use the Image.FromStream Method within the System.Drawing namespace to convert a stream to an image (be sure to add a reference to System.Drawing.dll to your assembly first). I'm not quite sure what you mean by 'font resources' but I'd do it this way:
public class GetResource
{
public Image GetImageFromResource(string resourceFolder, string resourceName, string extension)
{
return Image.FromStream(this.GetStreamFromResource(resourceFolder, resourceName, extension), true);
}
private Stream GetStreamFromResource(string ResourceFolder, string resourceName, string Extension)
{
Assembly myAssembly = Assembly.GetExecutingAssembly();
return myAssembly.GetManifestResourceStream(myAssembly.GetName().Name + "." + ResourceFolder + "." + resourceName + "." + Extension);
}
}
Related
I am using CodeDom Compiler and Microsoft.CSharp, I am trying to embed a resource and call it. The reason I don't try to call properties is because I always get an error saying Properties does not exist in the current context. So I want to know if doing
Parameters.EmbeddedResources.Add("C:/Users/User1/Music/sample.mp3"); is actually helpful or if I should be doing it another way. This is what I have now in the compiler source:
Extract("TestCompiler", "C:/Users/User1/Downloads", "", "Music.mp3");
private static void Extract(string NameSpace, string OutputDir, string InternalPath, string ResourceName){
Assembly assembly = Assembly.GetCallingAssembly();
using (Stream s = assembly.GetManifestResourceStream(NameSpace + "." + (InternalPath == "" ? "" : InternalPath + ".") + ResourceName))
using (BinaryReader r = new BinaryReader(s))
using (FileStream fs = new FileStream(OutputDir + "\\" + ResourceName, FileMode.OpenOrCreate))
using (BinaryWriter w = new BinaryWriter(fs))
w.Write(r.ReadBytes((int)s.Length));
}
When I do this and run the compiled exe this is the exception/error I get:
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: input
at System.IO.BinaryReader..ctor(Stream input, Encoding encoding, Boolean leaveOpen)
at TestCompiler.Program.Extract(String NameSpace, String OutputDir, String InternalPath, String ResourceName)
at TestCompiler.Program.Main(String[] args)
I also have tried doing Extract("TestCompiler", "C:/Users/User1/Downloads", "Resources", "Music.mp3"); but I get the same error.
Is calling a embedded resource possible or should I give up? I've been at this for 3 days.
To answer my own question, I had to get all of the resources by doing this:
string[] Resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();
and to reference and extract them I did this:
foreach(string Resource in Resources)
WriteResources(Resources[Resource], "C:\\Test\\example.mp3");
public static void WriteResources(string Name, string Output){
using(var Resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(Name))
using(var File = new FileStream(Output, FileMode.Create, FileAccess.Write))
Resource.CopyTo(File);
}
Luckily I was able to finish my project after some solid days.
I have four resource files embedded in my C# executable, 1 python script and 3 perl scripts. I could extract all three perl scripts successfully. But I am not able to extract the python script. I tried so many ways. Could someone please have a look ? Thank you.
public static string ExtractResource(string resourceName)
{
string destFile = "";
//look for the resource name
foreach (string currentResource in System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames() )
if (currentResource.LastIndexOf(resourceName) != -1)
{
string subPath = Common_Utilities.GetTempPath() + "SCRIPTS";
bool isExists = System.IO.Directory.Exists(subPath);
if (!isExists)
System.IO.Directory.CreateDirectory(subPath);
string strFile = subPath + "\\" + resourceName;
string path = System.IO.Path.GetDirectoryName(strFile);
string rootName = System.IO.Path.GetFileNameWithoutExtension(strFile);
destFile = path + #"\" + rootName + System.IO.Path.GetExtension(currentResource);
System.IO.Stream fs = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream( currentResource ) ;
byte[] buff = new byte[fs.Length];
fs.Read(buff, 0, (int)fs.Length);
fs.Close();
System.IO.FileStream destStream = new System.IO.FileStream(destFile, FileMode.Create);
destStream.Write(buff, 0, buff.Length);
destStream.Close();
}
return destFile;
// throw new Exception("Resource not found : " + resourceName);
}
Not sure why the Python script can't be extracted.... couple points though:
I would recommend to use Path.Combine() to stick together path and file name - don't do this yourself, too many chances for error!
Since those are (text-based) scripts, you could do the whole copying much simpler:
System.IO.Stream fs = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(currentResource);
string scriptContents = new StreamReader(fs).ReadToEnd();
File.WriteAllText(destFile, scriptContents);
With this approach, you should be easily able to see in debugging whether or not the script is properly loaded from resources. If not - check your resource name etc. (is the script really set to "embedded" resource?). If you have subdirectories for your resources, be aware that the resource name will contain those subdirectories as part of the fully qualified name - but separated by a dot (.), not a backslash like a physical path!
easy way you can mod your code with
Binary files -> File.WriteAllBytes(Path, Properties.Resources.filename);
Text files -> File.WriteAllText(Path, Properties.Resources.filename);
I have a few methods which work with MemoryMappedFiles for writing/reading data. They work alright if I use simple string for file name, for example "file.mmf". However if I use full directory path the above mentioned exception is being thrown -
Exception has been thrown by the target of an invocation.
With inner exception - {"Could not find a part of the path."}. Here is how my method looks like:
public void WriteToFile(string fileName, string value)
{
string newFileName = CombineDirectory(fileName);
byte[] newValue = Encoding.UTF8.GetBytes(value);
long capacity = newValue.Length + INT_MAXVALUE_TO_BYTEARRAY_LENGTH;
using (var mmf = MemoryMappedFile.CreateFromFile(newFileName, FileMode.Create, newFileName, capacity))
{
using (var accesor = mmf.CreateViewAccessor())
{
byte[] newValueLength = BitConverter.GetBytes(value.Length);
accesor.WriteArray(0, newValueLength, 0, newValueLength.Length);
accesor.WriteArray(INT_MAXVALUE_TO_BYTEARRAY_LENGTH, newValue, 0, newValue.Length);
}
}
}
My path looks like this :
"C:\\Users\\MyUser\\Documents\\Visual Studio 2012.mmf"
And I am using
Path.Combine
The exception occurs on the first 'using' line. If I try to create a file using the same file path with
File.Create
the file is being created with no problem.
If anyone has any suggestions, that would be great.
Regards
You need to make sure that the mapName argument (i.e. the third argument in your call to CreateFromFile) is not identical to the file path. It will throw a PathNotFound exception if you do. Not really helpful in figuring out why it is failing, I agree.
So your options for choosing a map name value:
Generate some unique key, e.g. Guid.NewGuid().ToString()
Use a constant value, e.g. "MySpecialMapForThings"
Use some convention, e.g. generate a unique key that you also use for just the file name part of the mapped file.
An example for the last option:
public static Tuple<FileInfo, string> GenerateMapInfo(string mapDirectory, string fileExtension)
{
var uniqueMapName = Guid.NewGuid().ToString();
var fileName = Path.Combine(mapDirectory, Path.ChangeExtension(uniqueMapName, fileExtension));
return Tuple.Create(new FileInfo(fileName), uniqueMapName);
}
public void WriteToFile(Tuple<FileInfo, string> mapInfo, string value)
{
byte[] newValue = Encoding.UTF8.GetBytes(value);
long capacity = newValue.Length + INT_MAXVALUE_TO_BYTEARRAY_LENGTH;
using (var mmf = MemoryMappedFile.CreateFromFile(mapInfo.Item1.FullName, FileMode.Create, mapInfo.Item2, capacity))
using (var accesor = mmf.CreateViewAccessor())
{
byte[] newValueLength = BitConverter.GetBytes(value.Length);
accesor.WriteArray(0, newValueLength, 0, newValueLength.Length);
accesor.WriteArray(INT_MAXVALUE_TO_BYTEARRAY_LENGTH, newValue, 0, newValue.Length);
}
}
I use this code to embed all dlls to app exe file but this code can embed only one dll. i search for other code but all are same that.
public App()
{
AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");
dllName = dllName.Replace(".", "_");
if (dllName.EndsWith("_resources")) return null;
System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
byte[] bytes = (byte[])rm.GetObject(dllName);
return System.Reflection.Assembly.Load(bytes);
}
to use ILmerge i have problem wuth my dlls. so i cant use this.
how can i do this?
This open source tool should help you
http://madebits.com/netz/
A possible approach is to add all your DLLs to resources (manually). Then, at the program's startup, use File.WriteAllBytes to write those resource byte streams to files.
NOTE : In this case you cannot use DllImport, since it requires constant string path. Instead, you will use what so called "dynamic P\Invoke". Learn more.
Using GetManifestResourceStream should work better.
When the dlls are embedded as resources the resource names are prefixed with the default name space for you project, so you will need to fill that in.
eg
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string defaultNameSpace = "...";
string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
string resourceName = String.Format("{0}.{1}.dll", defaultNameSpace , dllName);
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
if (stream == null)
return null;
byte[] data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return Assembly.Load(data);
}
}
I am having below string and filename, the filename is the output of another function, so it look like below
string filename = "maindestination.jpg"; //It can .png, .gif etc depend on the type of file.
Then I have got another function which gives the output as below
string id = "tcm:123-3455";
Now I want to write a function something like below which will do the merging of both the outputted values as below:
public static string newFileName(string filename, string strID)
{
string newFileName = "maindestination_tcm:123-3455.jpg"
return newFileName;
}
public static string GetFileNameWithId(string fileName, string strId) {
return string.Format(
"{0}_{1}{2}",
Path.GetFileNameWithoutExtension(fileName),
strId,
Path.GetExtension(fileName));
}
Use the methods in the Path class, in the System.IO namespace:
string newFileName=Path.GetFileNameWithoutExtension(filename)+"_"+strID+Path.GetExtension(filename);
By the way, this will work on any version of the .NET Framework, not just in C# 2.0.