如何在 Microsoft 脚本控件中实现事件?

How to Implement An Event in Microsoft Script Control?

我在 MSScriptControl 上阅读的所有文档都说它可以响应添加到它的对象的事件。

the script control allows you to write script that will automatically fire when an event on an object occurs. https://msdn.microsoft.com/en-us/library/ms974586.aspx

the ScriptControl will be able to sink events generated by objects added using the AddObject method. http://flylib.com/books/en/1.492.1.154/1/

但我没有成功。我假设这意味着当添加的对象引发它的事件时,ScriptControl 中的代码将被触发。我无法得到任何工作。

寻找将 any 对象添加到 ScriptControl 并处理该控件触发的事件的示例代码。不关心对象是自定义 class、窗体、控件还是内置 Excel 对象(如 Worksheet)。

运行在 Win Server 2008 64 位上安装 Office 2010 32 位。

对其他方法持开放态度,例如 WSH,但 Tushar Mehta 在这里没有成功 http://dailydoseofexcel.com/archives/2009/08/19/using-vbscript-to-monitor-office-eventsor-not/

我已成功将 Excel Application 对象添加到 ScriptControl,并在 Excel Application 对象上执行了代码:

这没问题:

Function TestProc()
          Dim oScriptCtl As New MSScriptControl.ScriptControl

          With oScriptCtl
                    ' init
                    .Language = "VBScript"
                    .AllowUI = True

                    ' add Excel application object
                    .AddObject "app", Application, True

                    ' add procedure
                    Dim sCode As String
                    sCode = "Sub TestProc : MsgBox ""hi"" : End Sub"
                    .AddCode sCode

                    ' run procedure. Msgbox displays. 
                    .Run "TestProc"
          End With

          ' cleanup
          Set oScriptCtl = Nothing
End Function

失败:

在这个测试中,m_oScriptCtl 是一个模块范围的变量。当我点击表格时没有任何反应:

Function TestForm()
          Set m_oScriptCtl = New MSScriptControl.ScriptControl

          With m_oScriptCtl
                    ' init
                    .Language = "VBScript"
                    .AllowUI = True

                    MyForm.Show False

                    .AddObject "app", Application, True
                    .AddObject "frm", MyForm, True
                    .State = Connected

                    Dim sCode As String
                    sCode = "Sub frm_Click():   MsgBox Chr(14):   End Sub"
                    .AddCode sCode
          End With
End Function

下一个在 .AddCode 上报告以下错误:

Expected ')'

Function TestSheet()
          Set m_oScriptCtl = New MSScriptControl.ScriptControl

          With m_oScriptCtl
                    ' init
                    .Language = "VBScript"
                    .AllowUI = True

                    .AddObject "app", Application, True
                    .AddObject "sheet", Sheet2, True
                    .State = Connected

                    Dim sCode As String
                    sCode = "Private Sub sheet_Change(ByVal Target As Range): MsgBox Target: End Sub"
                    .AddCode sCode
          End With
End Function

在接下来的测试中,MyClass定义为:

Public Event MyEvent()

Public Sub TestEvent()
          RaiseEvent MyEvent
End Sub

但以下报告 "object does not support property or method" .运行。所以在这种情况下,失败的不是事件——我只是不能 运行 class 中的方法。

Function TestClassEvent()
          Set oScriptCtl = New MSScriptControl.ScriptControl

          Dim oClass As New MyClass

          With oScriptCtl
                    ' init
                    .Language = "VBScript"
                    .AllowUI = True

                    ' add objects
                    .AddObject "app", Application, True
                    .AddObject "oClass", oClass, True
                    .State = Connected

                    ' add code
                    Dim sCode As String
                    sCode = "Sub oClass_MyEvent() : MsgBox vbNullString : End Sub"
                    .AddCode sCode

                    .Run "oClass.TestEvent"
          End With

          ' cleanup
          Set oScriptCtl = Nothing
End Function

线索:

有人发帖:

If you totally fail to sink your events, try calling 'ScriptControl1.Modules("Global").CodeObject.Name_Of_Your_Event(ParameterList)' http://computer-programming-forum.com/59-vbscript/4b059f9f6eacfaf0.htm

-- 但我不清楚该解决方法:事件过程不应该是 "called" 明确的,它们应该只是触发。以下几行都给出 "Method or data member not found",在上面的 TestClassEvent 示例中:

m_oScriptCtl.Modules("Global").CodeObject.MyEvent
m_oScriptCtl.Modules("Global").CodeObject.TestEvent

我没有测试以下内容,因为我不太确定如何:

the script control can't handle events from a class in the same project as the application it's being hosted in https://diigo.com/08we68

不确定以下是否相关,不太明白: http://www.programmersheaven.com/discussion/79452/me-activecontrol-and-events

让它起作用的关键是:必须在listener中设置event-firing-object-class 之后将两者都添加到脚本控件——而不是之前。意思是,这一行必须在 SC:

内部执行

Set oListener.EventFiringObject = oEventFiringObject

这是一个在脚本控件内的对象之间触发和响应事件的工作示例。

在这个例子中:

  • 我演示了 2 种事件触发对象:自定义 class 和工作表。
  • 自定义 class 在添加到脚本控件 ("sc") 之前实例化。
  • 我在自定义 sc 对象中调用了一个方法。

设置演示

  • 开始一个新项目(即,在 Excel 中添加一个新的工作簿)。
  • 在您的 VB IDE 中,添加对 Microsoft 脚本控件的引用。
  • 创建以下 VB 个组件:

代码

Class clsSheetListener:

Public WithEvents oSht As Worksheet

Private Sub oSht_Change(ByVal Target As Range)
  ' show  changed cell
  MsgBox "Sheet Listener" & vbCrLf & "Changed: " & Target.Address _
          & vbCrLf & Target.Cells(1).Value2
End Sub

Class clsEventClass:

Public Event MyEvent(sCaller As String)

Public Sub Raise_MyEvent(sCaller As String)
  RaiseEvent MyEvent(sCaller)
End Sub

Class clsClassListener:

Public WithEvents m_oEventClass As clsEventClass

Private Sub m_oEventClass_MyEvent(sCaller As String)
  ' show my execution-scope
  MsgBox "Class Listener, " & sCaller & " caller"
End Sub

模块 Module1:

Function Main()
  ' init scriptcontrol
  Set m_oScriptCtl = Nothing
  Set m_oScriptCtl = New MSScriptControl.ScriptControl
  With m_oScriptCtl
    .Language = "VBScript"
    .AllowUI = True

    ' add Excel application object, needed for all Excel methods in script-control
    .AddObject "sc_Application", Application, True


    ' add Sheet2 to the sc
    ' code executed in sc refers to objects by name, as defined in .AddObject
    .AddObject "sc_oSheet", Sheet2, True

    ' init sheet event-listener, and add to sc
    Dim oSheetListener As New clsSheetistener
    .AddObject "sc_oSheetListener", oSheetListener, True

    ' register the sheet-object with its listener in the scriptcontrol
    ' so the listener can hear the sheet's events
    .ExecuteStatement "Set sc_oSheetListener.oSht = sc_oSheet"


    ' init custom event-firing class object, and add to sc
    Dim oEventClass As New clsEventClass
    .AddObject "sc_oEventClass", oEventClass, True

    ' init class-event listener, and add to sc
    Dim oClassListener As New clsClassListener
    .AddObject "sc_oClassListener", oClassListener, True

    ' register event-firing object with its listener inside the Script Control
    ' so the listener can hear the object's events
    .ExecuteStatement "Set sc_oClassListener.m_oEventClass = sc_oEventClass"


    ' cause event to be raised. 
    ' Call from local context, then sc-context.
    ' it's the same object instance in both cases
    oEventClass.Raise_MyEvent "Local"
    .ExecuteStatement "sc_oEventClass.Raise_MyEvent ""SC"""

  End With
End Function

测试

逐步完成 Main()。您会看到 Raise_MyEventclsEventClass 中触发 MyEvent 时,clsClassListener 使用消息框响应事件。

现在切换到Excel前端,在Sheet2的单元格中输入一个值。您会看到 clsSheetListener 使用消息框响应 Change 事件。