【发布时间】:2011-07-23 05:38:49
【问题描述】:
重要更新:
正如 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)
我已经查看了this,但我相信我的脚本对引号没有任何问题。为了清楚起见,我在“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'"
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”而不会出现太多问题。最好同时运行两个脚本,看看它是如何工作的。
【问题讨论】:
-
当您的脚本应该在无限循环中运行时,尤其是在社区站点上发布时,您可能不想使用“taskmgr.exe”作为示例进程名称。如何停止“wscript.exe”进程? (当然,我为自己运行代码而没有先检查它而感到羞耻......)
-
@Cheran S - 大声笑,对不起;我有一个后退。我从来没有考虑过这个问题,原因有两个:(1)我没有工作代码,rofl。 (2) 我在运行对话框中使用这个命令:
TaskKill /Im Wscript.exe /F。有一个警告:我正在运行 XP Professional 客户端,而“TaskKill”命令仅适用于 XP Pro。 XP Home 的替代方案是TsKill Wscript。我相信这个原则适用于所有家庭版和专业版(XP/Vista/7)。再次抱歉。
标签: vbscript windows-xp