Newsgroup: it.comp.programmare.win32
Titolo: MFC : chiudere una MessageBox

Ciao a tutti,
sono un neofita delle MFC con un piccolo problema:
ho scritto un piccolo programma, che al suo interno lancia un eseguibile 
esterno con CreateProcess( ... ).
Tutto funziona, ma il programma esterno impiega diversi minuti a 
terminare ed io vorrei mandare delle notifiche all'utente.
L'ideale sarebbe avere una MessageBox con testo "operazione in corso" ed 
eventualmente un pulsante "Annulla", che poi venga automaticamente 
sostituita da una finestrella con scritto "Operazione conclusa" ed un 
pulsante "OK"... esiste un qualche modo per fare ciò?
Attualmente quello che io faccio è molto semplicemente
===============================================================
     if( !CreateProcess(NULL, char_cmd, NULL, NULL, FALSE, 
CREATE_NEW_CONSOLE, NULL, m_DirAvvio, &si, &pi ) )
	{
         MessageBox( "Errore durante il calcolo delle distanze", 
TITOLO_ERRORE, MB_ICONERROR );
         return -1;
     }
     // Wait until child process exits.
     WaitForSingleObject( pi.hProcess, INFINITE );
     // Close process and thread handles.
     CloseHandle( pi.hProcess );
     CloseHandle( pi.hThread );
===============================================================
che vorrei tramutare in
===============================================================
     if( !CreateProcess(NULL, char_cmd, NULL, NULL, FALSE, 
CREATE_NEW_CONSOLE, NULL, m_DirAvvio, &si, &pi ) )
	{
         MessageBox( "Errore durante il calcolo delle distanze", 
TITOLO_ERRORE, MB_ICONERROR );
         return -1;
     }
     CreaFinestraOperazioneInCorso();
     // Wait until child process exits.
     WaitForSingleObject( pi.hProcess, INFINITE );
     // Close process and thread handles.
     CloseHandle( pi.hProcess );
     CloseHandle( pi.hThread );
     CreaFinestraOperazioneConclusa();
===============================================================
Dove ovviamente la funzione CreaFinestraOperazioneInCorso() NON può 
essere un semplice wrapper per MessageBox() in quanto deve restare 
aperta (quindi:non ritornare nulla) e permettere l'esecuzione di 
WaitForSingleObject !
come posso fare? Grazie mille per ogni suggerimento!
andre

come posso fare? Grazie mille per ogni suggerimento!
Puoi usare un wrapper della MessageBox, ma forse e' meglio creare
una CDialog apposta e lavori seguendo questo schema:
if (!CreateProcess (------))
   {
   MessageBox (---);
   return -1;
   }
CreaDialogoConTastoAnnulla ();
while (1)
   {
   if (PremutoTastoAnnulla ())
      {
      // Chiudi il processo, gli handle, il dialogo e ritorni
      }
   if (WaitForSingleObject (pi.hProcess,0) != WAIT_FAILED)
      break;
   Sleep (500);
   }
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
CambiaTastoOKeAspetta ();
---------------------
PS: wrapper MessageBox =
http://www.codeproject.com/dialog/CPPMessageBox.asp


Ho provato a usare il tuo schema, e tutto funziona -più precisamente,
quello che ho implementato è:
CDialog * pDialog;
...
//crea e mostra la finestra - pDialog->m_FermaCalcolo è un flag che
indica se
//fermare o meno i conti in corso
while ( TRUE ) {
    if ( pDialog->m_FermaCalcolo )
       {
       // Chiudi il processo, gli handle, il dialogo e ritorni
       . . .
       break;
       }
    else if (WaitForSingleObject( pi.hProcess, 0 ) == WAIT_OBJECT_0 )
{
       // Chiudi il processo, gli handle, il dialogo e ritorni
       . . .
       break;
    } else {
       Sleep( 500 );
    }
}
il problema è questo: con CreateProcess lancio un eseguibile esterno
che usa tutta la CPU, e nel frattempo entrambe le mie finestre (sia la
finestra da cui lancio CreateProcess che la finestrella pDialog) sono
bloccate, e dal task manager vengono viste come applicazioni che non
rispondono!
Come posso ovviare a questo?
Devo "stoppare" l'eseguibile esterno per far respirare la CPU?
ciao e grazie,
Andrea

Devo "stoppare" l'eseguibile esterno per far respirare la CPU?
Occorre solo abbassare la sua priorita' di esecuzione: nella
CreateProcess aggiungi IDLE_PRIORITY_CLASS al parametro
dwCreationFlags.

OT ha scritto:

Non vedo il messaggio che avevo postato e lo riposto :-(
---
Il problema non e' l'eseguibile esterno, nel tuo ciclo non rilasci mai
il controllo a windows che non puo' gestire quindi i messaggi della
tua applicazione.
Hai due soluzioni.
Nella prima avvii l'eseguibile esterno in un thread separato che
attende la fine del'eseguibile e poi setta un flag prima di uscire.
Nel dialogo di attesa creai un timer con cui vai a controllare lo
stato del flag.
Nella seconda usi MsgWaitForMultipleObjects() al posto della
WaitForSingleObject().
Ciao

Goodidea ha scritto:

purtroppo non funziona!
Se vuoi darmi altri suggerimenti, incollo qui sotto il pezzo di codice 
incriminato
( CDialogOpInCorso è una classe corrispondente ad un dialo 
semplicissimo: ha solo la var. booleana m_StopComputing ed un pulsante 
"Annulla tutto" che la setta a TRUE)
======================================
     ZeroMemory( &si, sizeof(si) );
     si.cb = sizeof(si);
     ZeroMemory( &pi, sizeof(pi) );
	si.dwFlags     = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;
     //CreateProcess lancia il cmd per lanciare ng_dist
     if( !CreateProcess(
		   NULL,     // if No module nam: use command line
            char_cmd,       // Command line - char_cmd is a char[ 
MAX_PATH] variable
            NULL,           // Process handle not inheritable
            NULL,           // Thread handle not inheritable
            FALSE,          // Set handle inheritance to FALSE
		   CREATE_NEW_CONSOLE | IDLE_PRIORITY_CLASS, // ???it works - 
http://www.codeproject.com/win32/runsilent.asp?df=100&forumid=4227&exp=0&select=581591
            NULL,           // Use parent's environment block
            m_DirAvvio,     // Use parent's starting directory
            &si,            // Pointer to STARTUPINFO structure
            &pi )           // Pointer to PROCESS_INFORMATION structure
		)
	{
         MessageBox( "Errore durante il calcolo delle distanze", 
TITOLO_ERRORE, MB_ICONERROR );
         return ERR_CREATE_PROCESS;
     }
	//AfxMessageBox("Avviato il processo ng_dist");
	CDialogOpInCorso* pDialog;
	//pDialog initialized to NULL in the constructor of CMyWnd class
	pDialog = new CDialogOpInCorso();
	//Check if new succeeded and we got a valid pointer to a dialog object
	if(pDialog != NULL)
	{
		BOOL ret = pDialog->Create(IDD_OPINCORSO,this);
		if(!ret)	//Create failed.
		{
			MessageBox("Error creating Dialog", TITOLO_ERRORE, MB_ICONERROR );
		}
		pDialog->ShowWindow(SW_SHOW);
		pDialog->m_StopComputing = FALSE;
		pDialog->Mostra();
	}
	else
	{
		MessageBox("Error Creating Dialog Object", TITOLO_ERRORE, MB_ICONERROR );
	}
	while( TRUE ) {
		if( pDialog->m_StopComputing ) {
			//processo da interrompere
			AfxMessageBox( "[Debug] letto flag di interruzione" );
			pDialog->Distruggi();
			break;
		} else if( WaitForSingleObject( pi.hProcess, 0 ) == WAIT_OBJECT_0 ) {
			//processo finito
			//AfxMessageBox( "proc finito" );
			pDialog->Distruggi();
			//AfxMessageBox( "processo terminato!", MB_ICONINFORMATION );
			break;
		} else {
			pDialog->Mostra();
			Sleep( 500 );
		}
	}

logicMind ha scritto:

Essendo (ancora) a digiuno di thread ho provato la seconda soluzione, ma 
senza risultati.
Mi sa che dovrò proprio imparare a gestire i thread!
by the way, il mio ciclo è:
===========================================
     //CreateProcess lancia il cmd per lanciare ng_dist
     if( !CreateProcess(
		   NULL,     // if No module nam: use command line
            char_cmd,       // Command line
            NULL,           // Process handle not inheritable
            NULL,           // Thread handle not inheritable
            FALSE,          // Set handle inheritance to FALSE
            CREATE_NEW_CONSOLE | IDLE_PRIORITY_CLASS,
            NULL,           // Use parent's environment block
            m_DirAvvio,     // Use parent's starting directory
            &si,            // Pointer to STARTUPINFO structure
            &pi )           // Pointer to PROCESS_INFORMATION structure
		)
	{
         MessageBox( "Errore durante il calcolo delle distanze", 
TITOLO_ERRORE, MB_ICONERROR );
         return ERR_CREATE_PROCESS;
     }
     [ ... ... ... ]
	while( TRUE ) {
		if( pDialog->m_StopComputing ) {
			//processo da interrompere
			AfxMessageBox( "ricevuto flag interrompi" );
			pDialog->Distruggi();
			break;
		} else if( MsgWaitForMultipleObjects( 1, &(pi.hProcess), TRUE, 500, 
QS_ALLINPUT ) == WAIT_OBJECT_0
			 /*WaitForSingleObject( pi.hProcess, 0 ) == WAIT_OBJECT_0*/ ) {
			//processo finito
			//AfxMessageBox( "proc finito" );
			pDialog->Distruggi();
			//AfxMessageBox( "processo terminato!", MB_ICONINFORMATION );
			break;
		} else {
			pDialog->Mostra();
			Sleep( 500 );
		}
	}
================================================================0
Io esco dal while SOLO quando finisce il processo perché la maschera 
resta "bloccata" e quindi non riesco mai a modificare il falg 
m_StopComputing :-(



Non conosco le MFC e quindi non so come vanno gestiti i messaggi, ma
penso ricalchino le API, quindi devi prelevare i messaggi e
dispatcharli. Se cerchi nel MSDN trovi l'esempio.
Poi invece di
[MsgWaitForMultipleObjects( 1, &(pi.hProcess), TRUE, 500,
QS_ALLINPUT )]
usa
[MsgWaitForMultipleObjects( 1, &(pi.hProcess), FALSE, INFINITE,
QS_ALLINPUT )]
e lo Sleep() finale è inutile.
Ciao
P.S.
ti incollo qui un pezzo dell'esempio
-----
    while (TRUE)
    {
        // block-local variable
        DWORD result ;
        MSG msg ;
        // Read all of the messages in this next loop,
        // removing each message as we read it.
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // If it is a quit message, exit.
            if (msg.message == WM_QUIT)
                return 1;
            // Otherwise, dispatch the message.
            DispatchMessage(&msg);
        } // End of PeekMessage while loop.
        // Wait for any message sent or posted to this queue
        // or for one of the passed handles be set to signaled.
        result = MsgWaitForMultipleObjects(cObjects, lphObjects,
                 FALSE, INFINITE, QS_ALLINPUT);
------

purtroppo non funziona!
Segui il consiglio di LogicMind e inserisci una message pump nel
while. A me funziona cosi':
static void MyMessagePump (void)
{
MSG msg;
while (PeekMessage (&msg,NULL,0,0,PM_REMOVE))
	{
	TranslateMessage(&msg);
	DispatchMessage(&msg);
	}
}
.
.
   } else {
      pDialog->Mostra();	// Inutile...
      MyMessagePump ();
      Sleep( 500 );		// Abbassa a 50
      }
.
.

Goodidea ha scritto:

perfetto!
Grazie mille