Domanda

Perché è che se io chiamo una funzione apparentemente sincrono di Windows come MessageBox() interna del mio ciclo di messaggi, il ciclo stesso non congelare come se ho chiamato Sleep() (o una funzione simile) invece? Per illustrare il mio punto, prendere il seguente WndProc scheletrico:

int counter = 0;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
             SetTimer(hwnd, 1, 1000, NULL); //start a 1 second timer
             break;
        case WM_PAINT:
             // paint/display counter variable onto window
             break;
        case WM_TIMER: //occurs every second
             counter++;
             InvalidateRect(hwnd, NULL, TRUE); //force window to repaint itself
             break; 
        case WM_LBUTTONDOWN: //someone clicks the window
             MessageBox(hwnd, "", "", 0);
             MessageBeep(MB_OK); //play a sound after MessageBox returns
             break;
        //default ....
    }
    return 0;
}

Nell'esempio precedente, la funzione principale del programma è quello di eseguire un timer e visualizzare il valore del contatore ogni secondo. Tuttavia, se l'utente fa clic su nostra finestra, il programma visualizza una finestra di messaggio e quindi emette un segnale acustico dopo la scatola è chiusa.

Ecco dove si fa interessante: possiamo dire MessageBox() è una funzione sincrona perché MessageBeep() non viene eseguito fino a quando la finestra di messaggio si chiude. Tuttavia, il timer continua a funzionare, e la finestra viene ridisegnata ogni secondo anche mentre si visualizza la finestra di messaggio. Così, mentre MessageBox() è apparentemente una chiamata di funzione di blocco, gli altri messaggi (WM_TIMER / WM_PAINT) può ancora essere elaborati. Va bene, a meno che sostituisco MessageBox per un altro blocco delle chiamate come Sleep()

    case WM_LBUTTONDOWN:
         Sleep(10000); //wait 10 seconds
         MessageBeep(MB_OK);
         break;

Questa blocchi la mia domanda del tutto, e non l'elaborazione dei messaggi avviene per i 10 secondi (WM_TIMER / WM_PAINT non sono trattati, il contatore non viene aggiornato, il programma 'congela', ecc). Allora perché è che MessageBox() permette l'elaborazione dei messaggi di continuare mentre Sleep() non lo fa? Dato che la mia domanda è single-threaded, che cos'è che fa MessageBox() per consentire questa funzionalità? Il sistema di 'replicare' il mio thread dell'applicazione, in modo che modo si può finire il codice WM_LBUTTONDOWN volta MessageBox() è fatto, pur consentendo il thread originale per elaborare gli altri messaggi nel frattempo? (Che era la mia ipotesi ignoranti)

Grazie in anticipo

È stato utile?

Soluzione

Il MessageBox() e simili funzioni API Windows non blocchino l'esecuzione, come un'operazione IO o mutexing farebbe. La funzione MessageBox() crea una finestra di dialogo di solito con un pulsante OK - in modo che ci si aspetta la gestione automatica dei messaggi di Windows relative alla finestra di messaggio. Questo viene implementato con il proprio ciclo di messaggi - non viene creato nessun nuovo thread, ma l'applicazione rimane sensibile, perché i messaggi selezionati come Paint sono gestite chiamando ricorsivamente la funzione WndProc(), e alcuni messaggi non vengono trasmesse a, a causa del tipo modale del creato finestra.

Il sonno () e altre funzioni chiamate direttamente dal proprio la gestione di un messaggio di Windows WndProc(), sarebbe in realtà bloccare l'esecuzione del singolo messaggio filettato Loop, nessun altro messaggio verrà elaborato.

Altri suggerimenti

MessageBox gestisce il proprio ciclo di messaggi Win32 (in modo da non congelare chiama app).

Attenzione utilizzarlo in funzioni non rientranti ...

EDIT: elaborare: ciclo di messaggi su Windows è qualcosa di simile (rubato da MSDN):

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
} 

DispatchMessage chiamerà qualunque procedura di finestra è necessario. Quella finestra proc può iniziare il proprio ciclo (sullo stesso thread), e chiamerà DispatchMessage sé, che chiamerà qualsiasi gestori di messaggi.

Se volete vederlo, lanciare la vostra applicazione in debugger, pop-up finestra di messaggio e pausa. Sarete caduto da qualche parte all'interno del suo ciclo. Guardate la stack e vedere se è possibile trovare ciclo genitore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top