开发者

VBScript - Error 0x80041017 (null)

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
   开发者_如何学Go 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜