1

I am trying to execute cs scripts in a directory a loop. Every time the script changed (or if it's new) it gets loaded and executed. But I receive an error on trying to load the script a second time:

Access to the path 'C:\Users\Admin\AppData\Local\Temp\CSSCRIPT\Cache\647885655\hello.cs.compiled' is denied.

What I tried to do was:

static Dictionary<string, string> mFilePathFileHashes = new Dictionary<string, string>();
public static void LoadFromDir(string dir)
{
    foreach (string filepath in Directory.GetFiles(dir))
    {
        string hash = GetMD5HashFromFile(filepath); //Generate file hash
        if (mFilePathFileHashes.Contains(new KeyValuePair<string, string>(filepath, hash))) continue; //Skip if it hasn't changed

        if (mFilePathFileHashes.ContainsKey(filepath))
        { //Hash changed
            mFilePathFileHashes[filepath] = hash;
        }
        else //This is the first time this file entered the loop
            mFilePathFileHashes.Add(filepath, hash);

        //Load the script
        IScript script = CSScript.Load(filepath)
                            .CreateInstance("Script")
                            .AlignToInterface<IScript>();

        //Do stuff
        script.AddUserControl();
    }

protected static string GetMD5HashFromFile(string fileName)
{
    FileStream file = new FileStream(fileName, FileMode.Open);
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] retVal = md5.ComputeHash(file);
    file.Close();

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < retVal.Length; i++)
    {
        sb.Append(retVal[i].ToString("x2"));
    }
    return sb.ToString();
}

At the "Load the script" part it would throw the error. So I read up on it a bit and tried this:

//Load the script
string asmFile = CSScript.Compile(filepath, null, false);
using (AsmHelper helper = new AsmHelper(asmFile, "temp_dom_" + Path.GetFileName(filepath), true))
{
    IScript script = helper.CreateAndAlignToInterface<IScript>("Script");
    script.AddUserControl();

    //helper.Invoke("Script.AddUserControl");
}

Because that page said Script is loaded in the temporary AppDomain and unloaded after the execution. To set up the AsmHelper to work in this mode instantiate it with the constructor that takes the assembly file name as a parameter

But that won't Align to the interface : Type 'Script' in Assembly 'hello.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. What does that even mean, and why would it need to be serializable?

If I switch to the helper.Invoke line instead I get a NullReferenceException.

The script:

using System;
using System.Windows.Forms;
using CSScriptTest;

class Script : CSScriptTest.IScript
{ 
    public void AddUserControl()
    {
        Form1.frm.AddUserControl1(this, "test_uc_1");
    }
} 

So that last error may be because I never actually Aligned to an interface, or because I am calling a static method from outside of the main AppDomain (I really wouldn't know).

Is there any way to get this working?

4

1 回答 1

0

好吧,它通过将我想要操作的对象传递给接口的方法来工作,如下所示:

using (var helper = new AsmHelper(CSScript.Compile(filepath), null, false))
{
    IScript script = helper.CreateAndAlignToInterface<IScript>("Script");
    script.AddUserControl(Form1.frm);
}

使用这样的脚本继承MarshalByRefObject

using System;
using System.Windows.Forms;
using CSScriptTest;

class Script : MarshalByRefObject, CSScriptTest.IScript
{ 
    public void AddUserControl(CSScriptTest.Form1 host)
    {
        host.AddUserControl1(this, "lol2");
    }
}

MSDN saisMarshalByRefObject Enables access to objects across application domain boundaries in applications that support remoting.所以我想这是有道理的.. 但是有什么方法可以让我将主要应用程序的方法暴露给脚本?

MarshalByRefObject通过在主程序中继承似乎不可能,如下所示:

public class CTestIt : MarshalByRefObject
{
    public static CTestIt Singleton;
    internal static void SetSingleton()
    { //This method is successfully executed before we start loading scripts
        Singleton = new CTestIt();
        Console.WriteLine("CTestIt Singleton set"); 
    }

    public static void test()
    {
       //Null reference when a script calls CSScriptTest.CTestIt.test();
        Singleton.test_member(); 
    }

    public void test_member()
    {
        Console.WriteLine("test");
    }
}
于 2012-10-17T19:33:56.447 回答