mirror of https://github.com/dahall/Vanara.git
101 lines
4.7 KiB
C#
101 lines
4.7 KiB
C#
using ICSharpCode.Decompiler;
|
|
using ICSharpCode.Decompiler.CSharp;
|
|
using ICSharpCode.Decompiler.TypeSystem;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace Vanara.PInvoke.Tests
|
|
{
|
|
public static class CSharpRunner
|
|
{
|
|
private static IEnumerable<string> StdRefs => new[] { typeof(object).Assembly.Location, typeof(Enumerable).Assembly.Location };
|
|
|
|
public static object Run(string snippet, IEnumerable<string> references, string typeName, string methodName, params object[] args) =>
|
|
Invoke(CompileLib(Parse(snippet), references), typeName, methodName, args);
|
|
|
|
public static object Run(MethodInfo methodInfo, params object[] args) =>
|
|
Invoke(CompileLib(Decompile(methodInfo.DeclaringType), methodInfo.DeclaringType.GetReferencedAssemblyNames()), methodInfo.DeclaringType.FullName, methodInfo.Name, args);
|
|
|
|
public static Process RunProcess<T>(string args = null) where T : class => RunProcess(typeof(T), args);
|
|
|
|
public static Process RunProcess(Type mainType, string args = null)
|
|
{
|
|
if (mainType.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) is null)
|
|
throw new ArgumentException("Supplied type must include a static Main method.");
|
|
var exe = Path.Combine(Path.GetDirectoryName(mainType.Assembly.Location), "tmp" + Guid.NewGuid().ToString("N") + ".exe");
|
|
CompileExe(exe, Decompile(mainType), mainType.GetReferencedAssemblyNames(), mainType.FullName);
|
|
return CreateProcess(exe, args, Path.GetDirectoryName(mainType.Assembly.Location));
|
|
}
|
|
|
|
public static Process RunProcess(string snippet, string workingDir, IEnumerable<string> references = null, string typeName = null, string args = null)
|
|
{
|
|
var exe = Path.Combine(workingDir, "tmp" + Guid.NewGuid().ToString("N") + ".exe");
|
|
CompileExe(exe, Parse(snippet), references, typeName);
|
|
return CreateProcess(exe, args, workingDir);
|
|
}
|
|
|
|
private static void CompileExe(string outputExePath, SyntaxTree syntaxTree, IEnumerable<string> references = null, string mainTypeName = null)
|
|
{
|
|
var mrefs = (references ?? StdRefs).Select(a => MetadataReference.CreateFromFile(a));
|
|
var opts = new CSharpCompilationOptions(OutputKind.ConsoleApplication, allowUnsafe: true, mainTypeName: mainTypeName);
|
|
var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), new[] { syntaxTree }, mrefs, opts);
|
|
var result = compilation.Emit(outputExePath);
|
|
if (!result.Success)
|
|
{
|
|
throw new InvalidOperationException(string.Join("\n", result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error).Select(d => $"{d.Id}: {d.GetMessage()}")));
|
|
}
|
|
}
|
|
|
|
private static Assembly CompileLib(SyntaxTree syntaxTree, IEnumerable<string> references = null)
|
|
{
|
|
var mrefs = (references ?? StdRefs).Select(a => MetadataReference.CreateFromFile(a));
|
|
var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), new[] { syntaxTree }, mrefs, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
|
|
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
var result = compilation.Emit(ms);
|
|
if (result.Success)
|
|
{
|
|
ms.Seek(0, SeekOrigin.Begin);
|
|
return Assembly.Load(ms.ToArray());
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException(string.Join("\n", result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error).Select(d => $"{d.Id}: {d.GetMessage()}")));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Process CreateProcess(string exe, string args, string workingDir)
|
|
{
|
|
var p = new Process { StartInfo = new ProcessStartInfo(exe, args) { WorkingDirectory = workingDir } };
|
|
p.Exited += (s, e) => File.Delete(exe);
|
|
p.Start();
|
|
return p;
|
|
}
|
|
|
|
private static SyntaxTree Decompile(Type type)
|
|
{
|
|
var decompiler = new CSharpDecompiler(type.Assembly.Location, new DecompilerSettings());
|
|
var typeInfo = decompiler.TypeSystem.MainModule.Compilation.FindType(type).GetDefinition();
|
|
return Parse(decompiler.DecompileTypeAsString(typeInfo.FullTypeName));
|
|
}
|
|
|
|
private static IEnumerable<string> GetReferencedAssemblyNames(this Type type) => type.Assembly.GetReferencedAssemblies().Select(n => Assembly.Load(n).Location);
|
|
|
|
private static object Invoke(Assembly assembly, string typeName, string methodName, object[] args)
|
|
{
|
|
var type = assembly.GetType(typeName);
|
|
var obj = Activator.CreateInstance(type);
|
|
return type.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, args);
|
|
}
|
|
|
|
private static SyntaxTree Parse(string snippet) => CSharpSyntaxTree.ParseText(snippet);
|
|
}
|
|
} |