Newsgroup: it.comp.lang.visual-basic
Titolo: [?] Lanciare un programma da shell e suo esito

Ciao a tutti,
sto facendo un programmetto che deve lanciare altri programmi scelti
dall'utente, tenendo
traccia delle scelte dell'utente (esempio:  lanciando l'aggiornamento del
norton antivirus
mi registro su un piccolo DB l'ora, il giorno, l'utente, altro...).
L'utilizzo del comando shell però è asincrono e quindi se l'installazione va
male,  rischio di
scrivere nel database delle inesattezze.
Domanda: esiste un modo di sapere se un'applicazione lanciata da shell ha
avuto esito positivo o è uscita con un errore?
Grazie,
                Manrico

 avuto esito positivo o è uscita con un errore?
Con Shell puoi solo testare l'esito dell'avvio del programma. Benché sia
possibile agganciare il processo così creato (Shell ritorna un id di
processo che può essere usato per aprirlo e restare in attesa o testare il
codice di ritorno) è ovvio che ogni applicazione ritorna quello che vuole e
alcune - 
p.es
. i prg in VB - raramente tornano qualcosa.
Non so se a te serve una funzione sincrona, ma ne dubbio te ne posto una
asincrona che usa la shell di VB (molto scomoda rispetto alla ShellExecuteEx
dell'API, ma più semplice) che comunque puoi convertire in una shell
sincrona eseguendo un loop. La funzione ritorna un handle al processo (0 in
caso di errore) con il quale devi interrogare la funzione ShellTest. Al
termine devi chiamare SEMPRE ShellClose (altrimenti l'handle resta aperto).
Tieni presente che senza ShellExecute è possibile che un processo termini
prima di poterlo intercettare.
Public Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle"
(ByVal hObject As Long) As Long
Public Declare Function OpenProcess Lib "kernel32" Alias "OpenProcess"
(ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal
dwProcessId As Long) As Long
Public Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As
Long, lpExitCode As Long) As Long
Public Const SYNCHRONIZE = &H100000
Public Const PROCESS_QUERY_INFORMATION = &H400
Public Const STILL_ACTIVE = &H103&
Public Function ShellApp(FileName As String) as Long
'si suppone che FileName contenga tutta la stringa di Shell (eseguibile,
parametri etc.)
On Error Goto ErrHndl
dim pid as long, ph as long
pid=Shell(FileName)
ph=OpenProcess(SYNCHRONIZE OR PROCESS_QUERY_INFORMATION,0,pid)
if ph = 0 then
    'il processo è verosimilmente terminato
    Err.Raise 20000,,"Processo terminato [" & Err.LastDLLError & "]"
end if
ShellApp=ph
Exit Function
ErrHndl:
if ph Then
    CloseHandle ph
End if
ShellApp=0
End Function
Function ShellTest(Handle as Long, ExitCode As Long) As Boolean
'NB: ExitCode=STILL_ACTIVE quando il processo è ancora attivo
    ShellTest = GetExitCodeProcess(Handle, ExitCode) <> 0
End Function
Sub ShellClose(Handle as Long)
if Handle Then
    CloseHandle Handle
End if
End Function
----------------------------------------------------------------
Stefano Minardi
zet...@mclink.it
----------------------------------------------------------------

 sincrona eseguendo un loop.
Ricordatevi del DoEvents nel loop, mi raccomando, sennň siete nella cacca fino
al collo nel 90% dei casi.
Mi chiedevo: non esiste un qualche tipo di API che monitora il sistema e quando,
ad esempio, un programma viene chiuso, invia un messaggio ad una finestra o ad
un thread, che tramite una funzione callback recupera l'handle del thread o del
processo terminato e l'eventuale valore di ritorno?

 processo terminato e l'eventuale valore di ritorno?
Che io sappia no. Ma se hai un handle del processo, Windows mantiene l'exit
code anche dopo la chiusura del processo. Immagino che avranno pensato così:
una callback richiede che qualcuno stia in ascolto, cosa non sempre
possibile (poi si creano legami 1:n che non si sa mai come finiscano).
D'altra parte, tenere uno stack delle procedure eseguite sarebbe
pericoloso - dopo un po' potrebbe essere enorme. Quindi tengono solo i
valori per i processi con un handle vivo: quando l'ultimo handle viene
chiuso, ordinatamente tutto viene rimosso dalla memoria, ma posso testare
l'exit code quando voglio. La responsabilità è dei programmatori, non di
Windows - allineato e coperto.
