Sincronizza Indice |
Scarica il progetto |
Testo dell'articolo |
Stampa l'articolo |
Abbiamo già visto in un altro articolo come avviare un programma esterno utilizzando la funzione Shell; tuttavia quella soluzione in molti casi non si rivela la scelta migliore; infatti la funzione Shell avvia il programma e immediatamente ritorna al progetto VB in modo da continuare l'esecuzione in maniera sincrona al processo esterno in esecuzione.
In molti casi invece è necessario avviare un processo esterno ed attendere finché questo non sia terminato; per far ciò la funzione Shell si rivela del tutto inutile ed è necessario procedere in un'altra maniera. Vedremo in questo articolo come sviluppare la cosiddetta Shell sospensiva che, per comodità, racchiuderemo all'interno di un unico modulo standard. Inizieremo proprio da questo modulo e dal codice vero e proprio e solo dopo passeremo alla dimostrazione del funzionamento:
La struttura STARTUPINFO verrà utilizzata per specificare le opzioni sul processo esterno da avviare; per ragioni di completezza riportiamo la descrizione di tutti i campi poiché possono rendersi utili in situazioni differenti da quella riportata: cb indicherà la lunghezza in bytes della struttura e rappresenta un valore obbligatorio; lpReserved indica un valore riservato e deve essere 0; lpDesktop in un ambiente multidesktop indicherà il nome del desktop sul quale visualizzare la nuova applicazione; lpTitle (valido solo per le applicazioni console) specifica il titolo mostrato sulla finestra della console; dwX e dwY indicano la coordinata della nuova finestra da mostrare; dwXSize e dwYSize indicheranno la larghezza e l'altezza della finestra da visualizzare; dwXCountChars e dwYCountChars (validi solo per le applicazioni console) specificheranno il numero di caratteri per riga e per colonna nella nuova finestra console; dwFillAttribute (valido solo per le applicazioni console) consente di specificare la combinazione di colori di testo e di sfondo; dwFlags comanda l'uso degli altri campi e può contenere una combinazione qualsiasi dei valori riportati di seguito; wShowWindow consente la specifica della modalità di visualizzazione della nuova finestra (corrisponde ai valori dell'enumerazione VbAppWinStyle); cbReserved2 e lpReserved2 rappresentano valori riservati e non andrebbero specificati; infine hStdInput, hStdOutput e hStdError consentono di specificare i 3 handle per lo Standard Input, Standard Output e Standard Error. Il valore del campo dwFlags può combinare una o più delle seguenti costanti:
Più di una documentazione riporta un'erronea rappresentazione del campo lpReserved2 all'interno della struttura STARTUPINFO; l'errore nasce da una cattiva traduzione della definizione C della struttura stessa che riporta LPBYTE lpReserved2 (LPBYTE indica Long Pointer Byte cioè un puntatore ad un array di bytes e quindi un normale puntatore a 32 bit) e che è stato a volte riportato come lpReserved2 As Byte. Al di là del fatto che funzioni comunque, a causa dell'allineamento ai 32 bit effettuato da Visual Basic, la struttura riportata in questo articolo è tuttavia quella corretta.
La struttura PROCESS_INFORMATION è utilizzata solo per contenere gli handle e i numeri identificativi del processo e del thread eseguiti; seguono le dichiarazioni delle tre funzioni utilizzate in seguito: CreateProcess si occuperà della reale apertura del processo esterno e richiede fra l'altro la specifica della cartella da cui avviare l'applicazione e della priorità da assegnare al nuovo processo. WaitForSingleObject è una funzione generica utilizzata solitamente per altri scopi ed in questo caso sfruttata per forzare l'attesa fintanto che il processo esterno non venga chiuso oppure per il periodo di tempo indicato. CloseHandle infine serve solamente per chiudere un handle aperto. La costante WAIT_TIMEOUT corrisponde al valore di ritorno di WaitForSingleObject in caso di supero del limite di tempo di attesa massimo; WAIT_FAILED corrisponde invece alla situazione di errore durante l'attesa; la costante NORMAL_PRIORITY_CLASS rappresenta la priorità normale e verrà indicata nella chiamata alla funzione CreateProcess. Sono state omesse per brevità le dichiarazioni delle costanti STARTF indicate in precedenza.
L'intera funzione ShellSospensiva si compone di poche e semplici righe e richiede la specifica del processo da eseguire, della cartella da cui avviarlo, dello stile della finestra da visualizzare e del tempo massimo per l'attesa in millisecondi; è possibile specificare un tempo di attesa infinito semplicemente fornendo il valore -1 (corrispondente al valore della costante INFINITE &HFFFFFFFF). Inizializzata la variabile Start con la specifica della modalità di visualizzazione e lunghezza della struttura (righe 42-46) potremo procedere al richiamo del processo esterno indicato dal parametro CommandLine eseguito a partire dal percorso specificato nel parametro Directory; la priorità è quella normale. L'avvio del processo assegnerà un valore ai campi della variabile proc; la funzione WaitForSingleObject attenderà la variazione (signaling) dello stato dell'handle hProcess per il periodo di tempo indicato dal parametro WaitTime. Il valore di ritorno della funzione corrisponde a 0 in caso di signaling regolare, altrimenti WAIT_TIMEOUT in caso di supero del tempo massimo o altri valori in caso di errore; pertanto la funzione ShellSospensiva restituirà il valore di ritorno di WaitForSingleObject e soltanto lo 0 indicherà l'assenza di errori ed il completamento regolare.
Superata questa attesa (per signaling o per timeout) sarà necessario chiudere l'handle mediante CloseHandle del processo avviato (riga 50). In caso di impossibilità ad avviare il processo esterno sarà restituito il valore di ritorno corrispondente all'errore durante l'attesa WAIT_FAILED. La dimostrazione del funzionamento di questa semplice funzione è quasi banale: sull'unico form sono posizionate due etichette, due caselle di testo di nome txtProcesso e txtAttesa ed un unico pulsante di nome cmdAvvia. Alla pressione del pulsante Avvia sarà eseguito il seguente codice:
Semplicemente chiamando la funzione ShellSospensiva e fornendo il percorso del processo da eseguire (txtProcesso), la cartella da cui avviare (in questo esempio stiamo usando la cartella corrente), lo stile della finestra (normale e attiva) ed il tempo di attesa in millisecondi (txtAttesa) sarà possibile recuperare il valore di ritorno per stabilire l'accaduto: il valore 0 indica l'assenza di errore e la normale apertura e chiusura del processo entro il tempo massimo; il valore corrispondente alla costante WAIT_TIMEOUT indica l'avvio dell'applicazione ma il superamento del tempo massimo di attesa; qualsiasi altro valore indica una situazione di errore. Per ciascuno di questi valori sarà mostrato un avviso differente:
|
L'utilizzo di questa funzione semplifica notevolmente i problemi legati alla sincronizzazione di processi esterni poiché essendo in grado di determinare l'attesa o il superamento di questo tempo è possibile effettuare le scelte opportune. Fibia
FBI
|
Torna all'indice degli HowTo |