Class 制作HTA';s setTimeout或setInterval调用VBScript类中的子函数/函数

Class 制作HTA';s setTimeout或setInterval调用VBScript类中的子函数/函数,class,vbscript,settimeout,setinterval,hta,Class,Vbscript,Settimeout,Setinterval,Hta,好吧,标题说明了一切。我有一个带有VBS类的HTA,我试图用另一个类sub作为其“函数”参数调用setInterval,但我得到了一个“类型不匹配”错误。 这可以以任何直接或变通的黑客形式完成吗?我能想到的唯一一件事就是在类外使用“argument”函数,但这种方法首先就违背了类的目的。。。 救命啊 编辑(示例代码): 基于我的想法,setInterval将把“function”字符串传递给GetRef(),但它的工作方式更像eval: <html> <head>

好吧,标题说明了一切。我有一个带有VBS类的HTA,我试图用另一个类sub作为其“函数”参数调用setInterval,但我得到了一个“类型不匹配”错误。 这可以以任何直接或变通的黑客形式完成吗?我能想到的唯一一件事就是在类外使用“argument”函数,但这种方法首先就违背了类的目的。。。 救命啊

编辑(示例代码):

基于我的想法,setInterval将把“function”字符串传递给GetRef(),但它的工作方式更像eval:

<html>
 <head>
  <Title>SetIntervalDemo</Title>
  <hta:application id="SetIntervalDemo" scroll = "no">
  <script type="text/vbscript">
   Dim g_sp0
   Sub sp0()
     MsgBox "sp0 called"
     ClearInterval g_sp0
   End Sub
   Sub sisp0()
     g_sp0 = SetInterval(GetRef("sp0"), 1000)
'    g_sp0 = SetInterval("mp0", 1000) <---- Type Mismatch
   End Sub
   Dim g_sp1
   Sub sp1(x)
     MsgBox "sp1 called: " & x
     ClearInterval g_sp1
   End Sub
   Sub sisp1()
     g_sp1 = SetInterval("sp1(4711 + g_sp1)", 1000)
   End Sub
   Dim g_mp0_a
   Dim g_o_a
   Dim g_mp0_b
   Dim g_o_b
   Sub simp0()
     Set g_o_a = New cC : g_o_a.m_sName = "Alpha"
     Set g_o_b = New cC : g_o_b.m_sName = "Beta"
     g_mp0_a = SetInterval("g_o_a.mp0", 1000)
     g_mp0_b = SetInterval("g_o_b.mp0", 1000)
   End Sub
   Class cC
     Public m_sName
     Public Sub mp0()
       MsgBox m_sName & ".mp0 called"
       ClearInterval g_mp0_a
       ClearInterval g_mp0_b
     End Sub
   End Class
  </script>
 </head>
 <body>
  <input type="button" value="sp0" onclick="sisp0" />
  <input type="button" value="sp1" onclick="sisp1" />
  <input type="button" value="mp0" onclick="simp0" />
 </body>
</html>

SetIntervalDemo
暗g_sp0
子sp0()
MsgBox“调用sp0”
间隙g_sp0
端接头
亚组sisp0()
g_sp0=设定间隔(GetRef(“sp0”),1000)
“g_sp0=SetInterval(“mp0”,1000)基于我的想法,SetInterval将把“函数”字符串传递给GetRef(),但它的工作方式似乎更像eval:

<html>
 <head>
  <Title>SetIntervalDemo</Title>
  <hta:application id="SetIntervalDemo" scroll = "no">
  <script type="text/vbscript">
   Dim g_sp0
   Sub sp0()
     MsgBox "sp0 called"
     ClearInterval g_sp0
   End Sub
   Sub sisp0()
     g_sp0 = SetInterval(GetRef("sp0"), 1000)
'    g_sp0 = SetInterval("mp0", 1000) <---- Type Mismatch
   End Sub
   Dim g_sp1
   Sub sp1(x)
     MsgBox "sp1 called: " & x
     ClearInterval g_sp1
   End Sub
   Sub sisp1()
     g_sp1 = SetInterval("sp1(4711 + g_sp1)", 1000)
   End Sub
   Dim g_mp0_a
   Dim g_o_a
   Dim g_mp0_b
   Dim g_o_b
   Sub simp0()
     Set g_o_a = New cC : g_o_a.m_sName = "Alpha"
     Set g_o_b = New cC : g_o_b.m_sName = "Beta"
     g_mp0_a = SetInterval("g_o_a.mp0", 1000)
     g_mp0_b = SetInterval("g_o_b.mp0", 1000)
   End Sub
   Class cC
     Public m_sName
     Public Sub mp0()
       MsgBox m_sName & ".mp0 called"
       ClearInterval g_mp0_a
       ClearInterval g_mp0_b
     End Sub
   End Class
  </script>
 </head>
 <body>
  <input type="button" value="sp0" onclick="sisp0" />
  <input type="button" value="sp1" onclick="sisp1" />
  <input type="button" value="mp0" onclick="simp0" />
 </body>
</html>

SetIntervalDemo
暗g_sp0
子sp0()
MsgBox“调用sp0”
间隙g_sp0
端接头
亚组sisp0()
g_sp0=设定间隔(GetRef(“sp0”),1000)

'g_sp0=SetInterval(“mp0”,1000)我认为不可能在实例本身中调用方法(即通过
Me
),因为调用计时器时上下文丢失

您可以使用一个全局变量(尽管这很糟糕)。问题是,如果同一类有多个实例,那么每个实例都需要一个全局变量,代码需要知道调用哪个变量

但是,上面有一个解决方法-使用数组或字典作为单个全局对象,然后使用名称或id从该集合中标识实例

现在,当您使用计时器时,在类外调用一个方法,将实例的标识符作为值传递。您调用的方法可以在集合中查找此id,返回您的实例,然后可以调用该实例上的相关方法

有点黑客,但它的工作-有一个演示hta应用程序下面发挥看看它的行动

搜索字符串
“!重要信息
查看代码的关键位

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <script type="text/vbs" language="vbscript">
            option explicit

            dim dummies '!Important - this is the global variable holding all your instances

            sub CreateDummyInstances()
                dim dum
                set dummies = CreateObject("Scripting.Dictionary")  
                set dum = (new Dummy)("Makaveli84", 5000) 
                set dum = (new Dummy)("JohnLBevan", 7000) 
                set dum = (new Dummy)("Ekkehard.Horner", 10000)
                set dum = nothing 
            end sub

            class Dummy

                private m_name
                private m_timeoutMilSec
                private m_timerOn
                private m_timerRunningLock

                private sub Class_Initialize
                    m_timerOn = false
                    m_timerRunningLock = false
                end sub

                public default function Dummy(name, timeoutMilSec)
                    m_name = name
                    m_timeoutMilSec = timeoutMilSec
                    dummies.add name, me '!Important - add this new instance to our collection
                    CreateButton
                    set Dummy = me
                end function

                public property Get Name
                    Name = m_name
                end property

                public property Get IsTimerOn
                    IsTimerOn = m_timerOn
                end property

                public sub BeginTimer()
                    m_timerOn = true
                    if not m_timerRunningLock then 'avoid creating two threads if an off-on occurs within a single timer wait
                        TimerLoop
                    end if
                end sub

                public sub EndTimer()
                    m_timerOn = false
                end sub

                public sub TimerLoop()
                    if m_timerOn then 'get out of jail free (altered by separate thread)
                        m_timerRunningLock = true
                        PerformSomeAction

                        'this doesn't work because Me loses its context when called by the timer
                        'window.setTimeout "Me.TimerLoop", m_timeoutMilSec, "VBScript"

                        'so instead we pass a name / id for this object as a parameter to an external function
                        'and have that lookup this instance and externally call the method we wanted to call
                        window.setTimeout "TheFunkyTrick(""" & m_name & """)", m_timeoutMilSec, "VBScript" '!Important - call the external function

                    else
                        m_timerRunningLock = false
                    end if
                end sub

                private sub CreateButton()
                    dim p
                    dim button
                    set p = document.createElement("p")
                    set button = document.createElement("button")
                    button.id = "btnStart" & m_name 
                    button.innerText = "Start " & m_name
                    AddClickEventHandler button, "StartTimer"
                    p.appendChild button
                    set button = document.createElement("button")
                    button.id = "btnStop" & m_name 
                    button.innerText = "Stop " & m_name
                    AddClickEventHandler button, "StopTimer"
                    p.appendChild button
                    divButtons.appendChild p
                    set button = Nothing
                    set p = Nothing
                end sub

                private sub AddClickEventHandler(objButton, strFunctionName)
                    dim fun
                    set fun = getRef(strFunctionName)
                    call objButton.attachEvent("onclick", fun)
                    set fun = Nothing
                end sub

                sub PerformSomeAction
                    msgbox "Hello from " & m_name & ".  I show up every " & cstr(cint(m_timeoutMilSec/1000)) & " seconds, until stopped."
                end sub

            end class

            function vbInit()
                CreateDummyInstances
            end function

            function GetDummy(name)
                if dummies.exists(name) then
                    set GetDummy = dummies(name) '!Important - get desired instance from the collection (assuming it exists)
                else
                    msgbox "name not found: " & name
                    set GetDummy = nothing 'the way I've coded stuff below this would cause an exception (i.e. since I've not bothered to check if it's nothing) - but as this is a demo that's fine
                end if
            end function

            function GetNameFromButtonEvent(objEvent, boilerplate)
                GetNameFromButtonEvent = Right(objEvent.srcElement.Id, len(objEvent.srcElement.Id) - len(boilerplate))
            end function

            sub StartTimer(objEvent)
                dim name
                name = GetNameFromButtonEvent(objEvent, "btnStart")
                GetDummy(name).BeginTimer
            end sub
            sub StopTimer(objEvent)
                dim name
                name = GetNameFromButtonEvent(objEvent, "btnStop")
                GetDummy(name).EndTimer
            end sub
            sub TheFunkyTrick(name) '!Important - call the method on the relevant instance
                GetDummy(name).TimerLoop
            end sub
        </script>
        <HTA:APPLICATION 
            ApplicationName="Stack Overflow VBScript Class Timer Demo"
            Caption="Yes"
            icon="img/favicon.ico"
            Scroll="no"
            SingleInstance="yes"
            WindowState="normal"
            ShowInTaskbar="Yes"
            SysMenu="Yes"
            MaximizeButton="No"
            ShowInTaskbar="Yes"
            MinimizeButton="No"
            Navigable="No"
            Border="Thin"
            BORDERSTYLE="Complex"
            INNERBORDER="No"
        />
        <title>Stack Overflow VBScript Class Timer Demo</title>
    </head>
    <body onload="vbInit()" language="vbscript">
        <h1>Demo</h1>
        <div id="divButtons"></div>
    </body>
</html>

选项显式
傻瓜!重要信息-这是保存所有实例的全局变量
子CreateDummyInstances()
暗哑
set dummies=CreateObject(“Scripting.Dictionary”)
设置dum=(新假人)(“Makaveli84”,5000)
设置dum=(新假人)(“约翰贝万”,7000)
设置dum=(新假人)(“Ekkehard.Horner”,10000)
设置dum=无
端接头
类虚拟
私人m_名称
私人m_timeoutMilSec
二等兵m_timerOn
专用定时锁
私有子类_初始化
m_timerOn=错误
m_timerRunningLock=错误
端接头
公共默认函数虚拟(名称,timeoutMilSec)
m_name=名称
m_timeoutMilSec=timeoutMilSec
傻瓜,加上名字,我!重要信息-将此新实例添加到我们的集合中
创建按钮
设置虚拟=我
端函数
公共属性获取名称
Name=m_Name
端属性
公共财产
IsTimerOn=m_timerOn
端属性
公共子起始者()
m_timerOn=真
如果不是m_timerRunningLock,则“如果在单个计时器等待中发生关闭-打开,则避免创建两个线程”
定时器环路
如果结束
端接头
公共子结束计时器()
m_timerOn=错误
端接头
公共子TimerLoop()
如果m_timerOn然后“自由出狱”(通过单独的线程更改)
m_timerRunningLock=真
表演动作
'这不起作用,因为当计时器调用Me时,Me会丢失其上下文
'window.setTimeout“Me.TimerLoop”、m_timeoutMilSec、“VBScript”
'因此,我们将此对象的名称/id作为参数传递给外部函数
'并将该查找用于此实例,并从外部调用我们想要调用的方法
window.setTimeout“TheFunkyTrick(“”&m_name&“”)”,m_timeoutMilSec,“VBScript”!要点-调用外部函数
其他的
m_timerRunningLock=错误
如果结束
端接头
私有子CreateButton()
暗p
暗按钮
set p=document.createElement(“p”)
设置按钮=document.createElement(“按钮”)
button.id=“btnStart”&m\u名称
button.innerText=“开始”&m\u名称
AddClickEventHandler按钮,“StartTimer”
p、 附加子按钮
设置按钮=document.createElement(“按钮”)
button.id=“btnStop”&m\u名称
button.innerText=“停止”&m\u名称
AddClickEventHandler按钮,“停止计时器”
p、 附加子按钮
divButtons.appendChild p
设置按钮=无
设置p=无
端接头
私有子AddClickEventHandler(对象按钮,strFunctionName)
暗淡的乐趣
set fun=getRef(strFunctionName)
Class My_Class
    Private TimerID

    Public Sub Sub1(param)
        Dim x
        x = DoSomeCalculations(param)
        Dim cb
        Set cb = New MyCallback
        Set cb.Target = Me
        cb.ParamValue = x
        TimerID = window.setInterval(cb , 1000, "VBScript")
    End Sub

    ' must be Public
    Public Sub Sub2(param)
        Dim y
        y = DoSomeMoreCalculations
        If param = y Then window.clearInterval(TimerID)
    End Sub
End Class

Class MyCallback

    Public Target
    Public ParamValue

    ' must be Public and Default
    Public Default Sub DoCall

        Target.Sub2 ParamValue
    End Sub
End Class