1

これが私のスクリプトコードです:

Imports System.Diagnostics

Public Class Script
Implements IScript

Public Sub DoWork(w As WebBrowser, f As Form1) Implements IScript.DoWork
    w.Navigate("http://www.google.com")
    wait("5000")
    w.Document.All("input").InvokeMember("click")
    w.Document.All("input").SetAttribute("value", "Torrenter is the best!")
    wait("2000")
    w.Document.All("421").InvokeMember("click")
wait("1000")
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

クラス終了

コード内:

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    If int1.Text = "1" Then
        int1.Text = "0"
        Dim script As IScript = GenerateScript(File.ReadAllText(ListBox2.Items.Item(int2).ToString()))
        script.DoWork(WebBrowser1, Me) 'Object reference not set to an instance of an object.
        int2 = int2 + 1
        int1.Text = "1"
    End If
End Sub

なんで?:(最初のスクリプトが完了した後に次のスクリプトを開始することになっています。4つの方法を試しましたが、理由がわかりません。

4

1 に答える 1

0

問題は、スクリプト コードがコンパイルに失敗していることですが、コンパイルされたアセンブリからオブジェクトをインスタンス化しようとしています。コンパイルに失敗したため、アセンブリは実際には存在しないため、エラーが発生します。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
于 2013-02-06T15:56:05.873 に答える