Have you ever wanted to be able to add scripting to your application? So your users can write a script and you can have it run inside it, adding menus, etc. - like Microsoft Visual Basic for Applications allows in Office.
This is a preliminary article, I'll try to rewrite this but I just took a 20 minute break from work (need to have something done for tomorrow - so yes, still working at 10PM! GRR) and finally managed to get scripting using Microsoft.VSA working from a C# application. Apologies for the lack of tabs in the formatting and lack of explanation.
This is missing the ability to access anything in the running application - you need to register a global item (in the same way as code items and references are added) to do that - then it is exposed as an object inside the environment running the script.
Add references to Microsoft.VisualBasic.Vsa and Microsoft.Vsa (when I repost I'll be using JScript.NET - never fear!) and add the following using clauses:
using
System.Reflection;
using
Microsoft.Vsa;
using
Microsoft.Win32;
And then add the following code to a button or similar (with a textbox to enter your script in) - this will create a scripting engine object, then run your script inside it. The best test is to show a message using MessageBox.Show(""); (remember though, it's VB!)
ScriptEngine eng = new ScriptEngine();
eng.Start();
IVsaCodeItem c = eng.CreateCodeItem("ScriptItem");
c.SourceText = textBox1.Text; //Where this is a simple vb.net script with a class called Script and a Sub called Main
eng.Run();
And now, the main code chunk snippet that is the scripting engine:
public class ScriptEngine : IVsaSite
{
private IVsaEngine Engine;
public ScriptEngine()
{
Start();
}
public void Start()
{
try
{
Engine = new Microsoft.VisualBasic.Vsa.VsaEngine();
Engine.RootMoniker = "myapp://net.nullify.www/ScriptEngine";
Engine.Name = "vsaEngine";
Engine.RootNamespace = "VsaEngine";
Engine.Site = this;
Engine.InitNew();
CreateReference("Mscorlib.dll");
CreateReference("System.dll");
CreateReference("System.Windows.Forms.dll");
CreateReference("System.Data.dll");
CreateReference("System.Drawing.dll");
CreateReference("System.XML.dll");
}
catch (VsaException ex)
{
MessageBox.Show("Scripting engine error: "+ex.Message);
}
}
public IVsaReferenceItem CreateReference(string assemblyName)
{
IVsaReferenceItem item = (IVsaReferenceItem)Engine.Items.CreateItem(assemblyName, VsaItemType.Reference, VsaItemFlag.None);
item.AssemblyName = assemblyName;
return item;
}
public IVsaCodeItem CreateCodeItem(string itemName)
{
try
{
IVsaCodeItem item = (IVsaCodeItem)Engine.Items.CreateItem(itemName, VsaItemType.Code, VsaItemFlag.Class);
return item;
}
catch (VsaException ex)
{
MessageBox.Show("Problem creating the code item: "+ex.Message);
}
return null;
}
public void Run()
{
if (Engine.Compile())
{
Engine.Run();
Type type = Engine.Assembly.GetType("VsaEngine.Script");
MethodInfo method = type.GetMethod("Main");
method.Invoke(null, null);
}
}
#region
IVsaSite Members
public object GetEventSourceInstance(string itemName, string eventSourceName)
{
// TODO: Add ScriptEngine.GetEventSourceInstance implementation
return this;
}
public object GetGlobalInstance(string name)
{
// TODO: Add ScriptEngine.GetGlobalInstance implementation
return null;
}
public void Notify(string notify, object info)
{
// TODO: Add ScriptEngine.Notify implementation
}
public bool OnCompilerError(IVsaError error)
{
MessageBox.Show("["+error.Line+"] Compiler error: "+error.Description);
return true;
}
public void GetCompiledState(out byte[] pe, out byte[] debugInfo)
{
// TODO: Add ScriptEngine.GetCompiledState implementation
pe = null;
debugInfo = null;
}
#endregion
}
And finally to test this you can use the following code:
imports System
imports System.Diagnostics
module Script
sub Main()
MessageBox.Show("Boo")
end sub
end module