VBScript - 错误 0x80041017(空) [英] VBScript - Error 0x80041017 (null)

查看:79
本文介绍了VBScript - 错误 0x80041017(空)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

重要更新:

正如 Cheran S 下文所述,避免在此脚本中使用taskmgr"是个好主意.我不打算编辑代码,因为我觉得最好尽可能保留原始问题,因为这样做会使 & 部分无效.混淆 Cheran 的回答 &评论.

taskmgr"的一个很好的替代方案是CharMap"(用于简单和快速测试).


在运行 Windows XP Professional(32 位)时,我得到了一个抛出此错误的脚本:

脚本:C:\test.vbs线路:40字符:3错误:0x80041017代码:80041017来源:(空)

代码如下:

Set objWshShell = Wscript.CreateObject("Wscript.Shell")Set objWshNet = CreateObject("Wscript.Network")strComputer = objWshNet.ComputerNameSet objWMIService = GetObject("winmgmts:" & _"{impersonationLevel=impersonate}!\\" &strComputer &"\root\cimv2")Dim arrWinTitle(2)arrWinTitle(0) = "我的文档"arrWinTitle(1) = "控制面板"Dim arrProcName(3)arrProcName(0) = "'taskmgr.exe'"arrProcName(1) = "'calc.exe'"arrProcName(2) = "'notepad.exe'"Sub srBlockWindow(strWinTitle, intWinTitle, strProcName, intProcName)我 = 0当 i = 0 时如果 objWshShell.AppActivate(strWinTitle(intWinTitle)) 然后objWshShell.AppActivate(strWinTitle(intWinTitle))Wscript.Sleep 100objWshShell.SendKeys "%{F4}"Wscript.Sleep 100万一如果 intWinTitle = 0 那么intWinTitle = intWinTitle + 1别的intWinTitle = 0万一Wscript.Sleep 100设置 colProcesses = objWMIService.ExecQuery _("SELECT * FROM Win32_Process WHERE NAME = " & strProcName(intProcName))对于 colProcesses 中的每个 objProcessobjProcess.Terminate()下一个如果 intProcName >= 0 那么intProcName = intProcName + 1ElseIf intProcName >= 5 那么intProcName = 0万一设置 colProcesses = 无环形结束子调用 srBlockWindow(arrWinTitle, 0, arrProcName, 0)

我已经查看了这个,但我相信我的脚本没有任何引号问题.为了清楚起见,我在For Each ..."字符串的开头收到了错误.

奇怪的是,它第一次运行良好,但一旦循环,就会出现错误.因此,它将关闭所有所需的 Windows/应用程序,但是一旦它通过第二次迭代,我就会收到错误消息.我已经插入了On Error Resume Next",但这并没有解决它(我稍后会添加它,因为当窗口/进程同时启动时需要解决冲突).

我认为是因为我应该有条件地检查进程是否存在;问题是,我不太确定如何用这段代码来做到这一点(我从来不擅长使用 Collections).有人对如何具体使用此代码提出建议吗?


我查看了 this 并试图编写一个快速的替代脚本,但它并没有真正起作用.代码如下:

Set service = GetObject("winmgmts:")Dim arrProcName(3)arrProcName(0) = "'taskmgr.exe'"arrProcName(1) = "'calc.exe'"arrProcName(2) = "'notepad.exe'"子 srTest(strProc, intProc)我 = 0当 i = 0 时对于 Service.InstancesOf("Win32_Process") 中的每个进程如果 Process.Name = strProc(intProc) 那么进程.名称.终止处理.终止万一下一个如果 intProc = 0 那么intProc = intProc + 1ElseIf intProc >= 3 那么内部处理 = 0万一环形结束子调用 srTest(arrProcName, 0)

如您所见,我尝试了Process.Terminate"和Process.Terminate"Process.Name.Terminate",但都没有产生任何结果(甚至没有错误).我进一步测试了Wscript.Echo Process.Name"&Wscript.Echo strProc(intProc)",但这些都不起作用.

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


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

  • 我的文档
  • 控制
  • taskmgr
  • 计算
  • 记事本

您可能知道这些关键字,但我只是想强调为什么我要使用这些特定的关键字(速度和简单性).


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

最终解决方案:

Set objWshShell = Wscript.CreateObject("Wscript.Shell")Set objWshNet = CreateObject("Wscript.Network")strComputer = objWshNet.ComputerNameSet objWMIService = GetObject("winmgmts:" & _"{impersonationLevel=impersonate}!\\" &strComputer &"\root\cimv2")Dim arrWinTitlearrWinTitle = Array("我的文档", "控制面板")Dim arrProcNamearrProcName = Array("'charmap.exe'", "'calc.exe'", "'notepad.exe'")Sub srBlockWindow(strWinTitle, intWinTitle, strProcName, intProcName)我 = 0当 i = 0 时出错时继续下一步' 在与窗口或进程启动发生冲突的情况下如果 objWshShell.AppActivate(strWinTitle(intWinTitle)) 然后objWshShell.AppActivate(strWinTitle(intWinTitle))Wscript.Sleep 100objWshShell.SendKeys "%{F4}"Wscript.Sleep 100万一intWinTitle = (intWinTitle + 1) Mod (UBound(strWinTitle) + 1)Wscript.Sleep 100设置 colProcesses = objWMIService.ExecQuery _("SELECT * FROM Win32_Process WHERE NAME = " & strProcName(intProcName))对于 colProcesses 中的每个 objProcessobjProcess.Terminate()下一个intProcName = (intProcName + 1) Mod (UBound(strProcName) + 1)设置 colProcesses = 无环形结束子调用 srBlockWindow(arrWinTitle, 0, arrProcName, 0)

这是我拼凑起来用来测试的快速脚本:

Set objWshShell = Wscript.CreateObject("Wscript.Shell")我 = 0当 i = 0 时objWshShell.Run "explorer.exe/e, C:\Documents and Settings\User\My Documents"Wscript.Sleep 200objWshShell.Run "CharMap.exe"Wscript.Sleep 200objWshShell.Run "Control.exe"Wscript.Sleep 200objWshShell.Run "calc.exe"Wscript.Sleep 200objWshShell.Run "notepad.exe"Wscript.Sleep 200环形

小心!调整时间,以便您可以在没有太多问题的情况下结束Wscript.exe".最好同时运行这两个脚本,看看它是如何工作的.

解决方案

我发现的两个大问题:

  1. 这里的主要问题在于您定义数组的方式.您在数组声明中指定的数字是最大的数组下标.由于 VBScript 数组总是从 0 开始索引,因此您实际上需要指定比数组中元素数少 1 的值.

    ' 这是错误的:Dim arrWinTitle(2)Dim arrProcName(3)' 应该:Dim arrWinTitle(1)Dim arrProcName(2)

    您还可以使用 Array 函数来初始化您的数组,假设您事先知道其中有多少个元素.在这种情况下,您只需将 arrWinTitle 声明为 Variant 而不是数组:

    Dim arrWinTitlearrWinTitle = Array("我的文档", "控制面板")

  2. 如果您进行更改并尝试运行脚本,您仍会收到下标超出范围"错误.该错误是由该块引起的:

    如果 intProcName >= 0 那么intProcName = intProcName + 1ElseIf intProcName >= 5 那么intProcName = 0万一

    首先,strProcName 的最大下标应该是 2,而不是 5.即使这样,这段代码也不起作用.看起来你想要做的是循环遍历数组的元素,然后从 0 开始.更好的做法是使用 Mod 运算符:

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

    还要注意我如何使用 UBound 函数以避免对数组的实际长度进行硬编码.

<小时>

我不会花太多时间分析您的第二个示例,因为这只是尝试使第一个示例工作.但是,我会注意到,在您的 arrProcName 数组中,进程名称仍然带有单引号,这也是该脚本不起作用的原因之一.

IMPORTANT UPDATE:

As Cheran S stated below, it's a good idea to avoid using "taskmgr" for this script. I'm not going to edit the code, as I feel it's best to maintain the original question as much as possible since doing so would partially invalidate & obfuscate Cheran's answer & comment.

A good alternative to "taskmgr" would be "CharMap" (for simple & fast testing).


Running Windows XP Professional (32-bit) and I've got this script that's throwing up this error:

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

Here's the code:

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)

I've reviewed this, but I believe my script doesn't have any issues with the quotes. For the sake of clarity, I'm getting the error at the start of the "For Each ..." string.

What's peculiar is that it will run fine the first time, but once it loops, that's when I get the error. So, it will close all the desired Windows/Applications, but once it goes through it's second iteration, I get the error. I've inserted "On Error Resume Next", but that doesn't resolve it (I will add it later, since it's required to resolve the conflict when the Window/Process Starts simultaneously with Close/End/Stop attempts made by the Script).

I think it's because I should be conditionally checking if the process exists; problem is, I'm not quite sure how to do that with this code (I've never been good with Collections). Anybody have suggestions on how to do it with this code specifically?


I reviewed this and tried to write a quick alternative script, but it didn't really work. Here's the code:

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)

As you can see, I tried both "Process.Terminate" & "Process.Name.Terminate", but neither yielded anything (not even an error). I further tested it with "Wscript.Echo Process.Name" & "Wscript.Echo strProc(intProc)", but neither of these worked too.

Now that I've failed at this alternative solution, I'm feeling that I'm wildly stabbing in the dark for solutions, so I'll defer these esoteric challenges to the community that is vastly superior to me.


There might be a few here who are reading this and wondering why I'm targeting My Documents, Control Panel, taskmgr.exe, calc.exe, & notepad.exe. Almost everybody reading this will probably be able to extrapolate on their own, but I'll make sure I'm clear on this for those who need it. I'm doing this because it makes it easier to test, since all of these can be accessed simply by using the "Run" shortcut (Windows Key + R) & then entering the following strings (one at a time, of course):

  • My Documents
  • Control
  • taskmgr
  • calc
  • notepad

You likely knew the keywords, but I just wanted to highlight why I'm using these specific ones (speed & simplicity).


I'll remove this if Cheran adds the final code to the answer posted

Final Solution:

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)

Here's a quick script I threw together to test it against:

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

BE CAREFUL! Adjust the timings so that you can end "Wscript.exe" without too many problems. Best to run both scripts simultaneously to see how it works.

解决方案

Two big issues I found:

  1. The main problem here is in the way you define your arrays. The number you specify in the array declaration is the largest array subscript. Since VBScript arrays are always indexed starting at 0, you actually need to specify one less than the number of elements in the array.

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

    You could also use the Array function to initialize your array, assuming that you know beforehand how many elements are in it. In that case, you would just declare arrWinTitle as a Variant and not as an array:

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

  2. If you make that change and try to run the script, you'll still get a "Subscript out of range" error. That error is caused by this block:

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

    First off, the maximum subscript should be 2 for strProcName, and not 5. Even then, this code won't work. It seems like what you're trying to do is loop through the elements of array, then start over back at 0. A better of doing this is with the Mod operator:

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

    Notice also how I use the UBound function to avoid hard-coding the actual length of the array.


I won't spend too much time analyzing your second example, since it was just an attempt to make the first example work. I will note, however, that in your arrProcName array, the process names still have the single quotes around them, which is one reason why that script didn't work either.

这篇关于VBScript - 错误 0x80041017(空)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆