VBS 中变量设置为变量的问题

发布于 2024-11-30 17:26:07 字数 2027 浏览 1 评论 0原文

在我与 SecureCRT 结合使用来自动化 Cisco 设备上的某些流程的 VBS 中,我(非常精简)了以下代码:

Sub prConnectToHost(strConnectHost)

  'If no host is passed into subroutine then we need to prompt for one.
  If strConnectHost = "" Then strConnectHost = LCase(crt.Dialog.Prompt("Enter hostname or IP address:", "Connect to a host", strHost, False))

  strHost = strConnectHost

  'If user hits Cancel or hits Ok with no hostname entered then exit.
  If strHost = "" Then
    booReconnect = False
    Exit Sub
  End If

  'Write to connection log
  Call prWriteToConnectionLog

  'Run command capture subroutine.
  Call prCommandLoop

  Set intWaitString = Nothing:  Set strScreenGet = Nothing
  Set strLatestScriptVersion = Nothing:  Set strConnectHost = Nothing
End Sub

Sub Main 有一个像这样的部分:

Do While booReconnect = True
  Call prConnectToHost("")
Loop

crt.Dialog.Prompt 与 MsgBox 相同,只是它以窗口为中心而不是以屏幕为中心,所以它更整洁一些。变量 strHost 是实际的主机名字符串,它在脚本中是全局的,包含我们要连接的主机名。它在 Prompt 行中用作默认文本,其想法是,如果您断开连接并设置了 booReconnect 标志,则此 Sub 是再次调用,下次提示您输入主机名时,旧主机名就在那里 - 如果您第一次拼写错误,或者您正在连接到一堆具有相似名称的设备,那么这很有用。

您可以看到我们在此 Sub 末尾调用 prCommandLoop 的位置,这是一个使用名为 WaitForStringscrt 函数 的循环/code> 它将搁置脚本,直到找到特定的字符串序列。当它发生时,它会发射一些东西,然后循环回来,直到再次等待。

其中一个自动化命令会检测连接菜单是否存在(因此我们已退出路由器会话)并提示用户输入另一个要连接的主机名。

重要的一点是最后的变量清除 - Set strConnectHost = Nothing。如果我保留此设置并立即退出设置了 booReconnectprCommandLoop,那么一旦应用 Set strConnectHost = NothingstrHost 死亡 - 如果我尝试引用它,我会收到错误未设置对象变量。我尝试将 MsgBox strHost 行放在 Sub 的末尾,这证明了这一点。

奇怪的是,如果我首先在 prCommandLoop 中选择不同的自动化命令,然后退出会话,则 Set strConnectHost = Nothing 似乎不会打扰任何人。

谁能帮我解释为什么这是一个问题,因为它让我感到困惑。我可以轻松解决这个问题(通过不在 prConnectToHost Sub 末尾发出 Set strConnectHost = Nothing ),但我只想了解问题所在。

In a VBS I have which I use in conjunction with SecureCRT to automate some processes on Cisco devices, I have (very much pared down) the following code:

Sub prConnectToHost(strConnectHost)

  'If no host is passed into subroutine then we need to prompt for one.
  If strConnectHost = "" Then strConnectHost = LCase(crt.Dialog.Prompt("Enter hostname or IP address:", "Connect to a host", strHost, False))

  strHost = strConnectHost

  'If user hits Cancel or hits Ok with no hostname entered then exit.
  If strHost = "" Then
    booReconnect = False
    Exit Sub
  End If

  'Write to connection log
  Call prWriteToConnectionLog

  'Run command capture subroutine.
  Call prCommandLoop

  Set intWaitString = Nothing:  Set strScreenGet = Nothing
  Set strLatestScriptVersion = Nothing:  Set strConnectHost = Nothing
End Sub

Sub Main has a section like this:

Do While booReconnect = True
  Call prConnectToHost("")
Loop

crt.Dialog.Prompt is the same as MsgBox, only it centres on the window and not the screen, so it's a little neater. The variable strHost is the actual hostname string which is global in the script and contains the hostname we want to connect to. It is used in the Prompt line as a default text, the idea being that if you disconnect and the booReconnect flag is set, this Sub is called again, and next time you're prompted for a hostname the old one is there - useful if you spelled it wrong first time, or you're connecting to a bunch of devices with a similar name.

You can see where we call prCommandLoop at the end of this Sub, which is a loop which uses a crt Function called WaitForStrings which puts the script on hold until it finds a particular string sequence. When it does, it fires off some stuff, then loops back around until it sits waiting again.

One of the automation commands detects for the presence of the connection menu (so therefore we have quit the router session) and prompts the user for another hostname to connect to.

The important bit is in the variable clearup at the end - Set strConnectHost = Nothing. If I leave this in and immediately exit prCommandLoop with booReconnect set, as soon as Set strConnectHost = Nothing is applied, strHost dies - if I try to reference it I get an error Object Variable not set. I experimented with putting a MsgBox strHost line right at the end of the Sub, which proved this.

The bizarre thing is that if I choose a different automation command in prCommandLoop first and then quit the session, the Set strConnectHost = Nothing doesn't seem to bother anyone.

Can anyone help me explain why this is a problem, as it is baffling me. I can easily work around it (by not issuing Set strConnectHost = Nothing at the end of the prConnectToHost Sub), but I just want to understand what the problem is.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ゃ人海孤独症 2024-12-07 17:26:07

Set用于将对象分配给变量。将 Nothing 视为一个非常特殊的对象

>> WScript.Echo IsObject(Nothing)
>>
-1

,它仅用于指示变量为空。您

Set strConnectHost = Nothing

将此 Nothing 分配给 strConnectHost。之后,该变量就毫无用处了——它保存着无法打印或在计算中使用或要求执行方法的空对象。

类型前缀欺诈 (*str*ConnectHost) 应提醒您这是可疑的。您使用字符串(和数字?);要清除/重置它们,请使用(简单)分配 Empty:

>> strConnectHost = Empty
>>
>> WScript.Echo IsEmpty(strConnection)
>>
-1

或合适的值:(

intWaitString = -1 ' or 0 ...

假设 intWaitString 不是另一种类型前缀欺诈)。

第二次尝试:

我假设您像这样调用您的子程序:

strHost = "SomeHost"
prConnectToHost strHost

您的子程序的相关摘要是:

Sub prConnectToHost( [ByRef] strConnectHost)
  ...
  Set strConnectHost = Nothing
End Sub

由于 VBScript 默认使用参数的引用传递,因此您的修改
更改调用者变量 strHost。这也发生在非对象变量上:

  Dim sVar : sVar = "String 0"
  WScript.Echo 0, sVar
  changeString sVar
  WScript.Echo 1, sVar

  Sub changeString( sByRefVar )
    sByRefVar = "String 1: changed by changeString( ByRef sByRefVar )"
  End Sub

输出:

0 String 0
1 String 1: changed by changeString( ByRef sVar )

在您的情况下,修改不会将任何内容分配给被调用的变量
Sub 中的 strConnectHost 和调用者级别的 strHost。正如我之前所说,
这使得该变量毫无用处(除了测试 Is Nothing 之外)。

我希望这能解释 strHost 的破坏。

WRT‘内存管理’:除了非常特殊的情况,你不需要
VBScript 中的清除/重置/SetToNothing 变量。在你的程序中使用局部变量
子/函数就是所需要的。如果您决定使用全局变量
并自己管理它们的状态,您必须注意变量类型:
改变对象的类型(包括Nothing)<=>非对象和说谎
通过误导性类型前缀来了解类型是危险的/肯定会导致灾难。
如果您认为必须清除 strHost,请将 Empty 或“”分配给 strConnectHost。

下一个补充

所有 VBScript 变量都是变体,但并非所有变体都是相同的:

>> s0 = "string"
>> s1 = CStr( 12.35 )
>> WScript.Echo TypeName( s0 ), TypeName( s1 )
>>
String String
>> n0 = 1
>> n1 = CByte( n0 )
>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Integer Byte

TypeName() 和 VarType() 显示子类型,程序员可以使用一组
C[hange/onvertTo]() 函数强制执行它们 - 在某种程度上,作为赋值
可能会“在幕后”改变类型。

>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Integer Byte
>> n0 = 1.1
>> n1 = 2 ^ 20
>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Double Double

甚至还有类型不匹配错误:

>> WScript.Echo Nothing
>>
Error Number:       13
Error Description:  Type mismatch
>>

>> WScript.Echo s0 Is Nothing
>>
Error Number:       424
Error Description:  Object required

所以子类型很重要。有些人认为类型前缀不酷,但其他人认为
它们对于弱类型语言来说是有价值的帮助。如果您决定使用它们,您
应该正确使用它们 -

   Set strWhatEver = objWhatever
   objWhatever = intWhatever
   intWhatever = objWhatever
   If strWhatEver = intWhatever Then

所有的味道(不注意类型并且很难确定后面代码中的错误)。

Set is used to assign objects to variables. Think of Nothing as a very special object

>> WScript.Echo IsObject(Nothing)
>>
-1

which is useful only to indicate the emptiness of the variable. Your

Set strConnectHost = Nothing

assigns this Nothing to strConnectHost. After that, the variable is good for nothing - it holds the empty object that can't be printed or used in computations or asked to do methods.

The type prefix fraud (*str*ConnectHost) should alert you that this is fishy. You work with strings (and numbers?); to clear/reset them use (simple) assignment with Empty:

>> strConnectHost = Empty
>>
>> WScript.Echo IsEmpty(strConnection)
>>
-1

or with a suitable value:

intWaitString = -1 ' or 0 ...

(assuming intWaitString isn't another type prefix fraud).

SECOND ATTEMPT:

I assume you call your sub like this:

strHost = "SomeHost"
prConnectToHost strHost

The relevant digest of your sub is:

Sub prConnectToHost( [ByRef] strConnectHost)
  ...
  Set strConnectHost = Nothing
End Sub

As VBScript uses by reference passing of parameters as default, your modification
changes the caller variable strHost. This happens to non-object variables too:

  Dim sVar : sVar = "String 0"
  WScript.Echo 0, sVar
  changeString sVar
  WScript.Echo 1, sVar

  Sub changeString( sByRefVar )
    sByRefVar = "String 1: changed by changeString( ByRef sByRefVar )"
  End Sub

output:

0 String 0
1 String 1: changed by changeString( ByRef sVar )

In your case the modification assigns Nothing to the variable that is called
strConnectHost in the Sub and strHost on the caller level. As I said before,
that makes the variable useless (except of testing for Is Nothing).

I hope that explains the clobbering of strHost.

WRT 'memory management': Except for very special cases, you don't need to
clear/reset/SetToNothing variables in VBScript. Using local variable in your
Subs/Functions is all that is necessary. If you decide to use global variables
and manage their state yourself, you must pay attention to the variable types:
Changing the type from object (including Nothing) <=> non-object and lying
about types by misleading type prefixes is dangerous/a sure way to desaster.
If you think you must clear strHost, assign Empty or "" to strConnectHost.

NEXT ADDITION

All VBScript variables are Variants, but not all Variants are created equal:

>> s0 = "string"
>> s1 = CStr( 12.35 )
>> WScript.Echo TypeName( s0 ), TypeName( s1 )
>>
String String
>> n0 = 1
>> n1 = CByte( n0 )
>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Integer Byte

TypeName() and VarType() show the sub-types and a progammer can use a set of
C[hange/onvertTo]<Type>() functions to enforce them - to a degree, as assignments
may change types 'under the hood'.

>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Integer Byte
>> n0 = 1.1
>> n1 = 2 ^ 20
>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Double Double

There are even Type Mismatch Errors:

>> WScript.Echo Nothing
>>
Error Number:       13
Error Description:  Type mismatch
>>

>> WScript.Echo s0 Is Nothing
>>
Error Number:       424
Error Description:  Object required

So sub-types matter. Some people think type prefixes are uncool, but others see
them as valuable help in weakly typed languages. If you decide to use them, you
should use them correctly -

   Set strWhatEver = objWhatever
   objWhatever = intWhatever
   intWhatever = objWhatever
   If strWhatEver = intWhatever Then

all smell (of not paying attention to types and hard to pin down errors in later code).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文