VBScript-错误0x80041017(空)

VBScript-错误0x80041017(空),vbscript,windows-xp,Vbscript,Windows Xp,重要更新: 正如Cheran S在下面所述,最好避免在这个脚本中使用“taskmgr”。我不打算编辑代码,因为我觉得最好尽可能多地保留原始问题,因为这样做会使Cheran的回答和评论部分无效和混淆。 替代“taskmgr”的一个好方法是“CharMap”(用于简单快速的测试)。 运行Windows XP Professional(32位)时,我有一个脚本抛出了这个错误: Script: C:\test.vbs Line: 40 Char: 3 Error: 0x800

重要更新:

正如Cheran S在下面所述,最好避免在这个脚本中使用“taskmgr”。我不打算编辑代码,因为我觉得最好尽可能多地保留原始问题,因为这样做会使Cheran的回答和评论部分无效和混淆。

替代“taskmgr”的一个好方法是“CharMap”(用于简单快速的测试)。


运行Windows XP Professional(32位)时,我有一个脚本抛出了这个错误:

Script:   C:\test.vbs
Line:     40
Char:     3
Error:    0x80041017
Code:     80041017
Source:   (null)
代码如下:

Set objWshShell = Wscript.CreateObject("Wscript.Shell")

Set objWshNet = CreateObject("Wscript.Network")
strComputer = objWshNet.ComputerName

Set objWMIService = GetObject("winmgmts:" & _
    "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Dim arrWinTitle(2)
    arrWinTitle(0) = "My Documents"
    arrWinTitle(1) = "Control Panel"

Dim arrProcName(3)
    arrProcName(0) = "'taskmgr.exe'"
    arrProcName(1) = "'calc.exe'"
    arrProcName(2) = "'notepad.exe'"

Sub srBlockWindow(strWinTitle, intWinTitle, strProcName, intProcName)
    i = 0
    Do While i = 0
        If objWshShell.AppActivate(strWinTitle(intWinTitle)) Then
            objWshShell.AppActivate(strWinTitle(intWinTitle))
            Wscript.Sleep 100
            objWshShell.SendKeys "%{F4}"
            Wscript.Sleep 100
        End If

        If intWinTitle = 0 Then
            intWinTitle = intWinTitle + 1
        Else
            intWinTitle = 0
        End If

        Wscript.Sleep 100

        Set colProcesses = objWMIService.ExecQuery _
            ("SELECT * FROM Win32_Process WHERE NAME = " & strProcName(intProcName))

        For Each objProcess In colProcesses
            objProcess.Terminate()
        Next

        If intProcName >= 0 Then
            intProcName = intProcName + 1
        ElseIf intProcName >= 5 Then
            intProcName = 0
        End If

        Set colProcesses = Nothing
    Loop
End Sub

Call srBlockWindow(arrWinTitle, 0, arrProcName, 0)
Set service = GetObject("winmgmts:")

Dim arrProcName(3)
    arrProcName(0) = "'taskmgr.exe'"
    arrProcName(1) = "'calc.exe'"
    arrProcName(2) = "'notepad.exe'"

Sub srTest(strProc, intProc)
    i = 0
    Do While i = 0
        For Each Process In Service.InstancesOf("Win32_Process")
            If Process.Name = strProc(intProc) Then
                Process.Name.Terminate
                Process.Terminate
            End If
        Next

        If intProc = 0 Then
            intProc = intProc + 1
        ElseIf intProc >= 3 Then
            intProc = 0
        End If
    Loop
End Sub

Call srTest(arrProcName, 0)
我已经复习过了,但我相信我的脚本在引用方面没有任何问题。为了清楚起见,我在“For Each…”字符串的开头得到了错误

奇怪的是,它在第一次运行时会运行良好,但一旦循环,我就会得到错误。因此,它将关闭所有需要的窗口/应用程序,但一旦它通过第二次迭代,我就会得到错误。我插入了“On Error Resume Next”(错误时继续下一步),但这并不能解决问题(我稍后会添加它,因为当窗口/进程与脚本的关闭/结束/停止尝试同时启动时,需要它来解决冲突)

我认为这是因为我应该有条件地检查流程是否存在;问题是,我不太确定如何使用这段代码(我从来都不擅长收集)。有人对如何具体使用此代码有什么建议吗?


我回顾并试图写一个快速的替代脚本,但它并没有真正起作用。代码如下:

Set objWshShell = Wscript.CreateObject("Wscript.Shell")

Set objWshNet = CreateObject("Wscript.Network")
strComputer = objWshNet.ComputerName

Set objWMIService = GetObject("winmgmts:" & _
    "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Dim arrWinTitle(2)
    arrWinTitle(0) = "My Documents"
    arrWinTitle(1) = "Control Panel"

Dim arrProcName(3)
    arrProcName(0) = "'taskmgr.exe'"
    arrProcName(1) = "'calc.exe'"
    arrProcName(2) = "'notepad.exe'"

Sub srBlockWindow(strWinTitle, intWinTitle, strProcName, intProcName)
    i = 0
    Do While i = 0
        If objWshShell.AppActivate(strWinTitle(intWinTitle)) Then
            objWshShell.AppActivate(strWinTitle(intWinTitle))
            Wscript.Sleep 100
            objWshShell.SendKeys "%{F4}"
            Wscript.Sleep 100
        End If

        If intWinTitle = 0 Then
            intWinTitle = intWinTitle + 1
        Else
            intWinTitle = 0
        End If

        Wscript.Sleep 100

        Set colProcesses = objWMIService.ExecQuery _
            ("SELECT * FROM Win32_Process WHERE NAME = " & strProcName(intProcName))

        For Each objProcess In colProcesses
            objProcess.Terminate()
        Next

        If intProcName >= 0 Then
            intProcName = intProcName + 1
        ElseIf intProcName >= 5 Then
            intProcName = 0
        End If

        Set colProcesses = Nothing
    Loop
End Sub

Call srBlockWindow(arrWinTitle, 0, arrProcName, 0)
Set service = GetObject("winmgmts:")

Dim arrProcName(3)
    arrProcName(0) = "'taskmgr.exe'"
    arrProcName(1) = "'calc.exe'"
    arrProcName(2) = "'notepad.exe'"

Sub srTest(strProc, intProc)
    i = 0
    Do While i = 0
        For Each Process In Service.InstancesOf("Win32_Process")
            If Process.Name = strProc(intProc) Then
                Process.Name.Terminate
                Process.Terminate
            End If
        Next

        If intProc = 0 Then
            intProc = intProc + 1
        ElseIf intProc >= 3 Then
            intProc = 0
        End If
    Loop
End Sub

Call srTest(arrProcName, 0)
如您所见,我尝试了“Process.Terminate”和“Process.Name.Terminate”,但都没有得到任何结果(甚至没有错误)。我用“Wscript.Echo Process.Name”和“Wscript.Echo strProc(intProc)”进一步测试了它,但这两种方法都不起作用

现在我在这个替代方案上失败了,我感觉我在黑暗中疯狂地寻找解决方案,所以我将把这些深奥的挑战推迟到比我优越得多的社区


这里可能有一些人正在阅读这篇文章,并想知道为什么我要将目标锁定在我的文档、控制面板、taskmgr.exe、calc.exe和notepad.exe上。几乎每一个读到这篇文章的人都有可能自己推断,但我会确保我对那些需要它的人清楚这一点。我这样做是因为它使测试更容易,因为所有这些都可以通过使用“运行”快捷方式(Windows键+R)访问&然后输入以下字符串(当然,一次一个):

  • 我的文件
  • 控制
  • 任务经理
  • 计算
  • 记事本
你可能知道这些关键词,但我只是想强调一下我为什么要使用这些特定的关键词(速度和简单性)


如果Cheran将最终代码添加到发布的答案中,我将删除此选项

最终解决方案:

Set objWshShell = Wscript.CreateObject("Wscript.Shell")

Set objWshNet = CreateObject("Wscript.Network")
strComputer = objWshNet.ComputerName

Set objWMIService = GetObject("winmgmts:" & _
    "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Dim arrWinTitle
    arrWinTitle = Array("My Documents", "Control Panel")

Dim arrProcName
    arrProcName = Array("'charmap.exe'", "'calc.exe'", "'notepad.exe'")

Sub srBlockWindow(strWinTitle, intWinTitle, strProcName, intProcName)
    i = 0
    Do While i = 0
        On Error Resume Next
            ' In the Event of Conflict w/Initiation of Window or Process
        If objWshShell.AppActivate(strWinTitle(intWinTitle)) Then
            objWshShell.AppActivate(strWinTitle(intWinTitle))
            Wscript.Sleep 100
            objWshShell.SendKeys "%{F4}"
            Wscript.Sleep 100
        End If

        intWinTitle = (intWinTitle + 1) Mod (UBound(strWinTitle) + 1)

        Wscript.Sleep 100

        Set colProcesses = objWMIService.ExecQuery _
            ("SELECT * FROM Win32_Process WHERE NAME = " & strProcName(intProcName))

        For Each objProcess In colProcesses
            objProcess.Terminate()
        Next

        intProcName = (intProcName + 1) Mod (UBound(strProcName) + 1)

        Set colProcesses = Nothing
    Loop
End Sub

Call srBlockWindow(arrWinTitle, 0, arrProcName, 0)
下面是我编写的一个快速脚本,用于测试它:

Set objWshShell = Wscript.CreateObject("Wscript.Shell")

i = 0
Do While i = 0
    objWshShell.Run "explorer.exe /e, C:\Documents and Settings\User\My Documents"
    Wscript.Sleep 200
    objWshShell.Run "CharMap.exe"
    Wscript.Sleep 200
    objWshShell.Run "Control.exe"
    Wscript.Sleep 200
    objWshShell.Run "calc.exe"
    Wscript.Sleep 200
    objWshShell.Run "notepad.exe"
    Wscript.Sleep 200
Loop

小心!调整计时,以便结束“Wscript.exe”时不会出现太多问题。最好同时运行这两个脚本,看看它是如何工作的。

我发现了两个大问题:

  • 这里的主要问题是定义数组的方式。在数组声明中指定的数字是最大的数组下标。由于VBScript数组的索引始终从0开始,因此实际上需要指定一个小于数组中元素数的值

    ' This is wrong:
    Dim arrWinTitle(2)
    Dim arrProcName(3)
    
    ' Should be:
    Dim arrWinTitle(1)
    Dim arrProcName(2)
    
    如果事先知道数组中有多少个元素,也可以使用该函数初始化数组。在这种情况下,您只需将
    arrWinTitle
    声明为变量,而不是数组:

    Dim arrWinTitle
    arrWinTitle = Array("My Documents", "Control Panel")
    
  • 如果进行了更改并尝试运行脚本,仍然会出现“下标超出范围”错误。该错误是由以下块引起的:

    If intProcName >= 0 Then
        intProcName = intProcName + 1
    ElseIf intProcName >= 5 Then
        intProcName = 0
    End If
    
    首先,strProcName的最大下标应该是2,而不是5。即使这样,这个代码也不会工作。看起来您要做的是循环遍历数组的元素,然后在0处重新开始。更好的方法是使用操作员:

    intProcName = (intProcName + 1) Mod (UBound(strProcName) + 1)
    
    还要注意我如何使用该函数来避免对数组的实际长度进行硬编码

  • ' This is wrong:
    Dim arrWinTitle(2)
    Dim arrProcName(3)
    
    ' Should be:
    Dim arrWinTitle(1)
    Dim arrProcName(2)
    


    我不会花太多时间分析你的第二个例子,因为它只是试图让第一个例子起作用。但是,我要注意的是,在
    arrProcName
    数组中,进程名的周围仍然有单引号,这也是该脚本无法工作的原因之一。

    当脚本应该在无限循环中运行时,您可能不想使用“taskmgr.exe”作为示例进程名,尤其是在社区网站上发布时。如何停止“wscript.exe”进程?(当然,我只是在运行代码而没有首先检查它,这让我感到羞耻…@Cheran S-LOL,对不起;我有退路了。我从来没有考虑过这个问题,原因有两个:(1)我没有工作代码,rofl。(2) 我在运行对话框中使用此命令:
    TaskKill/Im Wscript.exe/F
    。有一个警告:我运行的是XP Professional客户端,“TaskKill”命令只适用于XP Pro。XP Home的替代方案是
    TsKill Wscript
    。我相信这一原则适用于所有家庭版和专业版(XP/Vista/7)。再一次抱歉,呜呜!关于你的第二点,我完全忘记了将ElseIf字符串编辑为2!我使用了更多的项目进行原型设计,并从第二个阵列中删除了一些项目,但我没有清理交互代码块。给我一些时间来消化你的文章,因为你对数组函数、Mod操作符和UBound函数的使用对我来说都是新的(感谢你记住我是一个完全的新手&添加了那些资源链接!)。在我测试并弄清楚整个脚本应该是什么样子之后,我会确保给您打上“复选标记”。你不必像上次那样等那么久,