This project has moved. For the latest updates, please go here.

add function to scriptengine

Apr 15, 2015 at 4:18 PM
hi,

i want to add an unknowned function from dll to the scriptengine.

ive loaded the methodinfo. How can i add the methodinfo to the scriptengine to use it like a real function?
Coordinator
Apr 15, 2015 at 7:26 PM
Hi furesoft,

Let's look at an example. Suppose you have a .NET class:
public class Foo {
    public string Method(int a, double b, string c) {
        return string.Format("{0} {1} {2}", a, b, c);
    }
}
Suppose also that you have a MethodInfo for one of its methods:
var method = typeof(Foo).GetMethod("Method");
To allow script code to use the MethodInfo easily, first declare a universal method delegate type:
public delegate object MethodFunc(object target, params object[] args);
Now expose a delegate that invokes the MethodInfo:
engine.Script.func = new MethodFunc(method.Invoke);
And now you can do something like this:
engine.AddHostType("Foo", typeof(Foo));
Console.WriteLine(engine.Evaluate("func(new Foo(), 123, Math.PI, 'blah')"));
Good luck!
Apr 15, 2015 at 7:43 PM
Edited Apr 15, 2015 at 7:58 PM
thanks but it desnt work correctly.

i use this:
var mf = new MethodFunc(me.Invoke);
se.AddHostObject(mi.Name, mf);
it throws an Comexception when i run the script who is calling the function via:
 var host = new HostFunctions();
                ((IScriptableObject)host).OnExposedToScriptCode(e);
                var del = (Delegate)host.func<object>(p.Length, e.Script[func]);

                return del.DynamicInvoke(p); // here is the Exception
return filesize("Std.dll");
Coordinator
Apr 15, 2015 at 8:11 PM
Hi again,

Can you provide more information? The two code blocks above appear to be unrelated, with several variables that aren't defined anywhere (mi, func, p).

If you could post a complete test program that demonstrates the problem, that would be perfect!

Thanks!
Apr 15, 2015 at 8:14 PM
Edited Apr 15, 2015 at 8:14 PM
public static class ModuleLoader
    {
        public delegate object MethodFunc(object target, params object[] args);

        public static void Load(WindowsScriptEngine se, Type t)
        {
            var ca = t.GetCustomAttribute<ScriptModuleAttribute>();

            var tmp = Activator.CreateInstance(t);

            if (ca != null)
            {
                if (ca.AsType)
                {
                    se.AddHostType(ca.Name != null ? ca.Name : t.Name, t);
                }
                foreach (var me in t.GetMethods())
                {
                    var meca = me.GetCustomAttribute<ScriptFunctionAttribute>();
                    if (meca != null)
                    {
                        var mf = new MethodFunc(me.Invoke);
                        se.AddHostObject(meca.Name != null ? meca.Name : me.Name, mf);
                    }
                }
            }
            foreach (var me in t.GetProperties())
            {
                var meca = me.GetCustomAttribute<ScriptMemberAttribute>();
                if (meca != null)
                {
                    se.AddHostObject(meca.Name != null ? meca.Name : me.Name, me.GetValue(tmp, null));
                }
            }
        }

        public static void Load(WindowsScriptEngine se, Assembly ass)
        {
            foreach (var t in ass.GetTypes())
            {
                Load(se, t);
            }
        }
    }
Coordinator
Apr 15, 2015 at 8:38 PM
It looks like ModuleLoader is designed to install functions and other data into a script engine, but how are you using it? If possible, please post the code that actually executes script code and raises the exception you're seeing.
Apr 15, 2015 at 8:46 PM
 ModuleLoader.Load(se, Assembly.LoadFile(Application.StartupPath + "\\Std.dll"));

se.Evaluate(File.ReadAllText(p))

var fs = PluginLoader.Call("init"); // run init function who run the imported function
Coordinator
Apr 15, 2015 at 9:00 PM
Unfortunately we can't help you without knowing more about the contents of Std.dll, the script code being executed, PluginLoader, the "init function", the exception stack and message, etc.

If you'd like to post a minimal but complete program that demonstrates the issue you're seeing, we'll be happy to take a look, but it's difficult to figure out what's going on based on the bits and pieces you've provided so far. Sorry!
Apr 15, 2015 at 9:03 PM
i thin the problem is the delegate.

i want to call the delegate myfunc(object,params) as filesize("filename")
Coordinator
Apr 15, 2015 at 9:11 PM
Edited Apr 15, 2015 at 9:15 PM
Can you post the definition of the .NET method you're calling from script code? The method signature should be enough.
Apr 15, 2015 at 9:23 PM
[ScriptFunction(Name = "filesize")]
        public int FileSize(string filename)
Coordinator
Apr 15, 2015 at 9:54 PM
Edited Apr 16, 2015 at 12:11 PM
OK, thanks. Note that this is an instance method (as opposed to a static method), so it requires a target (a this object).

When script code calls this method, what should the target be?

There are two ways to go. The caller can provide the target at the call site, or you can expose a delegate that's bound to a target in advance. Both are easy to do. Which shall it be?
Apr 16, 2015 at 4:22 PM
Edited Apr 16, 2015 at 4:31 PM
i changed all methods to static but now i have a new exception: object expected

*ive steped through the code, the functions are not added. there are static in the signature but in reflection is isstatic=false

what do i wrong?
Apr 16, 2015 at 4:41 PM
i want to know both
Coordinator
Apr 16, 2015 at 5:43 PM
In JScript, "Object expected" can indicate an attempt to call an undefined function. This seems likely given your statement that "the functions are not added". Can you confirm that?

As for why you aren't seeing static methods in reflected types, it's difficult to tell. Are you sure you've rebuilt the assembly you're inspecting?
Apr 17, 2015 at 11:53 AM
thanks i forgot to rebuild, but i have the same error like first: The type must be inferred from the delegate
se.AddHostObject(meca.Name != null ? meca.Name : me.Name, me.CreateDelegate(t));
Coordinator
Apr 17, 2015 at 12:48 PM
Right, that won't work, assuming your code is as you posted it earlier.

If me represents a static method, first declare an appropriate delegate type:
public delegate object StaticMethodFunc(params object[] args);
Now you can expose a delegate that invokes the static method:
engine.AddHostObject(me.Name, new StaticMethodFunc(args => me.Invoke(null, args)));
By the way, if me represents an instance method, you can still expose a delegate that doesn't require an explicit target. All you have to do is provide the target in advance:
var target = Activator.CreateInstance(t);  // or create the target some other way
engine.AddHostObject(me.Name, new StaticMethodFunc(args => me.Invoke(target, args)));
Apr 17, 2015 at 1:39 PM
thanks it works
Coordinator
Apr 17, 2015 at 8:13 PM
Glad to hear it, thanks!