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:
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 declarearrWinTitle
as a Variant and not as an array:Dim arrWinTitle arrWinTitle = Array("My Documents", "Control Panel")
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 theMod
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.
精彩评论