Imports System.IO
Imports System.Text
Imports System.Reflection
Imports System.Collections
Public Class VsaScriptHost
' Engine to be used in the class
Private myEngine As Microsoft.Vsa.IVsaEngine
' Items for the engine
Private myItems As Microsoft.Vsa.IVsaItems
' Code Item that stores the script
Private myScript As Microsoft.Vsa.IVsaCodeItem
' The implementation of the VSASite used for call backs
Private mySite As VsaSite
' temporary Src string
Private tempSrc As String
' VSA reference Item for holding the system.dll reference
Private systemRef As Microsoft.Vsa.IVsaReferenceItem
' temporary reference used in the AddReference method
Private tempRef As Microsoft.Vsa.IVsaReferenceItem
' String that contains any imports statements needed for the addobject
Private ImportsScript As String
' Boolean for determining debugging or not
Private debugValue As Boolean
' Boolean determining whether the engine has been compiled
Private IsCompiled As Boolean
Dim myPE As Byte()
Dim myPDB As Byte()
Dim tempModules(0) As String
Private languageValue As String
Public ReadOnly Property CompiledState() As Byte()
Get
Try
myEngine.SaveCompiledState(myPE, myPDB)
Catch e As System.Exception
End Try
Return myPE
End Get
End Property
' The language of the engine being used
Public ReadOnly Property Language() As String
Get
Return languageValue
End Get
End Property
' The script code
Public Property scriptSrc() As String
Get
' Add the imports to the beginning of the script
Return myScript.SourceText
End Get
Set(ByVal Value As String)
myScript.SourceText = Value
End Set
End Property
' Collection of Procedures in the engine
Public ReadOnly Property Procedures() As MethodInfo()
Get
' Check to see if the engine is running
' If it's not run it so we can get the modules
If Not myEngine.IsRunning Then
Me.Run()
End If
' Return the procedures in the module
Dim fullName As String
Dim modType As Type
Dim methods As MethodInfo()
' Create the fullname of the namespace that containts the method
fullName = myEngine.RootNamespace & "." & myEngine.RootNamespace
' Get the type from the assembly
modType = myEngine.Assembly.GetType(fullName, True, True)
' Get the methods from the module
methods = modType.GetMethods(BindingFlags.Static Or BindingFlags.Public)
' Return the methods
Return methods
End Get
End Property
Public ReadOnly Property Modules() As String()
Get
' *** HACK ***
' It's a demo after all
Try
tempModules(0) = "scriptcode"
Catch e As Exception
End Try
Return tempModules
End Get
End Property
Public Property Debug() As Boolean
Get
' Return the value of the debug flag
Return debugValue
End Get
Set(ByVal Value As Boolean)
debugValue = Value
End Set
End Property
Public ReadOnly Property CompiledAssembly() As System.Reflection.Assembly
Get
Return myEngine.Assembly
End Get
End Property
Public Sub New(ByVal scriptlanguage As String, ByVal Moniker As String, ByVal [NameSpace] As String)
Try
' Store the langauge
Me.languageValue = scriptlanguage
' Creat the Script Engine based on the language
createEngine()
' Set the moniker to be something relatively unique
myEngine.RootMoniker = Moniker
' Create a new instance of the VSA Site
myEngine.Site = New VsaSite()
' Get the instance of the site
mySite = myEngine.Site
' Initialize the engine
myEngine.InitNew()
' Set the rootnamespace
myEngine.RootNamespace = [NameSpace]
' Set the engine name
myEngine.Name = [NameSpace]
Catch e As Microsoft.Vsa.VsaException
End Try
' Get the items collection from the engine
myItems = myEngine.Items
' Create a blank codeitem
If Me.Language <> "JScript.NET" Then
myScript = myItems.CreateItem("scriptcode", Microsoft.Vsa.VsaItemType.Code, Microsoft.Vsa.VsaItemFlag.Module)
Else
myScript = myItems.CreateItem("scriptcode", Microsoft.Vsa.VsaItemType.Code, Microsoft.Vsa.VsaItemFlag.None)
End If
' Create a reference to system
Me.AddReference("System", "System.dll")
' Setup debugging
Me.setupDebug(Debug)
' Add an inports to system
Me.setupImports("System")
IsCompiled = False
End Sub
Public Sub AddCode(ByVal Code As String)
' Need to get the source text to put the code inside the module/class
tempSrc = Me.scriptSrc
If Me.Language <> "JScript.NET" Then
Me.scriptSrc = tempSrc.Insert(tempSrc.LastIndexOf("End Module"), Code & vbCrLf)
Else
Me.scriptSrc += Code & vbCrLf
End If
End Sub
Public Sub AddObject(ByVal Name As String, ByVal Type As String, ByRef Instance As System.Object, ByVal AssemblyName As String, Optional ByVal Events As Boolean = True)
' Add an eventsource to the engine
myScript.AddEventSource(Name, Type)
' Add the instance to the sites hashtable
mySite.AddEvent(Name, Type, Instance, True)
' JScript.NET Beta 2 has a bug whereby adding an event source actually
' adds an entry to the item list so adding "Ref" to the Name ensure that
' theres no naming collisions
Me.AddReference(Name & "Ref", AssemblyName)
' Make sure the reference gets imported
' Use split to get the type from the beginning of the Type String
Me.setupImports(Type.Split(".")(0))
End Sub
Public Sub AddReference(ByVal Name As String, ByVal AssemblyName As String)
Try
' Create a reference to the object
tempRef = myItems.CreateItem(Name, Microsoft.Vsa.VsaItemType.Reference, Microsoft.Vsa.VsaItemFlag.None)
' Set the assemblyname
tempRef.AssemblyName = AssemblyName
Catch e As Microsoft.Vsa.VsaException
Throw New Exception("Couldn't add Assembly")
End Try
End Sub
Public Sub Compile()
' Check to see if the engine is running
If myEngine.IsRunning Then
' If it is reset the engine
myEngine.Reset()
End If
Try
If myEngine.Compile() Then
Me.Run()
Else
Throw New Exception("Error in compilation")
End If
Catch e As Microsoft.Vsa.VsaException
End Try
End Sub
Public Function Invoke(ByVal ModuleName As String, ByVal MethodName As String, ByVal Arguments As Object()) As Object
Dim FullName As String
Dim ModType As Type
Dim method As MethodInfo
Dim evidencecontrol As New System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.ControlEvidence)
evidencecontrol.Assert()
If Not myEngine.IsRunning Then
Throw New Exception("Engine isn't running!")
Exit Function
End If
Dim evidencecol As IEnumerator
evidencecol = myEngine.Assembly.Evidence.GetEnumerator()
' Create the fullname of the namespace that containts the method
FullName = myEngine.RootNamespace & "." & ModuleName
Try
' Get the type from the assembly
ModType = myEngine.Assembly.GetType(FullName, True, True)
Catch e As Microsoft.Vsa.VsaException
Throw New Exception("Unable to get assembly named " & FullName)
End Try
' Get the method from the type
method = ModType.GetMethod(MethodName)
' Check to see if we can find the method
If Nothing Is method Then
' Can't find the method so throw an exception
Throw New Exception("method not found")
Else
Try
' Call the method and return any value
Return method.Invoke(Nothing, Arguments)
Catch e As Exception
MsgBox(e.ToString)
End Try
End If
End Function
Public Sub Run()
Try
myEngine.Run()
Catch e As Microsoft.Vsa.VsaException
Throw New Exception("Unable to run the engine")
End Try
End Sub
Private Sub createEngine()
Try
Select Case Language
Case "VB", "Visual Basic"
myEngine = New Microsoft.VisualBasic.Vsa.VsaEngine()
Case "JScript", "JScript.NET"
myEngine = New Microsoft.JScript.Vsa.VsaEngine()
Case Else
Throw New Exception("Unknown Engine")
End Select
Catch e As Exception
End Try
End Sub
Private Sub setupImports(ByVal Type As String)
' Should use CodeDOM here really
' That will be in the next installment
If Language = "VB" Then
ImportsScript = "imports"
Else
ImportsScript = "import"
End If
ImportsScript += " " & Type
ImportsScript += vbCrLf
' Add the imports to the beginnging of the script
Me.scriptSrc = ImportsScript & Me.scriptSrc
End Sub
Private Sub setupDebug(ByVal state As Boolean)
If state Then
' Write out the temporary file
Dim fs As FileStream
Dim FilePath As String = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData) & "\scriptpad\script.vb"
Dim DirectoryName As String = Path.GetDirectoryName(FilePath)
If Not (Directory.Exists(DirectoryName)) Then
Directory.CreateDirectory(DirectoryName)
End If
fs = New FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None)
Dim writer As New StreamWriter(fs, New UnicodeEncoding())
writer.Write(Me.scriptSrc)
writer.Close()
fs.Close()
Me.scriptSrc = "#ExternalSource(" & FilePath & ",1)" & Me.scriptSrc
Me.scriptSrc += "#End ExternalSource"
Else
End If
End Sub
End Class
' Simple implementation of a VSA Site for use by the VSAScriptHost Class
Public Class VsaSite
Implements Microsoft.Vsa.IVsaSite
' Hashtable to store the instances of the objects being added to the engine
Private eventInstances As New Hashtable()
Public Function AddEvent(ByVal Name As String, ByVal type As String, ByRef Instance As Object, ByVal Events As Boolean)
Try
eventInstances.Add(Name, Instance)
Catch e As Exception
MsgBox("Couldn't add event instance to the hashtable")
End Try
End Function
Public Sub GetCompiledState(ByRef pe() As Byte, ByRef debugInfo() As Byte) Implements Microsoft.Vsa.IVsaSite.GetCompiledState
End Sub
Public Function GetEventSourceInstance(ByVal itemName As String, ByVal eventSourceName As String) As Object Implements Microsoft.Vsa.IVsaSite.GetEventSourceInstance
Try
Return eventInstances(eventSourceName)
Catch e As Exception
Throw New Exception("couldn't find the instance")
End Try
End Function
Public Function GetGlobalInstance(ByVal [name] As String) As Object Implements Microsoft.Vsa.IVsaSite.GetGlobalInstance
End Function
Public Sub Notify(ByVal notify As String, ByVal info As Object) Implements Microsoft.Vsa.IVsaSite.Notify
End Sub
Public Function OnCompilerError(ByVal [error] As Microsoft.Vsa.IVsaError) As Boolean Implements Microsoft.Vsa.IVsaSite.OnCompilerError
' Provide a simple dialog with the compile error message
MsgBox([error].Description & "on line " & [error].Line, MsgBoxStyle.Exclamation, "Compile Error")
End Function
End Class