How do I invoke .getmethodinfo? - c#

I have recently started to read how a open source encryption program works.
The problem is, I'm stuck here on these 2 lines of code which I can't understand at all, I have looked at MSDN but it doesn't help me at all to understand what these 2 lines do.
MethodInfo run = Assembly.Load(InjRes).GetType("Resource.reflect").GetMethod("Run");
bool inj = (bool)run.Invoke(null, new object[] { Assembly.GetExecutingAssembly().Location, "", PayloadRes, false });
I'm also trying to figure out another way to accomplish the same thing, is there a way to invoke the .GetMethod?

This is fairly basic "reflection" in .NET.
Basically what happens here is:
Loads a .NET assembly as indicated by InjRes
Inside that assembly, get the type definition for Resource.reflect (which is probably a class)
Inside the Resource.reflect type, get the Run method and save it to variable run
Invoke (in other works, "execute") the Run() function on a null instance (which means Run() is probably a static method) with the parameters (Assembly.GetExecutingAssembly().Location, "", PayloadRes, false)
More simply, these lines would translate to "regular old C#" that looks like:
bool inj = Resource.reflect.Run(Assembly.GetExecutingAssembly().Location, "", PayloadRes, false);
but the original author probably couldn't have just written the simple 1 line above because either:
The assembly wasn't referenced at build-time, so the compiler doesn't know about the Resouce namespace so would have thrown a compile error
or the Resouce.reflect class or the Run method isn't public so couldn't have been called normally. Reflection can bypass this limitation.

Related

Runtime error "parameter mismatch" using CallByName and Invoke

I've deleted my first attempt at asking this question, as I wasn't quite up to speed on the semantics. Now I'm not much better. Basically here's the issue. I have a small block of online demo code that I'm analyzing that is showing how to access assembly-related functions in VB from C#. Basically loading and executing an assembly in C# using CallbyName to VB functions. Here is the relevant code, with all variables defined:
// the only non-default usings for this code are:
using Microsoft.VisualBasic;
using System.Reflection;
private void Form1_Load(object sender, EventArgs e)
{
string exefile = Properties.Resources.binaryfile;
// Convert base64 to bytes
byte[] exe_bytes = Convert.FromBase64String(exefile);
// okay, the load call takes as an argument the byte array exe_bytes,
// this makes sense
object loaded = Interaction.CallByName(AppDomain.CurrentDomain, "load",CallType.Method, exe_bytes);
// next, the entrypoint is taken from the loaded assembly, and
// passed to the object entry
object entry = Interaction.CallByName(loaded, "entrypoint", CallType.Get);
// finally, invoke is called to execute it, being passed the
// entrypoint. But what are the null, null for? This seems
// to be what is throwing the runtime error.
object invocation = Interaction.CallByName(entry, "invoke", CallType.Method, null, null);
Okay, let me stop here to note a few things. This builds successfully in C# (.NET 4.5), but throws a runtime error for parameter mismatch at the invocation line. It seems to me from looking at the code that someone just put that into three separate lines (load,entrypoint,invoke) to demonstrate what they were doing, as we could substitute object definitions to create one line. I add and subtract "nulls" from the 2 listed, and the error message remains, either saying it doesn't take 3 arguments, or that I erroneously have no arguments.
In my previous ask of the question a few hours ago, a helpful post suggested that I (quoting) "load the assembly (Reflection.Assembly.Load) and then inspect the parameters on the Assembly.EntryPoint property (MethodInfo) by calling its GetParameters method. Once you know what you are dealing with, then you can play with CallByName to start it." (credit to user TnTinMn)
So after about two hours of reading online docs with sparse examples, I've come up with only this line:
object loaded = System.Reflection.Assembly.Load(exe_bytes);
to replace the loaded definition in the code. After that, I have absolutely no idea what I am reading or doing! Assembly.Entrypoint, GetParameters, MethodInfo, oh my! Basically, I just want "how many parameters do you need? please print to console!" translated into C# .NET OO speak. Because I am utterly lost. Thank you!
The above seemed a good start, but alternative courses to a solution are certainly welcome. If you can, please please provide code in your answer, as my ability translating tasks from concept to OO programming is noticeably deficient.
EDIT: This may be relevant for examining the number of parameters?
MethodInfo[] methods = BUT_WHAT_OBJECT_GOES_HERE.GetMethods();
foreach (MethodInfo info in methods)
{
Console.WriteLine(info.Name);
}
In the example I took the code from, the object for the method GetMethods was a Program class. I tried using the assembly object exefile and it won't take it.

Get method body c#

I am trying to write a custom rule (code analysis) where, if the body of a method contains empty statements, an error is raised.
However, there is one problem. I can not seem to figure out how to get the body of a method (the text that is in the method).
How can I get the text inside a method, and assign it to a string?
Thanks in advance.
For reference; I use c# in visual studio, with FxCop to make the rule.
Edit: Some code added for reference, this does NOT work.
using Microsoft.FxCop.Sdk;
using Microsoft.VisualStudio.CodeAnalysis.Extensibility;
public override ProblemCollection Check(Member member)
{
Method method = member as Method;
if (method == null)
{
return null;
}
if (method.Name.Name.Contains("{}"))
{
var resolution = GetResolution(member.Name.Name);
var problem = new Problem(resolution, method)
{
Certainty = 100,
FixCategory = FixCategories.Breaking,
MessageLevel = MessageLevel.Warning
};
Problems.Add(problem);
}
return Problems;
}
FxCop doesn't analyse source code, it works on .Net assemblies built from any language.
You may be able to find whether the method contains a statement or not using FxCop, I advice you to read the documentation and check the implementation of existing rules to understand it.
An empty statement in the middle of other code might be removed by the compiler and you may not find it using FxCop. If you want to analyze source code you should take a look at StyleCop.
However, there is one problem. I can not seem to figure out how to get the body of a method
(the text that is in the method).
You can not. FxCop does not work based on the source, but analysis the compiled bytecode.
What you can do is find the source - which is not totally trivial - but you have to do so without the FxCop API. A start point may be analysing the pdb files (not sure where to find documentation) as they can point you to the file that contains the method.

CS-Script Evaluator LoadCode: How to compile and reference a second script (reusable library)

The question in short is: How do you reference a second script containing reusable script code, under the constraints that you need to be able to unload and reload the scripts when either of them changes without restarting the host application?
I'm trying to compile a script class using the CS-Script "compiler as service" (CSScript.Evaluator), while referencing an assembly that has just been compiled from a second "library" script. The purpose is that the library script should contain code that can be reused for different scripts.
Here is a sample code that illustrates the idea but also causes a CompilerException at runtime.
using CSScriptLibrary;
using NUnit.Framework;
[TestFixture]
public class ScriptReferencingTests
{
private const string LibraryScriptCode = #"
public class Helper
{
public static int AddOne(int x)
{
return x + 1;
}
}
";
private const string ScriptCode = #"
using System;
public class Script
{
public int SumAndAddOne(int a, int b)
{
return Helper.AddOne(a+b);
}
}
";
[Test]
public void CSScriptEvaluator_CanReferenceCompiledAssembly()
{
var libraryEvaluator = CSScript.Evaluator.CompileCode(LibraryScriptCode);
var libraryAssembly = libraryEvaluator.GetCompiledAssembly();
var evaluatorWithReference = CSScript.Evaluator.ReferenceAssembly(libraryAssembly);
dynamic scriptInstance = evaluatorWithReference.LoadCode(ScriptCode);
var result = scriptInstance.SumAndAddOne(1, 2);
Assert.That(result, Is.EqualTo(4));
}
}
To run the code you need NuGet packages NUnit and cs-script.
This line causes a CompilerException at runtime:
dynamic scriptInstance = evaluatorWithReference.LoadCode(ScriptCode);
{interactive}(7,23): error CS0584: Internal compiler error: The invoked member is not supported in a dynamic assembly.
{interactive}(7,9): error CS0029: Cannot implicitly convert type '<fake$type>' to 'int'
Again, the reason for using CSScript.Evaluator.LoadCode instead of CSScript.LoadCode is so that the script can be reloaded at any time without restarting the host application when either of the scripts changes. (CSScript.LoadCode already supports including other scripts according to http://www.csscript.net/help/Importing_scripts.html)
Here is the documentation on the CS-Script Evaluator: http://www.csscript.net/help/evaluator.html
The lack of google results for this is discouraging, but I hope I'm missing something simple. Any help would be greatly appreciated.
(This question should be filed under the tag cs-script which does not exist.)
There is some slight confusion here. Evaluator is not the only way to achieve reloadable script behavior. CSScript.LoadCode allows reloading as well.
I do indeed advise to consider CSScript.Evaluator.LoadCode as a first candidate for the hosting model as it offers less overhead and arguably more convenient reloading model. However it comes with the cost. You have very little control over reloading and dependencies inclusion (assemblies, scripts). Memory leaks are not 100% avoidable. And it also makes script debugging completely impossible (Mono bug).
In your case I would really advice you to move to the more conventional hosting model: CodeDOM.
Have look at "[cs-script]\Samples\Hosting\CodeDOM\Modifying script without restart" sample.
And "[cs-script]\Samples\Hosting\CodeDOM\InterfaceAlignment" will also give you an idea how to use interfaces with reloading.
CodeDOM was for years a default CS-Script hosting mode and it is in fact very robust, intuitive and manageable. The only real drawback is the fact that all object you pass to (or get from) the script will need to be serializable or inherited from MarshalByRef. This is the side effect of the script being executed in the "automatic" separate domain. Thus one have to deal with the all "pleasures" of Remoting.
BTW this is the only reason why I implemented Mono-based evaluator.
CodeDOM model will also automatically manage the dependencies and recompile them when needed. But it looks like you are aware about this anyway.
CodeDOM also allows you to define precisely the mechanism of checking dependencies for changes:
//the default algorithm "recompile if script or dependency is changed"
CSScript.IsOutOfDateAlgorithm = CSScript.CachProbing.Advanced;
or
//custom algorithm "never recompile script"
CSScript.IsOutOfDateAlgorithm = (s, a) => false;
The quick solution to the CompilerException appears to be not use Evaluator to compile the assembly, but instead just CSScript.LoadCode like so
var compiledAssemblyName = CSScript.CompileCode(LibraryScriptCode);
var evaluatorWithReference = CSScript.Evaluator.ReferenceAssembly(compiledAssemblyName);
dynamic scriptInstance = evaluatorWithReference.LoadCode(ScriptCode);
However, as stated in previous answer, this limits the possibilities for dependency control that the CodeDOM model offers (like css_include). Also, any change to the LibraryScriptCode are not seen which again limits the usefulness of the Evaluator method.
The solution I chose is the AsmHelper.CreateObject and AsmHelper.AlignToInterface<T> methods. This lets you use the regular css_include in your scripts, while at the same time allowing you at any time to reload the scripts by disposing the AsmHelper and starting over. My solution looks something like this:
AsmHelper asmHelper = new AsmHelper(CSScript.Compile(filePath), null, false);
object obj = asmHelper.CreateObject("*");
IMyInterface instance = asmHelper.TryAlignToInterface<IMyInterface>(obj);
// Any other interfaces you want to instantiate...
...
if (instance != null)
instance.MyScriptMethod();
Once a change is detected (I use FileSystemWatcher), you just call asmHelper.Dispose and run the above code again.
This method requires the script class to be marked with the Serializable attribute, or simply inherit from MarshalByRefObject.
Note that your script class does not need to inherit any interface. The AlignToInterface works both with and without it. You could use dynamic here, but I prefer having a strongly typed interface to avoid errors down the line.
I couldn't get the built in try-methods to work, so I made this extension method for less clutter when it is not known whether or not the interface is implemented:
public static class InterfaceExtensions
{
public static T TryAlignToInterface<T>(this AsmHelper helper, object obj) where T : class
{
try
{
return helper.AlignToInterface<T>(obj);
}
catch
{
return null;
}
}
}
Most of this is explained in the hosting guidelines http://www.csscript.net/help/script_hosting_guideline_.html, and there are helpful samples mentioned in previous post.
I feel I might have missed something regarding script change detection, but this method works solidly.

How to access variables in Windows Workflow in VB expressions constructed at runtime

I hope I'm not being misguided in trying to do this, but I'd like to set the VB expression for an InArgument in Windows Workflow at runtime and have it access variables that are currently in scope.
In particular, I'd like to change the following bit of example code to say new VisualBasicValue<string>("String.Format(\"Hello {0}\", FirstName) - that is, I'd like to stop specifying the explicit string "World" and start passing in a name to the workflow from Main. I add a new InArgument called FirstName to the workflow itself, and then try and access it as above, but it doesn't work - I'm guessing because it doesn't know what FirstName is referring to at the point at which it compiles the expression. Please do you know of an alternative way to accomplish the same goal?
(The context for this problem is that I'm writing code to run different types of calculation. A calculation takes a string parameter that contains a VB expression that must be run to get some data from one of a variety of different locations. I want to specify the VB expression for each different calculation type in a .config file, then evaluate those expressions "on-the-fly" at runtime when it becomes necessary to run the various different calculations.)
using System.Activities;
using Microsoft.VisualBasic.Activities;
namespace SMG_RuntimeExpressionTest
{
class Program
{
static void Main(string[] args)
{
var wf = new Workflow();
wf.Text = new VisualBasicValue<string>("String.Format(\"Hello {0}\", \"World\")");
WorkflowInvoker.Invoke(wf);
}
}
}
I've got a couple of blog posts on arguments WF4: Passing Arguments to Activities and Passing arguments to Workflow Activities (again) that might help you.

Passing a lambda to a secondary AppDomain as a stream of IL and assembling it back using DynamicMethod

Is it possible to pass a lambda expression to a secondary AppDomain as a stream of IL bytes and then assemble it back there using DynamicMethod so it can be called?
I'm not too sure this is the right way to go in the first place, so here's the (detailed) reason I ask this question...
In my applications, there are a lot of cases when I need to load a couple of assemblies for reflection, so I can determine what to do with them next. The problem part is I need to be able to unload the assemblies after I'm finished reflecting over them. This means I need to load them using another AppDomain.
Now, most of my cases are sort of similar, except not quite. For example, sometimes I need to return a simple confirmation, other times I need to serialize a resource stream from the assembly, and again other times I need to make a callback or two.
So I end up writing the same semi-complicated temporary AppDomain creation code over and over again and implementing custom MarshalByRefObject proxies to communicate between the new domain and the original one.
As this is not really acceptable anymore, I decided to code me an AssemblyReflector class that could be used this way:
using (var reflector = new AssemblyReflector(#"C:\MyAssembly.dll"))
{
bool isMyAssembly = reflector.Execute(assembly =>
{
return assembly.GetType("MyAssembly.MyType") != null;
});
}
AssemblyReflector would automize the AppDomain unloading by virtue of IDisposable, and allow me to execute a Func<Assembly,object>-type lambda holding the reflection code in another AppDomain transparently.
The problem is, lambdas cannot be passed to other domains so simply. So after searching around, I found what looks like a way to do just that: pass the lambda to the new AppDomain as an IL stream - and that brings me to the original question.
Here's what I tried, but didn't work (the problem was BadImageFormatException being thrown when trying to call the new delegate):
public delegate object AssemblyReflectorDelegate(Assembly reflectedAssembly);
public class AssemblyReflector : IDisposable
{
private AppDomain _domain;
private string _assemblyFile;
public AssemblyReflector(string fileName) { ... }
public void Dispose() { ... }
public object Execute(AssemblyReflectorDelegate reflector)
{
var body = reflector.Method.GetMethodBody();
_domain.SetData("IL", body.GetILAsByteArray());
_domain.SetData("MaxStackSize", body.MaxStackSize);
_domain.SetData("FileName", _assemblyFile);
_domain.DoCallBack(() =>
{
var il = (byte[])AppDomain.CurrentDomain.GetData("IL");
var stack = (int)AppDomain.CurrentDomain.GetData("MaxStackSize");
var fileName = (string)AppDomain.CurrentDomain.GetData("FileName");
var args = Assembly.ReflectionOnlyLoadFrom(fileName);
var pars = new Type[] { typeof(Assembly) };
var dm = new DynamicMethod("", typeof(object), pars,
typeof(string).Module);
dm.GetDynamicILInfo().SetCode(il, stack);
var clone = (AssemblyReflectorDelegate)dm.CreateDelegate(
typeof(AssemblyReflectorDelegate));
var result = clone(args); // <-- BadImageFormatException thrown.
AppDomain.CurrentDomain.SetData("Result", result);
});
// Result obviously needs to be serializable for this to work.
return _domain.GetData("Result");
}
}
Am I even close (what's missing?), or is this a pointless excercise all in all?
NOTE: I realize that if this worked, I'd still have to be carefull about what I put into lambda in regard to references. That's not a problem, though.
UPDATE: I managed to get a little further. It seems that simply calling SetCode(...) is not nearly enough to reconstruct the method. Here's what's needed:
// Build a method signature. Since we know which delegate this is, this simply
// means adding its argument types together.
var builder = SignatureHelper.GetLocalVarSigHelper();
builder.AddArgument(typeof(Assembly), false);
var signature = builder.GetSignature();
// This is the tricky part... See explanation below.
di.SetCode(ILTokenResolver.Resolve(il, di, module), stack);
dm.InitLocals = initLocals; // Value gotten from original method's MethodInfo.
di.SetLocalSignature(signature);
The trick is as follows. Original IL contains certain metadata tokens which are valid only in the context of the original method. I needed to parse the IL and replace those tokens with ones that are valid in the new context. I did this by using a special class, ILTokenResolver, which I adapted from these two sources: Drew Wilson and Haibo Luo.
There is still a small problem with this - the new IL doesn't seem to be exactly valid. Depending on the exact contents of the lambda, it may or may not throw an InvalidProgramException at runtime.
As a simple example, this works:
reflector.Execute(a => { return 5; });
while this doesn't:
reflector.Execute(a => { int a = 5; return a; });
There are also more complex examples that are either working or not, depending on some yet-to-be-determined difference. It could be I missed some small but important detail. But I'm reasonably confident I'll find it after a more detailed comparison of the ildasm outputs. I'll post my findings here, when I do.
EDIT: Oh, man. I completely forgot this question was still open. But as it probably became obvious in itself, I gave up on solving this. I'm not happy about it, that's for sure. It's really a shame, but I guess I'll wait for better support from the framework and/or CLR before I attempt this again. There're just to many hacks one has to do to make this work, and even then it's not reliable. Apologies to everyone interested.
I didn't get exactly what is the problem you are trying to solve, but I made a component in the past that may solve it.
Basically, its purpose was to generate a Lambda Expression from a string. It uses a separate AppDomain to run the CodeDOM compiler. The IL of a compiled method is serialized to the original AppDomain, and then rebuild to a delegate with DynamicMethod. Then, the delegate is called and an lambda expression is returned.
I posted a full explanation of it on my blog. Naturally, it's open source. So, if you get to use it, please send me any feedback you think is reasonable.
Probably not, because a lambda is more than just an expression in source code. lambda expressions also create closures which capture/hoist variables into their own hidden classes. The program is modified by the compiler so everywhere you use those variables you're actually talking to the class. So you'd have to not only pass the code for the lambda, but also any changes to closure variables over time.

Categories

Resources