I found the following code at Dr Dobbs (slightly rewritten):
namespace TestEXEApp
{
public class Program
{
static void Main(string[] args)
{
AssemblyName an = new AssemblyName();
an.Name = "TestEXEApp";
AppDomain ad = AppDomain.CurrentDomain;
AssemblyBuilder ab = ad.DefineDynamicAssembly(an,
AssemblyBuilderAccess.Save);
ModuleBuilder mb = ab.DefineDynamicModule(an.Name, "Hello.exe");
TypeBuilder tb = mb.DefineType("TestEXEApp.Program",
TypeAttributes.Public | TypeAttributes.Class);
MethodBuilder fb = tb.DefineMethod("Main",
MethodAttributes.Public |
MethodAttributes.Static,
typeof(int), new Type[] { typeof(string[]) });
ILGenerator ilg = fb.GetILGenerator();
ilg.Emit(OpCodes.Ldstr, "Hello, World!");
ilg.Emit(OpCodes.Call, typeof(TestClasses.Class1).GetMethod("Test",
new Type[] { typeof(string) }));
ilg.Emit(OpCodes.Ldc_I4_0);
ilg.Emit(OpCodes.Ret);
// Seal the lid on this type
Type t = tb.CreateType();
// Set the entrypoint (thereby declaring it an EXE)
ab.SetEntryPoint(fb, PEFileKinds.ConsoleApplication);
// Save it
ab.Save("Hello.exe");
Console.WriteLine("Press enter...");
Console.ReadLine();
}
}
}
Also, I have the following class in a separate project called TestClasses:
namespace TestClasses
{
public class Class1
{
public static void Test(String t)
{
Console.WriteLine("Test: " + t);
}
}
}
Now, when I compile this, I get (obviously) the two files "TestEXEApp.exe" and "TestClasses.dll". If I run it, I get a new file, "Hello.exe", and if I run this new file, it prints "Test: Hello, World!". So far, so good. Now, the problem is, this new file obviously depends on TestClasses.dll. So if I emit it into another directory, or move it for some reason, it can no longer execute.
Is there some way for Reflection.Emit to in some way include the TestClasses.Class1 code into the Hello.exe executable, so that it becomes 100% self-contained (apart from the dependence on the .NET framework, obviously)? Or, if that can't be done, how can I get the program to output a copy of TestClasses.dll, so that I always have the dll-file written in the same directory as Hello.exe?
Related
I am developing a library in C# that generates runtime types using System.Reflection.Emit.TypeBuilder class and i want to generate the following class hierarchy:
[XmlInclude(typeof(Derived))]
public class Base
{
}
public class Derived : Base
{
}
I use the TypeBuilder class in the following way:
class Program
{
public static void Main(string[] args)
{
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var moduleBuilder = assembly.DefineDynamicModule("Test");
var baseTypeBuilder = moduleBuilder.DefineType("Base", TypeAttributes.Public, typeof(Object));
var derivedTypeBuilder = moduleBuilder.DefineType("Derived", TypeAttributes.Public);
derivedTypeBuilder.SetParent(baseTypeBuilder);
baseTypeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(XmlIncludeAttribute).GetConstructor(new[] { typeof(Type) }), new[] { derivedTypeBuilder }));
var baseType = baseTypeBuilder.CreateType();
var derivedType = derivedTypeBuilder.CreateType();
var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();
}
}
The call:
var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();
I receive the following error:
Could not load file or assembly 'Test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Any ideas are well-appreciated: how can i apply a custom attribute on a TypeBuilder for base class that refers to a TypeBuilder for a derived class?
P.S: I'm using Visual Studio 2017 (v15.7.5) and a C# Class Library (.NET Framework project template) NOT .NET Core or .NET Standard
Cannot provide much reason but a solution that will work without additional load/unload or whatever from and to disk:
Adding a separate field containing the actual Assembly, one can just subscribe to AppDomain.CurrentDomain.AssemblyResolve and check if the dynamic assembly was requested.
If it was, you just need to return your field and it works perfectly fine.
Example:
class Program
{
static Assembly ass;
public static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var moduleBuilder = assembly.DefineDynamicModule("Test");
var baseTypeBuilder = moduleBuilder.DefineType("Base", TypeAttributes.Public, typeof(Object));
var derivedTypeBuilder = moduleBuilder.DefineType("Derived", TypeAttributes.Public);
derivedTypeBuilder.SetParent(baseTypeBuilder);
baseTypeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(XmlIncludeAttribute).GetConstructor(new[] { typeof(Type) }), new[] { derivedTypeBuilder }));
var baseType = baseTypeBuilder.CreateType();
var derivedType = derivedTypeBuilder.CreateType();
ass = baseType.Assembly;
var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();
Console.WriteLine(attribute.Type.FullName);
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
return ass;
}
}
I've reproduced your exception. It's looks like the .NET Framework want to read a module from disk.
So simplest workaround would be to save your assembly to the disk:
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("Test"),
AssemblyBuilderAccess.RunAndSave); // allow run & save
var moduleBuilder = assembly.DefineDynamicModule("Test",
"Test.dll"); // specify a file name where module will be stored
...
var baseType = baseTypeBuilder.CreateType();
var derivedType = derivedTypeBuilder.CreateType();
assembly.Save("Test.dll");
Now I was able to get attribute without exception:
var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();
Well, I can tell you why the fix #X39 posted works. Stepping through the forest of framework code (perhaps fallbacks for different cultures) for the baseType.GetCustomAttribute(); call, when finally reaching appdomain.cs I see:
At this point, _AssemblyResolve is null (which is the private backing field for AppDomain.CurrentDomain.AssemblyResolve) and after stepping through to return null;, the code crashes with the error you posted.
More info: https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.assemblyresolve?view=netframework-4.7.2
#X39 feel free to merge my answer and let me know so that I can remove mine, I did not want to edit your answer directly.
I'm developing some .Net application and I need to inject in any assembly new method with my own code. I'm using Mono.Cecil to get body of assembly and I found some samples, but they're old enough. Unfortunately, there's no info in migraton section on github wiki.
So, I have this code:
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace CustomFieldsInjection
{
public partial class Injector
{
public static void MethodInjection(string assemblyFilename, string typeName, string methodName)
{
AssemblyDefinition assembly = AssemblyFactory.GetAssembly(assemblyFilename);
TypeReference returnTypeReference = assembly.MainModule.Import(typeof(void));
MethodDefinition methodDefinition = new MethodDefinition(methodName, MethodAttributes.Public | MethodAttributes.Static, returnTypeReference);
Instruction instruction1 = methodDefinition.Body.CilWorker.Create(OpCodes.Nop);
Instruction instruction2 = methodDefinition.Body.CilWorker.Create(OpCodes.Ldstr, methodName);
MethodReference writeline = assembly.MainModule.Import(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
methodDefinition.Body.CilWorker.Append(instruction1);
methodDefinition.Body.CilWorker.Append(instruction2);
methodDefinition.Body.CilWorker.InsertAfter(instruction2, methodDefinition.Body.CilWorker.Create (OpCodes.Call, writeline));
methodDefinition.Body.CilWorker.Append (methodDefinition.Body.CilWorker.Create(OpCodes.Ret))
assembly.MainModule.Inject(methodDefinition, assembly.MainModule.Types[typeName]);
MethodReference methodReference = null;
foreach (MethodDefinition method in assembly.MainModule.Types[typeName].Methods)
{
if (method.Name == methodName)
{
methodReference = assembly.MainModule.Import(method);
break;
}
}
Instruction callTest = methodDefinition.Body.CilWorker.Create(OpCodes.Call, methodReference);
if (assembly.EntryPoint != null)
{
assembly.EntryPoint.Body.CilWorker.InsertBefore(assembly.EntryPoint.Body.Instructions[0], callTest);
}
AssemblyFactory.SaveAssembly(assembly, assemblyFilename);
}
}
}
It's old sample. Most features are up to date. I'm interesting in this construction:
assembly.MainModule.Inject(methodDefinition, assembly.MainModule.Types[typeName]);
I could not find a new analogues of this design. Someone can tell me what it can be replaced?
I'm not familiar with the construct you are referring to, but adding a MethodDefinition to an existing type is quite easy
using (var assemblyDefinition = AssemblyDefinition.ReadAssembly("assemblyPath")) {
var module = AssemblyDefinition.MainModule;
//Select the type you need to open for addition
var typeDef = module.Types.First(td => td.Name == "footer");
//Add your MethodDefinition
typeDef.Methods.Add(your_method_definition);
//Write the assembly back
assemblyDefinition.Write();
}
NOTE: If you don't use yet cecil 0.10.0.0 you'll use slightly different ReadAssembly() and Write() variants (without the using, and passing the assemblyPath to Write, mainly...)
One can store in a read only field of a class using strfld op code in dynamic method if it has its owner set to that class and JIT checks are turned off. An example is here. This approach, however, failed to work with the class that comes from F#, namely FSharpOption. Please analyse an example below:
using Microsoft.FSharp.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
#if true
using MyType = Microsoft.FSharp.Core.FSharpOption<string>;
#else
using MyType = System.Tuple<string>;
#endif
namespace ConsoleApplication27
{
class Program
{
static void Main(string[] args)
{
var something = new MyType("test");
var dynMethod = new DynamicMethod("ChangeField", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(void), new [] { typeof(MyType) }, typeof(MyType), true);
var generator = dynMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldstr, "success");
generator.Emit(OpCodes.Stfld, typeof(MyType).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)[0]);
generator.Emit(OpCodes.Ret);
var method = (Action<MyType>) dynMethod.CreateDelegate(typeof(Action<MyType>));
method(something);
Console.WriteLine(typeof(MyType).GetProperties()[0].GetGetMethod().Invoke(something, new object[0]));
}
}
}
First of all, you have to reference FSharp.Core library to run it. Then, by changing #if true to #if false you can switch between writing a read only field fo Tuple and FSharpOption. For the former it works perfectly even though both have similar structure, that is a single read only field accessible via property. For the latter it causes verification failure. Why is that so?
Very very late response.
This is very odd.
By replacing the MyType with the module of the field type. it all starts to work
var dynMethod = new DynamicMethod("ChangeField", MethodAttributes.Public | MethodAttributes.Static,
CallingConventions.Standard, typeof(void), new[] {typeof(MyType)}, typeof(MyType), true);
Becomes:
var dynMethod = new DynamicMethod("ChangeField", MethodAttributes.Public | MethodAttributes.Static,
CallingConventions.Standard, typeof(void), new[] {typeof(MyType)}, typeof(string).Module, true);
That is:
typeof(MyType), true);
becomes
typeof(string).Module, true);
The type of the field being set is string so we take the module of that.
I would love to hear a better explanation on why this is.
The plot thickens
it turns out, that typeof(string).module makes it work for any type.
even if I define my own type like this:
using System;
using System.Reflection;
using System.Reflection.Emit;
#if true
using MyType = Microsoft.FSharp.Core.FSharpOption<string>;
#else
using MyType = System.Tuple<ConsoleApplication27.Poco>;
#endif
namespace ConsoleApplication27
{
public class Poco
{
}
class Program
{
static void Main(string[] args)
{
var something = new MyType(null);
var dynMethod = new DynamicMethod("ChangeField", MethodAttributes.Public | MethodAttributes.Static,
CallingConventions.Standard, typeof(void), new[] {typeof(MyType)}, typeof(string).Module, true);
var generator = dynMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Stfld,
typeof(MyType).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)[0]);
generator.Emit(OpCodes.Ret);
var method = (Action<MyType>) dynMethod.CreateDelegate(typeof(Action<MyType>));
method(something);
Console.WriteLine(typeof(MyType).GetProperties()[0].GetGetMethod().Invoke(something, new object[0]));
}
}
}
Now nothing makes sense. the FSharpOption type lives in the F# module.
The Poco class lives in my program module.
and still it all works when the module passed is the corelib module.
But not if I pass any of the two (above) that would make sense..
I want to create a program that produces an executable slideshow.
So I need it to output an EXE with some required code and certain embedded resources (pictures) in it.
Does .NET provide such capability?
You can use CSharpCodeProvider class to compile code at runtime and add embedded resources. Have a look at this article where I explain how to do it: SlideShow Builder
This is easy to accomplish.
You can add pictures as embedded resources and then use the technique of Reflection to discover and retrieve the embedded pictures.
So the program you write is independent of the list of pictures, which are just embedded resources. You can embed pictures as resources using Visual Studio, or create a custom program to do it.
You can find some examples at http://msdn.microsoft.com/en-us/library/aa287676(v=VS.71).aspx and http://www.java2s.com/Code/CSharp/Development-Class/Saveandloadimagefromresourcefile.htm.
Good luck!
Like what SK-Logic said there is
http://msdn.microsoft.com/en-us/library/system.reflection.emit.aspx
here is example of that
http://olondono.blogspot.com/2008/02/creating-code-at-runtime.html
You could also create a the project file and create the code files and use the Process class to call the compiler if you want help doing this I can give an example
this will generate a process for you with the specified name (you'll still need to add code for the pictures):
public static Process GenerateRuntimeProcess(string processName, int aliveDuration, bool throwOnException = true)
{
Process result = null;
try
{
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName() { Name = processName }, AssemblyBuilderAccess.Save);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(processName, processName + ".EXE");
TypeBuilder typeBuilder = moduleBuilder.DefineType("Program", TypeAttributes.Public);
MethodBuilder methodBuilder = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, null, null);
ILGenerator il = methodBuilder.GetILGenerator();
il.UsingNamespace("System.Threading");
il.EmitWriteLine("Hello World");
il.Emit(OpCodes.Ldc_I4, aliveDuration);
il.Emit(OpCodes.Call, typeof(Thread).GetMethod("Sleep", new Type[] { typeof(int) }));
il.Emit(OpCodes.Ret);
typeBuilder.CreateType();
assemblyBuilder.SetEntryPoint(methodBuilder.GetBaseDefinition(), PEFileKinds.ConsoleApplication);
assemblyBuilder.Save(processName + ".EXE", PortableExecutableKinds.Required32Bit, ImageFileMachine.I386);
result = Process.Start(new ProcessStartInfo(processName + ".EXE")
{
WindowStyle = ProcessWindowStyle.Hidden
});
}
catch
{
if (throwOnException)
{
throw;
}
result = null;
}
return result;
}
you can findmore info on System.Reflection.Emit on MSDN here or a tutorial here or here.
if I were you I'd also look into just using powerpoint and/or the viewer app and some command line options as detailed here. maybe you don't need to "make an app that makes another app that is a slideshow" at all..
I have a assembly. In this assembly I have a class and interface. I need to load this assembly at runtime and want to create an object of the class and also want to use the interface.
Assembly MyDALL = Assembly.Load("DALL"); // DALL is name of my dll
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // LoadClass is my class
object obj = Activator.CreateInstance(MyLoadClass);
This is my code. How could it be improved?
If your assembly is in GAC or bin use the assembly name at the end of type name instead of Assembly.Load().
object obj = Activator.CreateInstance(Type.GetType("DALL.LoadClass, DALL", true));
You should Use Dynamic Method with for Improving. its faster than reflection..
Here is a sample code for creating Object using Dynamic Method..
public class ObjectCreateMethod
{
delegate object MethodInvoker();
MethodInvoker methodHandler = null;
public ObjectCreateMethod(Type type)
{
CreateMethod(type.GetConstructor(Type.EmptyTypes));
}
public ObjectCreateMethod(ConstructorInfo target)
{
CreateMethod(target);
}
void CreateMethod(ConstructorInfo target)
{
DynamicMethod dynamic = new DynamicMethod(string.Empty,
typeof(object),
new Type[0],
target.DeclaringType);
ILGenerator il = dynamic.GetILGenerator();
il.DeclareLocal(target.DeclaringType);
il.Emit(OpCodes.Newobj, target);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
}
public object CreateInstance()
{
return methodHandler();
}
}
//Use Above class for Object Creation.
ObjectCreateMethod inv = new ObjectCreateMethod(type); //Specify Type
Object obj= inv.CreateInstance();
This method takes only 1/10th time needed by Activator.
Check out http://www.ozcandegirmenci.com/post/2008/02/Create-object-instances-Faster-than-Reflection.aspx
Check out http://www.youtube.com/watch?v=x-KK7bmo1AM
To modify his code to load multiple assemblies use
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string assemblyName = args.Name.Split(',').First();
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("YourNamespace." + assemblyName + ".dll"))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
In your main method put
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Be sure to add your assemblies to your project and change the build action property to "Embedded Resource".