問題は、スクリプト コードがコンパイルに失敗していることですが、コンパイルされたアセンブリからオブジェクトをインスタンス化しようとしています。コンパイルに失敗したため、アセンブリは実際には存在しないため、エラーが発生します。Return
メソッドの行を変更しGenerateScript
てコンパイル エラーが表示されるようにすると、実際の問題がより明確になります。
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codes)
If results.Errors.HasErrors Then
Dim builder As New StringBuilder()
builder.AppendLine("Script failed to compile due to the following errors:")
For Each i As CompilerError In results.Errors
builder.AppendFormat("Line {0}: {1}", i.Line, i.ErrorText)
builder.AppendLine()
Next
Throw New Exception(builder.ToString())
Else
Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
End If
コンパイルに失敗する理由の 1 つは、スクリプトIScript
が未定義の which を使用しているためだと思われます。未定義であると不平を言う理由は、2 つの理由からです。最初に、クラスIScript
内にネストされたインターフェイスを宣言しました。Form1
他のタイプの内部にネストされないように、フォーム クラスの外に移動する必要があります。第二に、完全な名前空間を指定していないか、スクリプトで名前空間をインポートしていません。Imports
次のように、コンパイルする前に、スクリプト コードの先頭に行を自動的に追加できます。
Dim interfaceNamespace As String = GetType(IScript).Namespace
Dim codes As String = "Imports " & interfaceNamespace & Environment.NewLine & code
上記のコメントで述べたように、文字列CompileAssemblyFromSource
ではなく、文字列配列をメソッドに渡す必要があります。それがどういうわけか許可されているものでない限り、それがどのようにコンパイルされるのかわかりませんかOption Strict Off
? いずれにせよ、それは配列を期待しているので、次のように実際に配列を与える必要があります:
Dim interfaceNamespace As String = GetType(IScript).Namespace
Dim codeArray() As String = New String() {"Imports " & interfaceNamespace & Environment.NewLine & code}
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codeArray)
スクリプトがコンパイルに失敗するもう 1 つの明白な理由は、Form1
クラスのメンバーであるかのように、クラスのメソッドとプロパティを使用しているためです。スクリプトScript
ファイルのソース コードで定義されたクラスは、別のアセンブリ内の完全に別のクラスであることに注意してください。参照を与えない限り、フォームへの参照はありません。たとえば、次のようにインターフェイスを定義できます。
Public Interface IScript
Sub DoWork(f As Form1)
End Interface
次に、スクリプトでこれを行うことができます。
Public Class Script
Implements IScript
Public Sub DoWork(f As Form1) Implements IScript.DoWork
f.WebBrowser1.Navigate("http://www.google.com")
f.wait("5000")
f.wait("4000")
f.WebBrowser1.Document.All("input").InvokeMember("click")
f.WebBrowser1.Document.All("input").SetAttribute("value", "User")
f.wait("2000")
f.WebBrowser1.Document.All("421").InvokeMember("click")
End Sub
End Class
アップデート
さて、あなたはそれを機能させることができないので、この会話全体が完全に失われたくないので、私は機能するプロジェクトをまとめてテストしました。これを機能させるために必要なことは次のとおりです。
IScript.vb の内容
Public Interface IScript
Sub DoWork(w As WebBrowser)
End Interface
Form1.vb の内容
Imports Microsoft.VisualBasic
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.IO
Imports System.Text
Public Class Form1
Dim int1 As Integer = 0
Dim int2 As Integer = 0
Dim p As Point
Public Function GenerateScript(ByVal code As String) As IScript
Using provider As New VBCodeProvider()
Dim parameters As New CompilerParameters()
parameters.GenerateInMemory = True
parameters.ReferencedAssemblies.Add(GetType(WebBrowser).Assembly.Location)
parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
Dim interfaceNamespace As String = GetType(IScript).Namespace
code = "Imports System.Windows.Forms" & Environment.NewLine & "Imports " & interfaceNamespace & Environment.NewLine & code
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, code)
If results.Errors.HasErrors Then
Dim builder As New StringBuilder()
builder.AppendLine("Script failed to compile due to the following errors:")
For Each i As CompilerError In results.Errors
builder.AppendFormat("Line {0}: {1}", i.Line, i.ErrorText)
builder.AppendLine()
Next
Throw New Exception(builder.ToString())
Else
Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
End If
End Using
End Function
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each File As FileInfo In New System.IO.DirectoryInfo(Application.StartupPath & "/scripts").GetFiles
If CheckedListBox1.GetItemCheckState(int2) = CheckState.Checked Then
ListBox1.Items.Add(File.FullName)
End If
int2 = int2 + 1
Next
int2 = 0
Dim script As IScript = GenerateScript(File.ReadAllText(ListBox1.Items.Item(int2).ToString()))
script.DoWork(WebBrowser1)
End Sub
End Class
スクリプトファイルの内容
Imports System.Diagnostics
Public Class Script
Implements IScript
Public Sub DoWork(w As WebBrowser) Implements IScript.DoWork
w.Navigate("http://www.google.com")
wait("5000")
wait("4000")
w.Document.All("input").InvokeMember("click")
w.Document.All("input").SetAttribute("value", "User")
wait("2000")
w.Document.All("421").InvokeMember("click")
End Sub
Public Sub wait(ByVal interval As Integer)
Dim sw As New Stopwatch
sw.Start()
Do While sw.ElapsedMilliseconds < interval
' Allows UI to remain responsive
Application.DoEvents()
Loop
sw.Stop()
End Sub
End Class