Newsgroup: it.comp.appl.access
Titolo: Come avviare programma esterno in modo sincrono ed recuperare codice numerico uscita?

Da codice Vba, come fare per avviare programma esterno ed avere di 
ritorno eventuale codice errore restituito dal programma eseguito?
Mi spiego meglio, dispongo di un programma che una volta avviato fa il 
suo lavoro e poi quando termina restituisce al chiamante un valore 
numerico, se zero nessun errore, altrimenti il valore indica l'errore 
ottenutuo durante l'elaborazione
 
Mi sembra che la shell funzioni solamente in modalita' asincrona, avvia 
il programma ed il controllo ritorna al codice, indipendentemente dal 
tempo impiegato ad eseguire l'elaborazione programma esterno
 
Volendo avviare da codice vba questo programma, e volendo leggere il 
codice che restituira' (e quindi credo sia necessario attendere la fine 
esecuzione programma esterno, o no?), come fare?
 


Puoi spiegare come leggi il Valore di cui parli...? Questo è il dilemma più importante...
 
Solitamente io userei ShellExecute in quanto restituisce appunto un codice eventualmente di Errore che trovi codificati quì:
https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea
 
 
Se però devi eseguire l'azione in modo SINCRONO ci sono vari modi, aprire un Processo ed attenderne la fine con le API, ovviamente questo è semplice se parliamo di un EXE, meno semplice se parliamo di un EXE asservito, esempio Excel che può aprire N file XLSX ma l'exe attivo è solo 1..., oppure usare il Metodo RUN di WindowsScriptingHost
 
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
 
wsh.Run FileName, windowStyle, waitOnReturn
 
Ciò detto, rimane sempre da capire come effettui la lettura del valore... 
 
@Alex


Veramente attualmente non so come leggerlo
Per questo ho postato, alla ricerca di aiuto
E' un programma che invia comandi ad un server mqtt, e quando esce 
restituisce al chiamante un valore numerico indicante l'esito 
dell'operazione
E mi serve capire, da codice vba che lo lancia, se l'operazione e' 
andata a buon fine oppure no perche' nel secondo caso devo ritentarla o 
segnalarla all'operatore
 
 
 

Salve,
 
RobertoA:

Lo faccio con la funzione ShellX di questo sito:
http://vb-tec.de/xshell.htm
 
 
È un sito tedesco ma forse puoi capirlo con google translate o simile.
In sostanza lanci il programma esterno non con Shell() ma con ShellX() 
che ritorna l'exit code. Se non riesci, posso cercare il codice concreto 
che uso in un progetto.
 
-- 
Ciao
Karl
*********
http://AccessDevCon.com
 
Access FAQ: 
http://donkarl.com/it
 

 Karl 
 
Si è il metodo da manuale, ma non risolve la lettura del parametro, infatti la Funzione ShellX restituisce INFO sul Processo non sull'EXE aperto:
 
     GetExitCodeProcess ProcHnd, ShellX
 
Quindi non è possibile qualcuno possa dare una risposta su COME leggere quel parametro se non chi ha sviluppato l'applicativo può dirti come LEGGERE quel valore. 
Non vorrei mai richieda un HOOK... 
 
Saluti
@Alex

 Non vorrei mai richieda un HOOK...
 
Non sono sicuro di capire cosa vuoi dire. Il valore di ritorno è 0 per 
convenzione se tutto va bene, è diverso se no. Quindi a volte è 
sufficiente un controllo su <> 0.
 
Se si deve valutarlo più esattamente, naturalmente è necessaria una 
documentazione del produttore. Nella mia esperienza questo è spesso il 
caso di programmi che si prendono la pena di fornire un exit code.


Karl Donaubauer:
@Alex:

...o è solo che non ti rendi conto che un codice di uscita viene sempre 
gestito attraverso il processo?
 
https://en.wikipedia.org/wiki/Exit_status
 


 Karl 
 
Karl, 
il valore restituito è 0 se il "Processo" viene correttamente chiuso dopo il lancio
il valore è <>0 se il "processo" non viene correttamente chiuso..., vale a dire che ShellX viene valorizzato con l'ExitCode del processo PID monitorato.
Se questo è quello che intendeva Roberto tutto OK...
 
Dalla richiesta iniziale:
"Volendo avviare da codice vba questo programma, e volendo leggere il
codice che restituira' (e quindi credo sia necessario attendere la fine
esecuzione programma esterno, o no?), come fare?"
 
magari ho frainteso io, ma l'italiano è abbastanza chiaro, ed il codice NON VIENE RESTITUITO dall'EXE ma dalla Shell, pare che Roberto debba leggere un codice relativo direttamente dall'EXE lanciato e forse è il motivo di fraintendimento...!
 
Quindi in questo secondo caso, tempo sarebbe impossibile farlo, senon con un HOOK all'Handle dell'Exe... ma come giustamente dicevi servirebbe la documentazione del produttore.
 
Spero di essere stato chiaro.
 
@Alex

 ...
 
Sua descrizione per me è quello di un exit code di un applicazione/exe. 
Come già scritto questo viene gestito attraverso il processo. L'ho 
dovuto controllarlo una volta per un C++exe di un cliente industriale.
 
Se leggi la documentazione di GetExitCodeProcess...
 
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess
 
 
...vedi che nella sezione "Remarks" descrivano che si tratta del exit 
code definita dall'applicazione.
 
Per il hook che non vuoi rischiare: Secondo me è l'unico metodo. Nelle 
remarks solo avvertirono che non si deve mandare STILL_ACTIVE come exit 
code perché altre applicazioni (come Access con ShellX) possano 
controllare questo valore. Però nessuno lo fa, lo standard è sempre 0 o 
un numero semplice più alto per un errore o stato speciale 
definito/documentato.


 
 
se fai 
 
del miofile.txt
tuoprogramma.exe > miofile.txt
 
cosa trovi in miofile.txt?
 
-- 
/-\ /\/\ /\/\ /-\ /\/\ /\/\ /-\ T /-\
-=- -=- -=- -=- -=- -=- -=- -=- - -=-
........... [ al lavoro ] ...........

 
 
Vedo niente
 
Per vedere qualcosa nel  miofile.txt dovrebbe esserci un qualcosa del 
tipo:
Console.WriteLine("123");
 
Nel mio caso il programma e' sostanzialmente:
-------------------------------
namespace CONSOLE_WITH_EXITCODE {
     class Program  {
         static int Main(string[] args) {
             .........
             Environment.Exit(123);
	    }
         }
     }
-------------------------------
 
E mostra l'exitcode, il valore 123, se lo avvi con un batch contenente:
 
start /wait CONSOLE_WITH_EXITCODE.exe
echo %errorlevel%
pause


Si, in effetti avrei dovuto meglio specificare la domanda
Perche' in effetti, alla chiusura del programma, e' possibile 
'acchiappare' sia l'exitcode che l'uscita sullo stdout emesso dal programma
Nel mio caso, e' l'exitcode che devo acciuffare
Quindi, dato il programma esempio:
--------------------------------
namespace CONSOLE_WITH_EXITCODE {
     class Program  {
         static int Main(string[] args) {
             .........
             Environment.Exit(123);
         }
       }
     }
-------------------------------
 
E' quel 123 che devo avere come esito delle operazioni eseguite
Valore che posso vedere da sistema operativo interrogando la variabile 
ambiente %errorlevel&
Se faccio un batch con le seguenti istruzioni:
 
start /wait CONSOLE_WITH_EXITCODE.exe
echo %errorlevel%
pause
 
Mi appare quanto atteso  'Echo 123'
Ora mi sembra siano meglio definiti i contorni del problema
 
Quindi la domanda e': dato l'esempio sopra, come fare per avviarlo da 
vba ed ottenere l'exit code 123 alla chiusura del programma avviato?
 
 
 
 

 vba ed ottenere l'exit code 123 alla chiusura del programma avviato?
 
Direi, come segnalato nella mia prima risposta.


 Karl 
 
Già... concordo.
@Alex

 
 
che mi dici di
echo %errorlevel% > miofile.txt   ?


 
 
E cosa vuoi che ti dica?
miofile.txt viene creato e riempito col valore 123
Quindi stiamo parlando strettamente di ExitCode come da documentazione 
Microsoft, non di scritte sulla consolle o sullo stout
 
Verificabile aprendo visual studio e ricopiando:


 
 
bene, era un workaround: se direttamente da access non si può, allora ci si 
inventa qualcosa di diverso per aggirare la limitazione e arrivare lo 
stesso al risultato
 
il nome di miofile.txt può essere una combinazione nomepc+nomeutente in 
modo da renderlo univoco in un ambiente di rete
 
access fa partire il programma, poi va in loop finché il file txt non viene 
creato
a quel punto legge il codice e continua
