VBScript - ошибка 0x80041017 (ноль) - PullRequest
2 голосов
/ 26 марта 2011

ВАЖНОЕ ОБНОВЛЕНИЕ:

Как Cheran S заявил ниже, это хорошая идея, чтобы избежать использования «taskmgr» для этого скрипта. Я не собираюсь редактировать код, так как считаю, что лучше сохранить исходный вопрос в максимально возможной степени, поскольку это частично аннулирует и запутывает ответ и комментарий Черана.

Хорошей альтернативой «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)

Я просмотрел это , но я считаю, что у моего скрипта нет проблем с кавычками. Для ясности я получаю сообщение об ошибке в начале строки "For Each ...".

Что особенного в том, что он будет работать нормально с первого раза, но как только он зациклится, вот когда я получаю ошибку. Таким образом, он закроет все нужные Windows / приложения, но как только он пройдет вторую итерацию, я получу ошибку. Я вставил «On Error Resume Next», но это не решает проблему (я добавлю его позже, так как это необходимо для разрешения конфликта, когда Window / Process запускается одновременно с попытками Close / End / Stop, выполненными сценарием ).

Я думаю, это потому, что я должен условно проверить, существует ли процесс; проблема в том, что я не совсем уверен, как это сделать с этим кодом (я никогда не был хорош с коллекциями). У кого-нибудь есть предложения, как это сделать с этим кодом конкретно?

<ч />

Я просмотрел это и попытался написать быстрый альтернативный скрипт, но он не сработал. Вот код:

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 Key + R), а затем вводя следующие строки (по одной, разумеется):

  • Мои документы
  • Контроль
  • Урочная
  • известково
  • блокнот

Вы, вероятно, знали ключевые слова, но я просто хотел выделить , почему Я использую эти конкретные (скорость и простота).

<ч />

Я уберу это, если Черан добавит окончательный код к опубликованному ответу

Окончательное решение:

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 без особых проблем. Лучше всего запустить оба сценария одновременно, чтобы увидеть, как он работает.

1 Ответ

1 голос
/ 27 марта 2011

Две большие проблемы, которые я обнаружил:

  1. Основная проблема здесь в том, как вы определяете свои массивы.Число, указанное в объявлении массива, является наибольшим индексом массива.Поскольку массивы VBScript всегда индексируются, начиная с 0, вам действительно нужно указать на единицу меньше, чем количество элементов в массиве.

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

    Вы также можете использовать функцию Arrayинициализировать ваш массив, предполагая, что вы заранее знаете, сколько в нем элементов.В этом случае вы просто объявите arrWinTitle как вариант, а не как массив:

    Dim arrWinTitle
    arrWinTitle = Array("My Documents", "Control Panel")
    
  2. Если вы сделаете это изменение и попытаетесь запустить скрипт, вывсе еще получаю ошибку «Subscript out of range».Эта ошибка вызвана этим блоком:

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

    Во-первых, максимальный индекс должен быть 2 для strProcName, а не 5. Даже тогда этот код не будет работать.Похоже, что вы пытаетесь сделать цикл элементов массива, а затем начать заново с 0. Лучше всего сделать это с помощью оператора Mod:

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

    Обратите также внимание на то, как я использую функцию UBound, чтобы избежать жесткого кодирования фактической длины массива.


Я не будупотратьте слишком много времени на анализ вашего второго примера, поскольку это была просто попытка заставить первый пример работать.Однако я отмечу, что в вашем массиве arrProcName имена процессов по-прежнему заключены в одинарные кавычки, что является одной из причин, по которой этот скрипт тоже не работал.

...