Here's my four-year-old zooming around the end of the street without training wheels.
Now we'll never be able to keep up with her...
Option Strict Offand be able to compile it. The way this works in the Vsa world is that we can use the GetGlobalInstance method to provide an object that implements an interface. In the example above, I have an IScriptDisplay interface with a ClearDisplay() method. I can pass in a class that implements this method, and the script can call it.
Imports System
Imports System.Windows.Forms
Module Script
Sub Main()
ScriptDisplay.ClearDisplay()
End Sub
End Module
VBCodeProvider vbCompiler = new VBCodeProvider();Then, set some compiler options. You may notice that the GenerateInMemory option doesn't quite work as advertised. It still writes out the assembly to disk, at least in .NET 1.1. I'm using the TempFiles property to tell the compiler to put the generated assembly somewhere safe.
ICodeCompiler iCodeCompiler = vbCompiler.CreateCompiler();
CompilerParameters compilerParams = new CompilerParameters();Now, add references to any assembly you might need to access from your scripts.
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = false;
compilerParams.IncludeDebugInformation = false;
compilerParams.CompilerOptions =
"/rootnamespace:SuperMegaCorp.Scripting";
compilerParams.TempFiles = new TempFileCollection(
System.IO.Path.GetTempPath(), false);
compilerParams.ReferencedAssemblies.Add("SuperMegaCorp.dll");
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.ReferencedAssemblies.Add("System.Drawing.dll");
compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
Now the tricky part. Since I don't want to force every script writer out there to change every script they've written, I need to change the script for them.int pos = script.ToUpper().IndexOf("Sub Main(".ToUpper());If this all works, we should have gone from this:
script = script.Insert(pos + "Sub Main(".Length,
"ByRef ScriptDisplay as IScriptDisplay");
Sub Main()to this:
Sub Main(ByRef ScriptDisplay as IScriptDisplay)Now we can compile the script.
CompilerResults results =If that works, all we have left to do is find the Main method and call it, with the application object passed as an argument.
iCodeCompiler.CompileAssemblyFromSource(
compilerParams, script);
if (results != null && results.CompiledAssembly != null)
{
// look for a method called "Main"
Type[] types = results.CompiledAssembly.GetTypes();
foreach (Type thisType in types)
{
MemberInfo[] members = thisType.GetMember("Main");
if (members.Length > 0)
{
// call it, with the script objects
// passed in as arguments
object[] args = new object[] {
(IScriptDisplay)
scriptInterfaces["ScriptDisplay"] };
thisType.InvokeMember("Main",
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.InvokeMethod |
BindingFlags.IgnoreCase,
null, null, args,
CultureInfo.InvariantCulture);
break;
}
}
}


A highlight of this year's Easter promotion by the Jelly Belly company (as additions to its 50 standard flavors) was its surprise BeanBoozled boxes, with odd tastes and non-standard colors. Although garlic beans, buttered-toast beans and cheese pizza beans are no longer available, connoisseurs can sample jelly beans made to taste like pencil shavings, ear wax, moldy cheese and vomit. A Jelly Belly spokeswoman told Newhouse News Service in March, "There are 20 flavors in each little box ... so you don't know what flavor you are tasting ... coconut or baby wipe." [Cleveland Plain Dealer, 3-22-08]
Next step, create a class that implements this interface.Public Interface __context_server
Sub StudyIdentifierChange(<[In](), _ MarshalAs(UnmanagedType.BStr)> ByVal Study_id As String)
End Interface
Class EventSink
Implements __context_server
Public Sub StudyIdentifierChange(ByVal Study_id As String) _
Implements __context_server.StudyIdentifierChange
MessageBox.Show("study id changed: " + Study_id)
End Sub
End Class
Now, create the class for the form that we're going to show from the script.Public Class Form1And finally, the rest of the script. These scripts are run using the VSA scripting, which is now obsolete post-.NET 1.1. Something else to look forward to will be coming up with a way to run these in a .NET 3.5 world, if we ever get there.
Inherits System.Windows.Forms.Form
Dim connectorClass As Object
Dim sink As EventSink
Dim cookie As Integer
Dim connectionPoint As UCOMIConnectionPoint
Public Sub New()
MyBase.New()
InitializeComponent()
' look up the types for the two COM classes we need
Dim connectorClassType As Type = _
Type.GetTypeFromProgID("mitra_context_server.connector_class")
Dim contextServerType As Type = _
Type.GetTypeFromProgID("mitra_context_server.context_server")
' create the connector class
Dim connectorClass As Object = _
Activator.CreateInstance(connectorClassType)
' get the reference to the class that holds the static data
Dim contextServer As Object = _
connectorClassType.InvokeMember("ContextServer", _
BindingFlags.GetProperty, Nothing, connectorClass, Nothing)
' create a connection point container
Dim connectionPointContainer As UCOMIConnectionPointContainer = _
CType(contextServer, UCOMIConnectionPointContainer)
' find the connection point for the guid of our COM server
Dim guid As New Guid("192AD08F-1213-11D4-8756-00500464D554")
connectionPointContainer.FindConnectionPoint(guid, connectionPoint)
' attach the class that handles events
sink = New EventSink
connectionPoint.Advise(sink, cookie)
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
' unhook context server
connectionPoint.Unadvise(cookie)
Marshal.ReleaseComObject(connectionPoint)
End If
MyBase.Dispose(disposing)
End Sub
Private components As System.ComponentModel.IContainerPrivate Sub InitializeComponent()
Me.SuspendLayout()
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 350)
Me.Name = "Form1"
Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
End Class
Option Strict Off
Imports System
Imports System.Windows.Forms
imports system.collections
imports agfahc.pacs.framework
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices
Module Script
dim WithEvents form as Form1
Sub Main()
form = new Form1()
form.Show()
End Sub
End Module