编辑:到目前为止,大多数响应都涉及检查可能不存在的对象,在Option Explicit启用的情况下,该对象完全无法在VBA中使用(它会引发编译时错误,因此On Error不起作用,并关闭Option显式不是一种选择)。还有其他回旋/开箱即用的方式来查找这里需要什么吗?
我正在尝试编写通用的复制和粘贴代码,这些代码将在独立的VBScript(.vbs文件)、. hta文件和VBA(例如在Excel文件)中工作。为此,我需要某种方式让代码本身知道运行在哪个引擎上。
到目前为止,我所听到的最好的主意是测试某些对象是否存在,但是在VBA中,它在编译时会失败(因此我无法使用On Error绕过它),因此无法解决。试图找出正在运行的文件的名称并没有可行性。这是要做的事情之一,具体取决于运行代码的三个脚本引擎中的哪个。 我很想拥有这样简单的东西,但是不确定用什么填充它:
Option Explicit
'--- Returns a string containing which script engine this is running in,
'--- either "VBScript", "VBA", or "HTA".
Function ScriptEngine()
If {what goes here?} Then ScriptEngine="VBS"
If {what goes here?} Then ScriptEngine="VBA"
If {what goes here?} Then ScriptEngine="HTA"
End Function
如果正确填写,则即使打开Option Explicit,您也应该能够将该函数复制并粘贴到任何VBA,VBS或HTA文件中,而无需修改,调用它并获得结果而不是错误。 。 最好的方法是什么?
答案 0 :(得分:9)
在VBA实现中要求使用Option Explicit
的限制使此操作比原本要困难得多(没有它,这是一个单行代码)...具有讽刺意味的是,这也成为实现此目标的关键解。
如果您不将自己限制在一个功能上,则可以通过执行以下操作来摆脱它:
Dim hta
Sub window_onload()
hta = True
End Sub
Function HostType()
On Error Resume Next
If hta Then
HostType = "HTA"
Else
Dim foo
Set foo = foo
If Err.Number = 13 Then
HostType = "VBA"
Else
HostType = "VBS"
End If
End If
End Function
它的工作原理如下-如果通过HTA文件加载,则window_onload
事件处理程序将运行,并将hta
变量设置为True
。那是第一次测试。第二个“测试”位于行Set foo = foo
引发的错误上。这是VBA中的类型不匹配,在VBA中它被解释为试图将Set
的{{1}}转换为Variant
,这是不兼容的类型。同一行代码在VBScript中引发错误424(需要对象),因为它不是强类型语言。这意味着将跳过VBA的类型检查,并尝试实际执行分配(失败)。剩下的只是弄清楚它是如何抛出的并返回结果。
VBA
Empty
VBScript
Option Explicit
Dim hta
Sub Test()
Debug.Print HostType 'VBA
End Sub
Sub window_onload()
hta = True
End Sub
Function HostType()
On Error Resume Next
If hta Then
HostType = "HTA"
Else
Dim foo
Set foo = foo
If Err.Number = 13 Then
HostType = "VBA"
Else
HostType = "VBS"
End If
End If
End Function
HTA
WSCript.Echo HostType
Dim hta
Sub window_onload()
hta = True
End Sub
Function HostType()
On Error Resume Next
If hta Then
HostType = "HTA"
Else
Dim foo
Set foo = foo
If Err.Number = 13 Then
HostType = "VBA"
Else
HostType = "VBS"
End If
End If
End Function
编辑:
FWIW,如果不需要<HTML>
<BODY>
<script type="text/vbscript">
Dim hta
Sub Test()
MsgBox HostType
End Sub
Sub window_onload()
hta = True
End Sub
Function HostType()
On Error Resume Next
If hta Then
HostType = "HTA"
Else
Dim foo
Set foo = foo
If Err.Number = 13 Then
HostType = "VBA"
Else
HostType = "VBS"
End If
End If
End Function
</script>
<button onclick="vbscript:Test()">Click me</button>
</BODY>
</HTML>
,则上面引用的单行代码就是这样:
Option Explicit
所有三个对象都有一个默认属性,该属性返回一个Function HostString()
HostString = Application & document & WScript
End Function
。在VBScript中,这将返回“ Windows Script Host”。在VBA中,它将返回主机的名称(即Excel中的“ Microsoft Excel”)。在HTA中,它将返回“ [object]”。
答案 1 :(得分:4)
尽管我同意@this,但是这是我的Option Explicit
安全方法,没有On Error
语句使用Window_OnLoad
监听器进行HTA(就像Comintern一样),并且区分VBScript和VBA的行标签技巧。
Dim IsInHTA, IsInVBScript
Sub Window_Onload()
IsInHTA = True
End Sub
Sub LineLabelTest()
'VBA and VB6 (maybe VB5 too, IDK) treats "DummyLabel:" as a line label
'VBScript treats "DummyLabel" as an expression to call and treats ":" as a statement separator.
DummyLabel:
End Sub
Sub DummyLabel()
'this is called by the LineLabelTest subroutine only in VBScript
IsInVBScript = True
End Sub
Function HostType()
LineLabelTest
If IsInVBScript Then
If IsInHTA Then
HostType = "HTA"
Else
HostType = "VBS" 'Other hosts incuding WSH, ASP, Custom
End If
Else
HostType = "VBA" 'VBA or VB6 (maybe VB5 too, don't know)
End If
End Function
答案 2 :(得分:2)
尝试检查是否存在上下文对象,例如
Function ScriptEngine()
dim tst
on error resume next
Err.Clear
tst = WScript is Nothing
if Err=0 then ScriptEngine="WScript" : exit function
Err.Clear
' similar way check objects in other environments
End Function
答案 3 :(得分:1)
任何未声明的变量将是Variant/Empty
,因此,如果VarType(something)
未定义,则vbEmpty
将是0
(或something
)。
除非VarType
在VBA标准库之外不存在(我不知道TBH),那么就不必捕获/跳过/处理任何错误,才能在VBA中进行测试:>
Function GetHostType()
If VarType(wscript) <> vbEmpty Then
GetHostType = "VBS"
Exit Function
End If
If VarType(Application) <> vbEmpty Then
GetHostType = "VBA"
Exit Function
End If
GetHostType = "HTA"
End Function
请注意,如果例如Application
或WScript
定义在某处,并且主机分别不是VBA或VBScript。
或者,不管是否定义了VarType
,这都行得通:
Function GetHostType()
On Error Resume Next
If Not WScript Is Nothing Then
If Err.Number = 0 Then
GetHostType = "VBS"
Exit Function
End If
End If
Err.Clear ' clear error 424 if not VBS
If Not Application Is Nothing Then
If Err.Number = 0 Then
GetHostType = "VBA"
Exit Function
End If
End If
Err.Clear ' clear error 424 if not VBA
GetHostType = "HTA"
End Function
再次假定没有定义这些名称的对象;该机制依赖于WScript
/ Application
是Variant/Empty
,因此在使用Is Nothing
进行测试时会引发运行时错误424“ Object Required”。
请注意,您不能为此指定Option Explicit
。原因是因为如果您使用Dim WScript
和Dim Application
来满足编译器的要求,那么在运行时,这些变量将覆盖正在检查的全局标识符,并且该函数将始终返回您首先检查的主机
答案 4 :(得分:1)
我建议您将问题向后处理。而不是询问“谁是这里的主持人?”,而是应该具有用于任务的通用接口。例如,您将有一个模块-称它为MyAPI
:
Public Function MySleep(Milliseconds As Long)
End Function
然后,您可以为VBA实现一个,为VBS实现一个,为HTA实现另一个(尽管我怀疑是否存在真正的区别。与主机无关的代码将要求包含该模块,所有这些模块都应允许。例如, see here for including a file to VBS。看起来也像HTA has something similar。在VBA中,这只是另一个模块。
然后,在不可知主机代码中,您将调用MySleep
而不是API声明的Sleep
或WScript.Sleep
,然后让包含的模块提供主机特定的实现,而无需任何分支因此,需要禁用Option Explicit
或测试不存在的对象。
答案 5 :(得分:1)
对于以后遇到此问题的任何人,这是我最终制作的最终代码,并且可以使用!特别感谢此主题中的每个人,他们贡献了共同的想法来完成这项工作! :-)
'------------------------------------------------------------------
'--- Function ScriptEngine
'---
'--- Returns a string containing which script engine this is
'--- running in.
'--- Will return either "VBScript","VBA", or "HTA".
Function ScriptEngine
On Error Resume Next
ScriptEngine="VBA"
ReDim WScript(0)
If Err.Number=501 Then ScriptEngine="VBScript"
Err.Clear
ReDim Window(0)
If Err.Number=501 Then ScriptEngine="HTA"
On Error Goto 0
End Function
'-------------------------------------------------------------------
答案 6 :(得分:-1)
所有程序都有一个主机,该主机至少提供一个全局Application
对象。 WScript提供了全局WScript
,Word / Excel提供了Application
对象,HTA提供了IE Window对象(通过父属性可以访问InternetExplorer.Application
对象。
在COM中,我们在IUnknown接口上调用QueryRef以查找其具有的对象。这发生在引擎盖下。原理是您尝试使用它,并查找表示属性E_Not_Implemented的错误。
这是应在Application对象https://docs.microsoft.com/en-au/previous-versions/windows/desktop/automat/using-the-application-object-in-a-type-library中使用的标准
所以wscript.name
,InternetExplorer.Application.Name
和Word.Application.Name
。
在Wscript中,此代码显示Windows Scripting Host
。在Word中,它打印Normal 424 Object Required
。在HTA Microsoft VBScript runtime error 424 Object required
中。
On Error Resume Next
x = wscript.name
If err.Number = 0 then
Msgbox x
Else
Msgbox err.source & " " & err.number & " " & err.description
End If
与Word Microsoft Word
,VBS Microsoft VBScript runtime error 424 Object required
和HTA Microsoft VBScript runtime error 424 Object required
类似。
On Error Resume Next
x = Application.Name
If Err.Number = 0 Then
MsgBox x
Else
MsgBox Err.Source & " " & Err.Number & " " & Err.Description
End If
还请注意,是否定义了针对Application的测试不是很可靠。 Excel还具有一个Application对象。您必须测试name
。