Форум программистов, компьютерный форум, киберфорум
Jack Famous
Войти
Регистрация
Восстановить пароль
Карта форума Блоги Сообщество Поиск Заказать работу  
Оценить эту запись

Как использовать командную строку? | VBA. How to use Cmd. Function «Shell()», Object «WshShell» and others

Запись от Jack Famous размещена 22.05.2024 в 12:04
Обновил(-а) Jack Famous 22.05.2024 в 12:18
Метки cmd, shell, vba, wshshell

Начинаю цикл тем о командной строке — чтобы зафиксировать полученный опыт для себя и других.
Шапка темы (этот пост) будет обновляться — здесь будут фиксироваться готовые приёмы и задаваться очередные вопросы для последующего разбора в постах темы.
Оставляю за собой право на ошибки и неточности. Прошу сообщать при их обнаружении.
Function Shell()
VBA Excel. Функция Shell
Основных моменты:
• не требует подключения дополнительных библиотек. Не помню, в какой из обязательных (для работы VBA) она находится.
• возвращает ID запущенного процесса. Можно сравнить ответ функции с ID, указанным в "Подробностях" Диспетчера задач (на скринах ниже).
• асинхронная. То есть, после ОТПРАВКИ команды на исполнение, код VBA продолжит работу НЕМЕДЛЕННО, не дожидаясь окончания выполнения. Практически никогда такое поведение не нужно и опасно. Фиксится использованием оболочки из API (покажу далее). В качестве универсального костыльного варианта — можно проверять ожидаемый итог исполнения команды (например, файлов в папке должно стать больше на один) в бесконечном цикле, пока итог не совпадёт. Как вы понимаете, применить этот костыль можно далеко не всегда.
• второй параметр — видимость окна. Например, 0 (или vbHide) отвечает за его скрытие, а 1 (или vbNormalFocus) — за передачу фокуса (переключение). Если вам нужно просто выполнить команду, то используйте 0 (если вы вызываете приложение, то оно будет запущено и, немедленно, скрыто), а, если вам нужно работать с, например, приложением, запущенным по команде, через его (приложения) интерфейс — нужно передать фокус.
• просто отправляет команду на исполнение. Никак не работает с ответом на команду.
Пример разных вызовов штатного блокнота (путь должен существовать)
Visual Basic
1
2
3
4
5
6
Private Sub Test_Shell()
Dim n&
    n = Shell("C:\WINDOWS\NOTEPAD.EXE", vbHide)         ' Run Notepad and Hide it immediately
    n = Shell("C:\WINDOWS\NOTEPAD.EXE", vbNormalFocus)  ' Run Notepad and set it Active
    Debug.Print n
End Sub
Скрины сравнения ответа Shell() и ID из диспетчера
Нажмите на изображение для увеличения
Название: Shell_NotePad_Immediate.png
Просмотров: 36
Размер:	6.5 Кб
ID:	8709Нажмите на изображение для увеличения
Название: Shell_NotePad.png
Просмотров: 43
Размер:	20.1 Кб
ID:	8708
Функция для синхронизации Shell() с помощью API (x64 Only)
Пример вызова: Debug.Print PRDX_API_ShellAndWait("C:\WINDOWS\NOTEPAD.EXE", True, True)
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Option Base 1
Option Explicit
Option Private Module
'==================================================================================================
Public Const PROCESS_QUERY_INFORMATION& = &H400, SYNCHRONIZE = &H100000, STILL_ACTIVE& = &H103
Public Const vc_Cyc_2bil& = 2000000000
'==================================================================================================
Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32.dll" (ByVal hProcess As Long, lpExitCode As Long) As Long
'==================================================================================================
Function PRDX_API_ShellAndWait(sCommand$, Optional MsgTrue As Boolean, Optional MsgFalse As Boolean) As Boolean
Dim p&, c&, e&, n&
 
p = Shell(sCommand, 0):                        If (p = 0) Then If MsgFalse Then MsgBox "Shell with command:" & vbLf & sCommand & vbLf & "is OUT!", vbCritical, "PRDX_API_ShellAndWait": Exit Function Else Exit Function
p = OpenProcess(PROCESS_QUERY_INFORMATION, 0, p):   If (p = 0) Then If MsgFalse Then MsgBox "OpenProcess of Shell with command:" & vbLf & sCommand & vbLf & "is OUT!", vbCritical, "PRDX_API_ShellAndWait": Exit Function Else Exit Function
 
For n = 1 To vc_Cyc_2bil
    e = GetExitCodeProcess(p, c): DoEvents:         If (e = 0) Then If MsgFalse Then MsgBox "GetExitCodeProcess of Shell with command:" & vbLf & sCommand & vbLf & "is OUT!", vbCritical, "PRDX_API_ShellAndWait": Exit Function Else Exit Function
    If (c <> STILL_ACTIVE) Then Exit For
Next n
 
If (n > vc_Cyc_2bil) Then n = 0:                    If MsgFalse Then MsgBox "Cycle to GetExitCodeProcess of Shell with command:" & vbLf & sCommand & vbLf & "was LOOPED!", vbCritical, "PRDX_API_ShellAndWait": Exit Function Else Exit Function
 
PRDX_API_ShellAndWait = True:                       If MsgTrue Then MsgBox "Shell with command:" & vbLf & sCommand & vbLf & "was succsessfully finished in " & Format$(n, "#,#") & " Cycles!", vbInformation, "PRDX_API_ShellAndWait"
End Function
Показов 478 Комментарии 1
Всего комментариев 1
Комментарии
  1. Старый комментарий
    andypetr (на Планете):
    n = Shell("C:\WINDOWS\NOTEPAD.EXE", vbHide)
    Процесс notepad.exe продолжает выполняться, но без визуализации (Диспетчер задач - Подробности).
    Полностью согласен. Спасибо. Поправил.
    Запись от Jack Famous размещена 22.05.2024 в 12:18 Jack Famous вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru