1

Тема: VBScript: запуск файлов ассоциированным приложением

Автор данной статьи - alexii.

Некоторые особенности методов DoIt, InvokeVerb, InvokeVerbEx, ShellExecute объекта автоматизации Shell.Application и метода Run объекта автоматизации WScript.Shell.

При опосредованном запуске приложений посредством методов DoIt, InvokeVerb, InvokeVerbEx, ShellExecute объекта автоматизации Shell.Application и метода Run объекта автоматизации WScript.Shell может возникнуть ситуация, что методы не будут работать как ожидается. Это может быть связано с тем, что скрипт завершает свою работу, прежде чем методы успевают отработать. Обычно подобное наблюдается, когда эти методы используются для опосредованного запуска «тяжёлых» приложений.

Демонстрация:

В папке C:\ShellExecute Demonstration находятся:
— текстовый файл Sample.txt;
— файлы Microsoft Word Sample.doc, Sample2.doc и Sample3.doc;
— файлы Microsoft Excel Sample.xls и Sample2.xls.

Option Explicit

Dim objShell

LogOut WScript.ScriptName & " started."

Set objShell = WScript.CreateObject("Shell.Application")

LogOut "Try run WinWord.exe by ShellExecute method"
objShell.ShellExecute "Sample.doc", "", "C:\ShellExecute Demonstration", "", 1

LogOut "Try run Notepad.exe by ShellExecute method"
objShell.ShellExecute "Sample.txt", "", "C:\ShellExecute Demonstration", "", 1

Set objShell = Nothing

LogOut WScript.ScriptName & " finished."

WScript.Quit 0

'=============================================================================
Function LogOut(varValue)
    WScript.Echo CStr(Now()) & " : " & CStr(varValue)
End Function
'=============================================================================

В большинстве случаев строка скрипта

objShell.ShellExecute "Sample.txt", "", "C:\ShellExecute Demonstration", "", 1

отработает корректно и откроет приложение Notepad.exe c файлом C:\ShellExecute Demonstration\Sample.txt, а при исполнении строки

objShell.ShellExecute "Sample.doc", "", "C:\ShellExecute Demonstration", "", 1

может произойти:
— будет открыто приложение WinWord.exe с файлом C:\ShellExecute Demonstration\Sample.doc;
— будет открыто приложение WinWord.exe;
— будет запущен процесс WinWord.exe (окно приложения не появляется);
— ничего не произойдёт;

Если после вызова этих методов добавить в скрипт паузу некоторой длительности, то указанные методы отработают корректно (необходимое значение времени приостановки работы скрипта может зависеть от многих факторов, как-то: общего быстродействия компьютера, наличия антивируса и включённых эвристик проверки, размера открываемого файла, дефрагментации диска):

Option Explicit

Dim objShell

LogOut WScript.ScriptName & " started."

Set objShell = WScript.CreateObject("Shell.Application")

LogOut "Try run WinWord.exe by ShellExecute method"
objShell.ShellExecute "Sample.doc", "", "C:\ShellExecute Demonstration", "", 1

LogOut "Try run Notepad.exe by ShellExecute method"
objShell.ShellExecute "Sample.txt", "", "C:\ShellExecute Demonstration", "", 1

' Приостановка работы скрипта на 10 секунд
WScript.Sleep 10000

Set objShell = Nothing

LogOut WScript.ScriptName & " finished."

WScript.Quit 0

'=============================================================================
Function LogOut(varValue)
    WScript.Echo CStr(Now()) & " : " & CStr(varValue)
End Function
'=============================================================================

Замечание: обратите внимание, что окно более «легкого» приложения Notepad.exe может появиться первым, несмотря на то, что опосредованно запускается вторым.

Подобным образом можно попробовать добиться корректной работы во всех перечисленных методах:

Option Explicit

Dim objShell
Dim objNameSpace
Dim objFolderItem
Dim objVerb

Dim objWshShell

LogOut WScript.ScriptName & " started."

Set objShell = WScript.CreateObject("Shell.Application")

LogOut "Try run WinWord.exe by ShellExecute method"
objShell.ShellExecute "Sample.doc", "", "C:\ShellExecute Demonstration", "", 1

Set objNameSpace = objShell.NameSpace("C:\ShellExecute Demonstration")

LogOut "Try run WinWord.exe by InvokeVerb method"
Set objFolderItem = objNameSpace.ParseName("Sample2.doc")
objFolderItem.InvokeVerb

LogOut "Try run WinWord.exe by InvokeVerbEx method"
Set objFolderItem = objNameSpace.ParseName("Sample3.doc")
objFolderItem.InvokeVerbEx

LogOut "Try run Excel.exe by DoIt method"
Set objFolderItem = objNameSpace.ParseName("Sample.xls")

For Each objVerb In objFolderItem.Verbs()
    If objVerb.Name = "&Открыть" Then
        objVerb.DoIt
        
        Exit For
    End If
Next

LogOut "Try run Excel.exe by Run method"
Set objWshShell = WScript.CreateObject("WScript.Shell")
objWshShell.Run """" & "C:\ShellExecute Demonstration\Sample2.xls" & """"

LogOut "Try run Notepad.exe by ShellExecute"
objShell.ShellExecute "Sample.txt", "", "C:\ShellExecute Demonstration", "", 1

' Приостановка работы скрипта на 20 секунд
WScript.Sleep 20000

Set objWshShell = Nothing

Set objVerb = Nothing
Set objFolderItem = Nothing
Set objNameSpace = Nothing
Set objShell = Nothing

LogOut WScript.ScriptName & " finished."

WScript.Quit 0

'=============================================================================
Function LogOut(varValue)
    WScript.Echo CStr(Now()) & " : " & CStr(varValue)
End Function
'=============================================================================

Ещё одна особенность библиотеки SHELL32.dll проявляется в следующем примере:

Option Explicit

Dim objShell
Dim objNameSpace
Dim objFolderItem

Set objShell = WScript.CreateObject("Shell.Application")
Set objNameSpace = objShell.NameSpace("C:\ShellExecute Demonstration")
Set objFolderItem = objNameSpace.ParseName("Sample.txt")

objFolderItem.InvokeVerb "properties"

WScript.Sleep 5000

Set objFolderItem = Nothing
Set objNameSpace = Nothing
Set objShell = Nothing

WScript.Quit 0

Данный скрипт отображает окно свойств файла C:\ShellExecute Demonstration\Sample.txt (такое же, которое появится при выборе пункта Свойства контекстного меню файла в Проводнике). После того, как скрипт завершит свою работу, это окно будет автоматически закрыто. Если же убрать команду

WScript.Sleep 5000

это окно не отобразится вовсе.

Примечание от The gray Cardinal: похоже, вышеописанные методы DoIt, InvokeVerb, InvokeVerbEx, ShellExecute запускаются асинхронно. Если взять код, отвечающий за организацию паузы, и переставить его после очистки объектов, то ничего не изменится — всё по-прежнему будет работать. Поэтому, похоже, проблема заключается даже не в безвременном "R.I.P." объектов, а именно в завершении всего скрипта.

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