Newsgroup: it.comp.programmare.win32
Titolo: Come chiudere un processo creato con CreateProcess.

Qualcuno recentemente chiedeva come chiudere un processo creato con
ShellExecute, io ho un problema simile:
da un programma lancio tramite CreateProcess il programma pkzip per
comprimere alcuni files;
quando la compressione è terminata la finestra DOS non si chiude
automaticamente ma rimane aperta con la scritta "Esecuzione terminata". C'è
qualche modo tramite CreateProcess per impostare la chiusura automatica
della finestra DOS quando il pkzip termina l'esecuzione ?
Adesso ho risolto semplicemente creando la PIF del pkzip e selezionando il
check-box "Chiudi all'uscita".
C'è qualche altra alternativa ?
Grazie
Porlock.

>>>>> "P" == Porlock  <por...@CAVAMIfreemail.it> writes:
P> Qualcuno recentemente chiedeva come chiudere un processo creato con
P> ShellExecute, io ho un problema simile:
P> da un programma lancio tramite CreateProcess il programma pkzip per
P> comprimere alcuni files;
P> quando la compressione è terminata la finestra DOS non si chiude
P> automaticamente ma rimane aperta con la scritta "Esecuzione terminata".
La  mia  esperienza Unix  mi  porterebbe a  dirti  di  provare con  la
WaitForSingleObject sull'handle  del processo  (sai mai che  uccida lo
zombie).   Ma siccome  ho paura  che non  ti venga  reso  l'handle del
processo vero e  proprio ma quello della VDM che  lo esegue, penso che
dovrai provare con una cosa laboriosa anzichenò.
Usa  EnumWindows() o  FindWindows()  per analizzare  gli handle  delle
finestre aperte. Devi quindi prendere tutte gli handle e per ogni devi
chiamare  GetWindowThreadProcessId()  per vedere  se  il  thread ID  è
quello ritornato dalla CreateProcess nell'apposita struttura. Ottenuto
l'handle della finestra sparagli un WM_QUIT o usa DestroyWindow().
A me è venuta in mente questa... Qualcuno ha qualcosa di meglio ?
+----------------------------------------------------------------+
| Gian Uberto Lauri * "So, are you working on fixing that bug    |
| 
sa...@eng.it
      *  *now* or leaving it until later ?" - YES  |
+----------------------------------------------------------------+
| Attenzione: rispondo ad ogni invio di pubblicità non richiesta | 
| o spam di qualsiasi altro genere con un messaggio al provider  |
| di competenza. Ai sensi della legge sulla privacy NON avete il |
| permesso di utilizzare i miei dati per questi scopi.           |
+----------------------------------------------------------------+


Non posso usare WaitForSingleObject semplicemente perché il processo è
ancora in esecuzione.
Mi spiego meglio:
lancio il pkzip con create process,
con waitforsingleobject mi metto in attesa....
intanto la finestra DOS sta eseguendo il pkzip,
il pkzip termina la compressione, sulla barra del titolo della finestra DOS
mi appare la scritta "Esecuzione terminata", ma il processo non è terminato
e la funzione waitforsingleobject non ritorna.
Ritorna solo dopo che manualmente ho chiuso la finestra DOS.
Il mio problema è qui, c'è qualche modo per impostare via codice la chiusura
automatica della finestra quando termina l'esecuzione ?
Come dicevo nel primo post attualmente ho creato la PIF per il pkzip con
selezionato "chiudi all'uscita" e funziona perfettamente.
Volevo solo sapere se lo potevo fare via codice.
Grazie comunque.
Porlock.

>>>>> "P" == Porlock  <por...@CAVAMIfreemail.it> writes:
P> Non posso usare WaitForSingleObject semplicemente perché il processo è
P> ancora in esecuzione.
P> Mi spiego meglio:
P> lancio il pkzip con create process,
P> con waitforsingleobject mi metto in attesa....
Lo immaginavo ma  mi ero spiegato male. Hai letto il  resto del post ?
Non era  quello che cercavi  tu ma probabilmente arrivava  alla stessa
conclusione...


 automatica della finestra quando termina l'esecuzione ?
Prova a creare l'applicazione invisibile: teoricamente la "console
nascosta" dovrebbe chiudersi automaticamente con la fine del programma
che ospita.
Oppure al limite quando chiami CreateProcess() puoi sempre specificare
come stdout una tua pipe creata con CreatePipe(), e vedere quando
"raggiunge" l'EOF. Ho scritto un programma che usava eseguibili esterni
(anche DOS) come filtri, faceva una cosa del genere e funzionava bene...
se vuoi ti cerco un po' di codice.
---
Bye! Lorenzo Lutti
http://www.geocities.com/SiliconValley/Peaks/6258/


Questo m'interessa molto. Se mi puoi inviare un po' di codice te ne sarei
grato.
Porlock.

>>>>> "LL" == Lorenzo Lutti <lorenz...@DOHtiscalinet.it> writes:
LL> Prova a creare l'applicazione invisibile: teoricamente la "console
LL> nascosta" dovrebbe chiudersi automaticamente con la fine del programma
LL> che ospita.
Questo si fa con il contenuto della struttura di startup vero ?
LL> Oppure al limite quando chiami CreateProcess() puoi sempre specificare
LL> come stdout una tua pipe creata con CreatePipe(), e vedere quando
LL> "raggiunge" l'EOF.
Ma la chiusura della pipe ti permette di terminare il processo o di 
fargli eseguire la ExitProcess() con la sua chiusura ?


l'handle della finestra sparagli un WM_QUIT o usa DestroyWindow().
Non e' WM_QUIT il messaggio che va spedito (deve essere usato solo nei
cicli di elaborazione dei messaggi, interni alle applicazioni), ma
WM_CLOSE.
--
Andrea Laforgia (ICQ 87230455)
------------------------------ 
#exclude <windows.h>


Ho letto il resto del post e se non ho capito male mi suggerisci di risalire
alla
finestra principale legata al processo e sparagli un WM_CLOSE.
Tra l'altro oltre alle funzioni che mi hai elencato esiste anche
EnumThreadWindows
che mi permette di enumerare le finestre non-child legate ad un thread di
cui conosco il threadID.
Ti spiego cosa sono riuscito a tirare fuori.
Con la EnumThreadWindows sono riuscito a trovare l'HWND della finestra DOS
(ho dovuto utilizzare anche GetClassName per identificare la finestra con
class "tty" poiché al processo sono legate piů di una finestra non-child).
Adesso posso lanciare WM_CLOSE e la finestra DOS mi avverte con una bella
message-box che:
"Impossibile chiudere il programma automaticamente. Chiudere il programma
usando i comandi appropriati ...... ecc ecc".
Questo perché il pkzip non ha ancora terminato l'esecuzione. E' lě il punto,
il messaggio WM_CLOSE
lo devo mandare solo quando il pkzip ha terminato l'esecuzione ma ancora non
ho capito come
posso fare per saperlo .... ammesso che si possa.
Porlock

 grato.
Ecco qui la funzione completa che usa un programma esterno come filtro.
Qui da me funziona sia con applicazioni Win32 console che con
applicazioni DOS... ah, c'e` un po' di roba di MFC, ma all'occorrenza e`
facile ripulirla. Scusa anche per tutte le tabulazioni e cose varie
mangiate, ma OE e` quello che e`; se ti e` piu` comodo te lo mando in
attach via mail.
BOOL CWndDummy::Filtro_EseguiEsterno( CString& str, CString& prg)
{
 CString dopo;
 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 // Crea una pipe per stdin e una per stdout
 SECURITY_ATTRIBUTES sa;
 HANDLE in[2], out[2];
 ::FillMemory( &sa, sizeof(sa), 0);
 sa.nLength = sizeof(sa);
 sa.bInheritHandle = TRUE;
 if( !::CreatePipe( &out[0], &out[1], &sa, 0))
  return FALSE;
 if( !::CreatePipe( &in[0], &in[1], &sa, 0))
 {
  ::CloseHandle( out[0]);
  ::CloseHandle( out[1]);
  return FALSE;
 }
 // Lancia il filtro esterno, con gli handles modificati
 FillMemory( &si, sizeof(si), 0);
 si.cb = sizeof(si);
 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
 si.wShowWindow = SW_HIDE;
 si.hStdOutput = si.hStdError = out[1];
 si.hStdInput = in[0];
 if( !::CreateProcess( NULL, (char *)LPCTSTR(prg), NULL, NULL,
  TRUE, 0, NULL, NULL, &si, &pi))
 {
  ::CloseHandle( out[0]);
  ::CloseHandle( out[1]);
  ::CloseHandle( in[0]);
  ::CloseHandle( in[1]);
  return FALSE;
 }
 // Chiude i lati che non servono piu`
 ::CloseHandle( out[1]);
 ::CloseHandle( in[0]);
 // Spedisce nell'stdin dell'altro processo il messaggio (con EOF alla
fine)...
 str += "\032\r\n";
 int a=0, n=str.GetLength();
 DWORD nIO;
 while( a<n)
 {
  if( !::WriteFile( in[1], LPCTSTR(str.Mid(a)), n-a, &nIO, NULL) || nIO
== 0)
   break;
  a += nIO;
 }
 ::CloseHandle( in[1]);
 // ...e legge il risultato dal suo stdout
 char buf[64];
 while( ::ReadFile( out[0], buf, 64, &nIO, NULL) && nIO>0)
  dopo += CString( buf, nIO);
 ::CloseHandle( out[0]);
 str = dopo;
 return TRUE;


 fargli eseguire la ExitProcess() con la sua chiusura ?
Questo temo di no... forse ti puoi accorgere quando l'eseguibile
"ospitato" e` terminato, ma temo che per la console che resta aperta non
ci sia nulla da fare a parte chiuderla con cattiveria.
(Ci sarebbe il modo per non farla mai restare aperta, perlomeno sotto a
NT: basta modificare lo shortcut che lancia la shell. Pero` ovviamente
questa non e` una soluzione ottimale, se uno vuole che normalmente resti
aperta non mi sembra carino modificargli i comportamenti system-wide
:-)).



Grazie mille, vedrò cosa riesco a combinare.
Porlock.

> l'handle della finestra sparagli un WM_QUIT o usa DestroyWindow().
AL> Non e' WM_QUIT il messaggio che va spedito (deve essere usato solo nei
AL> cicli di elaborazione dei messaggi, interni alle applicazioni), ma
AL> WM_CLOSE.
Non credo ci siano problemi, a meno che non ci sia in ballo un dialogo
tra applicazioni attraverso messaggi WM_, che potrebbe stallare per la
morte subitanea di uno degli interlocutori. L'unica cosa era che Win16
aveva solo  8 slot quindi rischiavi  di perderlo, per  cui hanno messo
QS_QUIT.
Anzi.
Se  tu,  come  suggerisce  Richter,  mandi  un  WM_CLOSE  che  fa  una
PostQuitMessage() allora il tuo  QS_QUIT verrà considerato solo quando
QS_SENDMESSAGE e QS_POSTMESSAGE sono ambedue  a 0, il che potrebbe non
accadere mai.
Se ci sono obiezioni, fammele sapere che è il caso ne sia al corrente!
:)


>>>>> "P" == Porlock  <por...@CAVAMIfreemail.it> writes:
P> Questo perché il pkzip non  ha ancora terminato l'esecuzione. E' lì
P> il  punto, il  messaggio WM_CLOSE  lo devo  mandare solo  quando il
P> pkzip ha terminato l'esecuzione ma  ancora non ho capito come posso
P> fare per saperlo .... ammesso che si possa.
Mi sembra che  tu abbia trovato la strada con  la tabella dei processi
nella quale dovrebbe comparire un entry per pkzip.
Alla più sporca metti un ciclo  in cui verifichi che esista, se esiste
fai una ssleep() e ricontrolli, se non esiste più spari la WM_CLOSE.


Se ci sono obiezioni, fammele sapere che è il caso ne sia al corrente!
"The WM_QUIT message indicates a request to terminate an application
and is generated when the application calls the PostQuitMessage
function." [MS SDK]
Il WM_QUIT e' sempre generato dall'applicazione.
Per chiudere applicazioni diverse dalla propria, si spedisca un


 writes:
AL> "The WM_QUIT message indicates a request to terminate an application
AL> and is generated when the application calls the PostQuitMessage
AL> function." [MS SDK]
Questo dice quando  è generato (ma stando al Richter  non è preciso al
100%), non dice "vietato usarlo".
Tra l'altro la documentazione del VC 6++ dice:
The WM_QUIT  message indicates a  request to terminate  an application
and  is  generated  when  the application  calls  the  PostQuitMessage
function. It causes the GetMessage function to return zero.
A  me  pare  un modo  per  uccidere  ferocemente  e senza  scampo  una
applicazione e comunque l'ho provato ad usarlo e funziona :)
/* test.c */
// pollo.cpp : Defines the entry point for the console application.
//
#include <windows.h>
#include <winuser.h>
int CALLBACK foobar(HWND hwnd, LPARAM lparam)
{
	PostMessage(hwnd,WM_QUIT,0,0);
	return 0;
}
int main(int argc, char* argv[])
{
	STARTUPINFO s;
	PROCESS_INFORMATION p;
 
	memset((void *)&s,0,sizeof(STARTUPINFO));
	s.lpReserved = NULL;
	s.cb = sizeof(STARTUPINFO);
	s.lpDesktop = NULL;
	s.lpReserved2 = NULL;
	s.wShowWindow =SW_SHOWDEFAULT;
	if (CreateProcess("d:\\NT4\\system32\\notepad.exe",
                      "d:\\NT4\\system32\\notepad.exe",NULL,NULL,
                      1,0,NULL,NULL,&s,&p))
        /* notepad appare per 10 secondi... */
        Sleep(10000);
		EnumThreadWindows(p.dwThreadId,foobar,0);
	else
	{
		LPVOID lpMsgBuf;
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                      FORMAT_MESSAGE_FROM_SYSTEM |
                      FORMAT_MESSAGE_IGNORE_INSERTS,    
                      NULL,
                      GetLastError(),
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      (LPTSTR) &lpMsgBuf,    0,    NULL );
		MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", _
                    MB_OK | MB_ICONINFORMATION );
		LocalFree( lpMsgBuf );
	}
	return 0;
}
/* fine */


100%), non dice "vietato usarlo".
Tempo fa si discusse con Alex Martelli proprio di questo.
Ricordo che lui affermo' che era sbagliato spedire un WM_QUIT, in
particolare disse proprio che era vietato. Cio' che va spedito, in
accordo con Alex, e' WM_CLOSE.


        Sleep(10000);
^^^ non Sleep, ma "WaitForInputIdle".


 writes:
AL> Tempo fa si discusse con Alex Martelli proprio di questo.
AL> Ricordo che lui affermo' che era sbagliato spedire un WM_QUIT, in
AL> particolare disse proprio che era vietato. Cio' che va spedito, in
AL> accordo con Alex, e' WM_CLOSE.
Oh,  allora è bene  prepararsi un  caricatore di  WM_QUIT.  Io  non ho
trovato alcun divieto  esplicito (<OT>e uno di Alex  Martelli è mostly
harmless - Andrea, non  ci sono molti Gian Uberto in giro  :) ed io di
te mi ricordo - positivamente</OT>).
Ambedue i metodi hanno dei problemi.
WM_CLOSE  se interpretato  come da  regolamento ha  il difetto  di non
garantire  la   chiusura  per  lo   meno  fino  a  NT   4.0.   Infatti
PostQuitMessage() non imposta  un messaggio ma alza un  flag, flag che
però viene ignorato se  almeno uno tra QS_POSTMESSAGE e QS_SENDMESSAGE
è  alto. La chiusura  dell'applicazione è  probabile ma  non garantita
(solito difetto di windows).
L'unico dubbio che  mi rimane è su un WM_QUIT inviato  ad un handle in
un certo task1  che viene in contemporanea usato  in una SendMessage()
di  un task differente  (task2).  Per  le mie  speculazioni ci  sono 2
possibilità  su 3  che succeda  qualcosa di  poco piacevole  (task2 si
blocca,  task2  va  in  errore  a causa  della  mancata  elaborazione,
l'elaborazione della SendMessage() viene completata...). A naso il più
probabile è il caso di task1  e task2 che si parlano con messaggi alla
finestra e uno dei due si trova nella situazione di aspettare Godot...


> Sleep(10000);
AL> ^^^ non Sleep, ma "WaitForInputIdle".
Sorry, Sleep() in quel punto è  una chiamata più che lecita mentre non
è lecita la WaitForInputIdle  (grazie comunque per avermela segnalata,
ho  conosciuto una nuova  call) dato  che il  programma che  esegue la
CreateProcess() è una applicazione in console :) .


 writes:
M> Diciamo che spedendo WM_QUIT e' probabile che l'applicazione non liberi
M> tutte le risorse allocate, ma solo alcune.
Scusa la domanda, puoi specificarmi  il tipo di risorse che potrebbero
non  venir  liberate  ?  (sono  abituato ad  ambienti  che  ucciso  il
processo, liberate le risorse).


accordo con Alex, e' WM_CLOSE.
Diciamo che spedendo WM_QUIT e' probabile che l'applicazione non liberi
tutte le risorse allocate, ma solo alcune. WM_CLOSE risolve questo problema,
ma purtroppo necessita della collaborazione da parte del programma
destinatario: se quest'ultimo non vuole chiudersi, WM_CLOSE e' inutile.
Si puo' fare un compromesso: si spedisce WM_CLOSE, e se il programma e'
ancora vivo dopo tot secondi, si passa WM_QUIT (e credo sia il sistema usato
dal task manager quando, richiamato con Ctrl+Alt+Canc, gli sia richiesto di
uccidere un processo).
Saluti,
    Mardy

uccidere un processo).
Assolutamente no.
Task Manager spedisce un WM_CLOSE con un timeout di 5 secondi.
Se la finestra non risponde usa un brutale TerminateProcess.


è lecita la WaitForInputIdle 
Non so che cosa ti spinga a dire che la chiamata a un'API fatta
*apposta* per quello scopo non sia lecita. La chiamata a "Sleep" non
ti assicura che il caricamento del programma e lo "show" della
finestra avvenga entro il tempo specificato.
"WaitForInputIdle" si'.
"The WaitForInputIdle function enables a thread to suspend its
execution until a specified process has finished its initialization
and is waiting for user input with no input pending. This can be
useful for synchronizing a parent process and a newly created child
process. When a parent process creates a child process, the
CreateProcess function returns without waiting for the child process
to finish its initialization. Before trying to communicate with the
child process, the parent process can use WaitForInputIdle to
determine when the child's initialization has been completed. For
example, the parent process should use WaitForInputIdle before trying
to find a window associated with the child process. 
The WaitForInputIdle function can be used at any time, not just during
application startup." [MS SDK]


> è lecita la WaitForInputIdle 
AL> Non so che cosa ti spinga a dire che la chiamata a un'API fatta
AL> *apposta* per quello scopo non sia lecita.
Cavoli,  hai  ragione, devo  aver  pasticciato  con  l'help perché  mi
ricordo  chiaramente  di  aver   letto  di  un  caveat  rispetto  alle
applicazioni in console... Grazie di aver insistito!


	return 0;
^^^ ci vogliono le CloseHandle degli handle del processo e del thread
primario.


> return 0;
AL> ^^^ ci vogliono le CloseHandle degli handle del processo e del thread
AL> primario.
Pignolo!!!!! :).  Era poco più di  una prova fatta in  tutta fretta (e
poco tempo), poco più di un sorgente scritto con cat > file.c ...


poco tempo), poco piů di un sorgente scritto con cat > file.c ...
...poco meno di un programma corretto ;)


non  venir  liberate  ? 
Se non viene eseguito il WM_DESTROY non viene/vengono distrutte le
finestre create dal thread. Credo non sia azzardato paragonare
l'elaborazione dei messaggi allo scatenamento degli eventi dei
componenti sotto Delphi o C++ Builder (per esempio).
Un evento singolo, generalmente, ne scatena altri e saltare al punto
di mezzo di una catena, non assicura il corretto funzionamento.


processo, liberate le risorse).
Sei abituato agli ambienti seri. Non sono sicuro che su win9x sia cosi'. Ora
che mi ci fai pensare, la mia idea deriva probabilmente dall'help in linea
del VC++ 4.0, che a proposito di LoadResource dice:
"
Remarks
Windows 95: The system does not automatically free resources loaded using
the LoadResource function. Applications must use the FreeResource function
function to explicitly discard a resource that is no longer needed.
Windows NT: The system automatically frees resources. Calling the FreeRource
function is not necessary to free a resource loaded by using the
LoadResource function.
"
Forse ho frainteso... Ad ogni modo, mi e' capitato spesso di debuggare i
miei programmi quando non avevo ancora implementato la deallocazione di
tutto quanto allocato. Beh, dopo poche esecuzioni, il sistema diventava
tremendamente instabile, e cambiavano i fonts di sistema, e pure alcune
bitmap (tipicamente le freccette delle combobox) non venivano caricate.
Immagino che le risorse che win9x non riesce a recuperare siano quelle della
GDI.
(ma parlo per esperienza, non so nulla a riguardo)
Saluti,
    Mardy

 processo, liberate le risorse).
Beh, in generale gli oggetti system-wide (e potenzialmente condivisi da
piu` processi) possono dare di questi problemi... ad esempio un
semaforo, o una pipe, o un mutex.
Onestamente credo che si tratti piu` che altro di problemi
implementativi (leggi: Windows 9x). Sotto a NT non ho mai avuto
esperienze particolarmente eclatanti sotto questo punto di vista...
