Newsgroup: it.comp.programmare.win32
Titolo: Attesa non attiva

Salve, sto scrivendo una piccola applicazione in C usando le API native di 
Windows. Ora vorrei fare questo: durante l'esecuzione di un blocco di codice 
(lanciato dalla pressione di un bottone) vorrei fermare l'elaborazione, 
finche' l'utente non preme un altro bottone, senza ricorrere all'attesa 
attiva (ad esempio, un ciclo stretto che controlla continuamente una 
variabile condivisa); per il momento ho risolto con un semaforo ma vorrei 
sapere se esiste qualche altra soluzione "piu' elegante" ad esempio 
intercettando il ciclo dei messaggi...
Grazie per i suggerimenti 


Essendo una applicazione interattiva con UI, devi per forza servire la 
message pump, altrimenti Windows ti vedrà come una applicazione che non 
risponde e la superficie della finestra non verrà ridisegnata (compito che è 
tutto tuo dentro il gestore della WM_PAINT).
La tua applicazione quindi non si può 'fermare'. Bisogna vedere cosa vuoi 
fermare. Se hai un task lungo che gira su un altro thread puoi sospenderne 
l'esecuzione usando ad esempio WaitForSingleObject ma questo non devi farlo 
dentro il thread che ha una message pump.
-- 
Raffaele Rialdi
Microsoft .NET MVP 
http://mvp.support.microsoft.com
 -
http://italy.mvps.org
 UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org
 Weblog: 
http://blogs.ugidotnet.org/raffaele

Ti ringrazio per la risposta. La situazione che ho e' questa:
...
case WM_COMMAND:
    ...
    case BUTTON_1:
        ...un po' di codice...
        <fermati qui finche' l'utente non preme BUTTON_2>
        ...altro codice
La soluzione che ho attualmente adottato prevede di usare un semaforo creato 
in WM_CREATE inizialmente settato a 0; il wait dell'applicazione in 'case 
BUTTON_1' avviene attraverso MsgWaitForMultipleObjects in modo da fermarsi 
sul semaforo 'rosso' e di continuare a processare i messaggi inviati alla 
finestra; infine, la pressione del BUTTON_2 si occupa semplicemente di 'dare 
il verde' al semaforo attraverso ReleaseSemaphore nel seguente modo:
    case BUTTON_2:
    ReleaseSemaphore(hMySem,1,NULL);
    ...
Il tutto sembra funzionare e mi chiedevo se esistesse qualche altra 
soluzione piu' semplice o alternativa per il problema. Grazie ancora. 

 soluzione piu' semplice o alternativa per il problema. Grazie ancora.
Sembra funzionare perchè MsgWaitForMultipleObject si sblocca non solo per il 
rilascio del semaforo ma anche se arriva un messaggio nella message pump. Il 
risultato questo però ti obbligherebbe a far processare il messaggio e 
rientrare nella MsgWaitForMultipleObject.
In sostanza, se non servi la message pump il tuo sistema dovrebbe fallire se 
sovrapponi e poi iconizzi per esempio notepad alla tua applicazione. In 
questo caso arriva la WM_PAINT alla tua app, sblocca la 
MsgWaitForMultipleIbjects anche se il button2 non è stato premuto.
Ovviamente è una supposizione non vedendo il resto del listato.


Posto un po' di codice:
// INIZIO CODICE
case WM_CREATE:
...
    hMySem = CreateSemaphore(NULL,0,1, NULL);
...
case WM_COMMAND:
    ...
    case BUTTON_1:
    // disabilito tutti i controlli che non voglio siano attivati 
dall'utente
    // e attivo il controllo BUTTON_2
    ...
    // altro codice
    ...
    // inizio blocco di codice per attesa
    lphObjects[0]=hMySem;
    while(TRUE)
    {
        WaitResult = MsgWaitForMultipleObjects(1, lphObjects, FALSE, 
INFINITE, QS_ALLEVENTS);
       if (WaitResult == WAIT_OBJECT_0 + 1)
       {
           // gestisco i messaggi alla finestra
           IsMessage = PeekMessage(&Msg,NULL,0,0,PM_REMOVE);
           if (IsMessage)
           {
               TranslateMessage(&Msg);
               DispatchMessage(&Msg);
            }
            continue;
       }
       else if (WaitResult == WAIT_OBJECT_0)
       {
           break;
        }
    }
    // fine blocco di codice per attesa
    // disabilito il controllo BUTTON_2
    ...
    // altro codice
    ...
    return 0;
    case BUTTON_2:
    ReleaseSemaphore(hMySem,1,NULL);
    return 0;
// FINE CODICE
L'unico inconveniente e' che facendo lo switch ad un'altra finestra e quindi 
tornando alla mia applicazione c'e' bisogno che arrivi almeno un messaggio a 
quest'ultima (basta passare sopra la finestra con il mouse) perche' venga 
ridisegnata; in caso contrario non c'e' ridisegno perche' resta bloccata su 
MsgWaitForMultipleObjects. E' per questo che cerco una soluzione 
alternativa...

 questo che cerco una soluzione alternativa...
Ecco questo è esattamente quello che cercavo di dirti nel mio post 
precedente.
La strada corretta è quella di disabilitare il bottone (e/o altri controlli) 
che non vuoi vengano usati e togliere semafori e waitxxx.


 che non vuoi vengano usati e togliere semafori e waitxxx.
Ma come faccio cosi' a sospendere l'esecuzione in 'case BUTTON_1' (senza 
ritornare) finche' l'utente non preme BUTTON_2?
Questo ancora non mi e' chiaro. Ora provo la soluzione di esaminare la coda 
dei messaggi per intercettare la pressione di BUTTON_2.
Grazie lo stesso comunque. 

> La strada corretta č quella di disabilitare il bottone (e/o altri 

Per un codice piů pulito ti conviene usare un thread separato.
Crei un oggetto evento.
Sul click Btn1 -> disabiliti quello che vuoi, fai partire il thread che 
esegue la prima parte di codice, invia un messaggio prima dell'evento (se ti 
serve, es. abilitare Btn2) e si ferma sull'evento.
sul click Btn2 -> segnali l'evento sbloccando il thread che termina il suo 
lavoro, invia un messaggio di terminato ed esce.
Ricordati di usare PostMessagge nella comunicazione tra thread diversi.