Shell и другие способы

  • Автор темы Автор темы PavelT100
  • Дата начала Дата начала
Скажите пожалуйста, а как определить окончание завершения уже запущенной задачи ?

И еще: если вызываю калькулятор или блокнот, то все работает, но строка :

ReturnCode = WShell.Run("C:\Program Files\PDFCreator\PDFCreator.exe", 1, True)

выдает ошибку
 
Скажите пожалуйста, а как определить окончание завершения уже запущенной задачи ?
Например так. Получить хэндл интересующего процесса и выполнить на нём WaitForSingleObject.
Для этого перебираем все активные процессы. Для каждого процесса перебираем загруженные исполняемые модули (exe, dll), в поисках интересующего exe-шника (процессов может оказаться более одного). И для интересующих процессов выполняем WaitForSingleObject или WaitForMultipleObjects. Пример перебора процессов и модулей из MSDN на C++:

Код:
void PrintProcessNameAndID( DWORD processID )
{
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

// Get a handle to the process.

HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID );

// Get the process name.

if (NULL != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;

if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), 
&cbNeeded) )
{
GetModuleBaseName( hProcess, hMod, szProcessName, 
sizeof(szProcessName)/sizeof(TCHAR) );
}
}

// Print the process name and identifier.

_tprintf( TEXT("%s (PID: %u)\n"), szProcessName, processID );

CloseHandle( hProcess );
}

void main( )
{
// Get the list of process identifiers.

DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;

if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
return;

// Calculate how many process identifiers were returned.

cProcesses = cbNeeded / sizeof(DWORD);

// Print the name and process identifier for each process.

for ( i = 0; i < cProcesses; i++ )
PrintProcessNameAndID( aProcesses[i] );
}
 
Я пишу на Lotus Script, который близок к Vision Basic. C СИ++, к сожалению, не работала.
Возможно ли переписать данный код под Vision Basic ?
 
Ну я и подразумевал, что код преобразуете в LotusScript через Declare. К сожелению, у меня сейчас нет на это времени. Может, кто ещё поможет.
 
можно рапнуть код под LS2J:


с нитями вопрос... (как их Нотес разруливает)
 
на самом деле вопрос довольно сложный, единого способо для любых приложений несуществует. Поведение может быть совершенно различным.
Когда я решал такую задачу, я делал проверки по нескольким возможным направлениям
Это и CreateProcessA с последующей проверкой по PID, или по заголовку окна (GetWindow) и даже (если работа с известным файлом) по монопольному открытию этого файла, если возможно то закладывал работу через COM (хотя некоторые тут его "готовить не умеют")

Просто как дополнение к выше сказаному в форуме, хотел заметить возможность поиска приложения по заголовку окна, там обычно имя файла с которым работаете светится...
что-то типа этого:
Код:
Declare Function apiGetClassName Lib "user32" Alias "GetClassNameA" (Byval Hwnd As Long, Byval lpClassname As String, Byval nMaxCount As Long) As Long
Declare Function apiGetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Long
Declare Function apiGetWindow Lib "user32" Alias "GetWindow" (Byval Hwnd As Long, Byval wCmd As Long) As Long
Declare Function apiGetWindowLong Lib "user32" Alias "GetWindowLongA" (Byval Hwnd As Long, Byval nIndex As Long) As Long
Declare Function apiGetWindowText Lib "user32" Alias "GetWindowTextA" (Byval Hwnd As Long, Byval lpString As String, Byval aint As Long) As Long

Код:
	Private Function fEnumWindows(PhWnd As Long, Find As String) As Long
Dim hWnd As Long, hWndLen As Long
Dim hWndStyle As Long, strCaption As String

hWnd = apiGetWindow(PhWnd, mcGWCHILD)
Do While Not hWnd = 0
strCaption = fGetCaption(hWnd)
If Len(strCaption) > 0 Then
hWndStyle = apiGetWindowLong(hWnd, mcGWLSTYLE)
If hWndStyle And mcWSVISIBLE Then
Capt$ = Ucase(fGetCaption(hWnd))
If Instr(Capt$, Ucase(Find)) <> 0 Then
Code%=0
For i%=0 To hWndCount-1
If hWndOld(i%)=hWnd Then Code%=1
Next
If Code%=0 Then fEnumWindows = hWnd
End If
End If
End If
ChildEnumWindow& = fEnumWindows(hWnd, Find)
If ChildEnumWindow& <>0 Then fEnumWindows = ChildEnumWindow&
hWnd = apiGetWindow(hWnd, mcGWHWNDNEXT)
Loop
End Function
Если результат <>0 то приложение еще запущенно

Кстати при проверки по PID, после запуска и перед проверкой делал задержку, поскольку приложение может зпустится передать инстанс в другую копию, и PID сначало вроде есть, а потом нет... :(
примерно так...
Код:
		Dim StartInf As STARTUPINFO
StartInf.cb = Len ( StartInf ) 
RetVal = CreateProcessA ( 0&, RunProg , 0& , 0& , 1&, NORMAL_PRIORITY_CLASS , 0& , 0& , StartInf , ProcessInfo )
PID = ProcessInfo.dwProcessId

RetVal = CloseHandle ( ProcessInfo.hProcess )
RetVal = CloseHandle ( ProcessInfo.hThread )
Sleep 1' потому как если проверять сразу, PID может быть еще жив....
tmpH&=OpenProcess(PROCESS_QUERY_INFORMATION, 0&, PID) 
If tmpH& <> 0& Then
'проверять будем по PID
Else
'проверять будем по "WindowCaption"
End If
 
общую логика проверки приложения на запущенность можно свести к нескольким подходам:
-получение идентификатора процесса
-получение имени процесса

эти вещи платформенно не зависимы и для их осуществления есть утилиты (в составе ОС)
для виндозы - tasklist.exe, с параметрами
для *никс - ps
вызовы апи, данном случае (ИМХО) излишни...
а проги могут вызывать и сами шел, а далее форкать процессы и много ещё чего
потому фильтровать нужно еще и по времени запуска (у tasklist я не помню такой опции)
 
да, вот дополнение...
обычно (как мне кажется :lol: ) вызов внешних программ связан с открытием к-л файлов (для обработки)
вот обнаружение процесс, кот. этот файл держит - может служить индикатором работы программы
в никсах - это lsof
в винде (начиная с Хрюши) OpenFiles
ежели ниже хрюши - надо ставить процесэксплорер Руссиновича
ныне, мсявые его купили
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!