Contemporary Carte de Visite

#

Listato S7

Classe statica per la compilazione a run-time
 
// copyright (c) 2020-2023 Roberto Ceccarelli - Casasoft
// http://strawberryfield.altervista.org
//
// This file is part of Casasoft Contemporary Carte de Visite Tools
// https://github.com/strawberryfield/Contemporary_CDV
//
// Casasoft CCDV Tools is free software:
// you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Casasoft CCDV Tools is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU AGPL v.3
// along with Casasoft CCDV Tools.  
// If not, see <http://www.gnu.org/licenses/>.

using Casasoft.CCDV.Engines;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Casasoft.CCDV.Scripting;

/// <summary>
/// c# scripts compiler
/// </summary>
public static class Compiler
{
    /// <summary>
    /// Compile the source code to a memory assembly
    /// </summary>
    /// <param name="sourceCode"></param>
    /// <returns>null if any compilation error</returns>
    public static Assembly Compile(string sourceCode)
    {
        MemoryStream ms = new();

        // define other necessary objects for compilation
        string assemblyName = Path.GetRandomFileName();

        string ExeFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
        string WorkPath = System.IO.Path.GetDirectoryName(ExeFilePath);

        MetadataReference[] references = new MetadataReference[]
        {
            MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
            MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Linq.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Linq.Expressions.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Linq.Queryable.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Core.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Runtime.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Runtime.Loader.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Console.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Collections.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Collections.Concurrent.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("System.Memory.dll")),
            MetadataReference.CreateFromFile(FromTrustedPlatformAssembly("netstandard.dll")),
            MetadataReference.CreateFromFile(Path.Combine(WorkPath, "Magick.NET-Q16-AnyCPU.dll")),
            MetadataReference.CreateFromFile(Path.Combine(WorkPath, "Magick.NET.Core.dll")),
            MetadataReference.CreateFromFile(Path.Combine(WorkPath, "Casasoft.CCDV.Common.dll"))
        };

        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);
        // analyse and generate IL code from syntax tree
        CSharpCompilation compilation = CSharpCompilation.Create(
            assemblyName,
            syntaxTrees: new[] { syntaxTree },
            references: references,
            options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

        // write IL code into memory
        EmitResult result = compilation.Emit(ms);

        if (!result.Success)
        {
            // handle exceptions
            IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                diagnostic.IsWarningAsError ||
                diagnostic.Severity == DiagnosticSeverity.Error);

            foreach (Diagnostic diagnostic in failures)
            {
                Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
            }
            return null;
        }

        // load this 'virtual' DLL so that we can use
        ms.Seek(0, SeekOrigin.Begin);
        return Assembly.Load(ms.ToArray());
    }

    /// <summary>
    /// Execute the code
    /// </summary>
    /// <param name="assembly">Memory assembly with compiled code</param>
    /// <param name="ClassName">Fully qualified class name</param>
    /// <param name="Method">Method to execute</param>
    /// <param name="args">Array of arguments</param>
    /// <param name="eng">Engine passed to constructor</param>
    public static object Run(Assembly assembly, string ClassName, string Method, object[] args, IEngine eng)
    {
        // create instance of the desired class and call the desired function
        Type type = assembly.GetType(ClassName);
        if (type is not null && type.GetMethod(Method) is not null)
        {
            object obj = Activator.CreateInstance(type, new object[] { eng });
            return type.InvokeMember(Method,
                BindingFlags.Default | BindingFlags.InvokeMethod,
                null,
                obj,
                args);
        }
        else return null;
    }

    /// <summary>
    /// Executes a method of an istanced object
    /// </summary>
    /// <param name="obj">instance</param>
    /// <param name="Method">Method to execute</param>
    /// <param name="args">Array of arguments</param>
    /// <returns></returns>
    public static object Run(object obj, string Method, object[] args)
    {
        Type type = obj.GetType();
        if (type is not null && type.GetMethod(Method) is not null)
        {

            return type.InvokeMember(Method,
            BindingFlags.Default | BindingFlags.InvokeMethod,
            null,
            obj,
            args);
        }
        else
            return null;
    }

    /// <summary>
    /// Execute the code in the Casasoft.CCDV.Scripts.UserScript class
    /// </summary>
    /// <param name="assembly">Memory assembly with compiled code</param>
    /// <param name="Method">Method to execute</param>
    /// <param name="args">Array of arguments</param>
    /// <param name="eng">Engine passed to constructor</param>
    public static object Run(Assembly assembly, string Method, object[] args, IEngine eng) =>
        Run(assembly, "Casasoft.CCDV.Scripts.UserScript", Method, args, eng);

    /// <summary>
    /// Creates an istance of the class
    /// </summary>
    /// <param name="assembly">Memory assembly with compiled code</param>
    /// <param name="ClassName">Fully qualified class name</param>
    /// <param name="eng">Engine passed to constructor</param>
    /// <returns></returns>
    public static object New(Assembly assembly, string ClassName, IEngine eng)
    {
        Type type = assembly.GetType(ClassName);
        if (type is not null)
        {
            return Activator.CreateInstance(type, new object[] { eng });
        }
        else return null;
    }

    /// <summary>
    /// Creates an istance of the Casasoft.CCDV.Scripts.UserScript class
    /// </summary>
    /// <param name="assembly">Memory assembly with compiled code</param>
    /// <param name="eng">Engine passed to constructor</param>
    /// <returns></returns>
    public static object New(Assembly assembly, IEngine eng) =>
        New(assembly, "Casasoft.CCDV.Scripts.UserScript", eng);

    /// <summary>
    /// Gets the dll complete path
    /// </summary>
    /// <param name="shortDllName"></param>
    /// <returns></returns>
    public static string FromTrustedPlatformAssembly(string shortDllName)
    {
        string dllString = AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES").ToString();
        var dlls = dllString.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
        return dlls.Single(d => d.Contains(shortDllName, StringComparison.OrdinalIgnoreCase));
    }

    /// <summary>
    /// Using declarations to be included in scripts
    /// </summary>
    public static string Usings => @"
using Casasoft.CCDV;
using Casasoft.CCDV.Engines;
using Casasoft.CCDV.JSON;
using ImageMagick;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
"
;


}
 
Inizio pagina
 
Home page