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

我怀疑它无法编译的原因之一是脚本使用IScript的是未定义的。它会抱怨它未定义的原因有两个。首先,您将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)

脚本无法编译的另一个明显原因是因为您使用了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 回答