ciclo di messaggi viene bloccato quando il menu applicazione ha il focus
-
11-09-2019 - |
Domanda
Sto sviluppando un'applicazione che si presenta principalmente in questo modo:
while (true)
{
while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
DoSomething();
Sleep(1);
}
Quello che ho notato è che DoSomething () non viene chiamato quando clicco sulla barra dei menu (che visualizza le opzioni del menu). Ho osservato che i blocchi di chiamata DispatchMessage il ciclo messae fino a quando esco della barra dei menu!
Come potevo evitare questo comportamento ??
Grazie!
Soluzione
Il motivo è perché Windows assume l'elaborazione dei messaggi quando viene visualizzato qualcosa di simile a un menu dell'applicazione o finestra di messaggio, e che ciclo di messaggi che Windows utilizza non chiamerà il metodo DoSomething()
. Questo può essere difficile da visualizzare, quindi cercherò di passare da ciò che sta accadendo:
- Quando qualcuno apre il menù, viene inviato un messaggio alla finestra dicendogli di disegnare la finestra.
DispatchMessage()
invia il messaggio al tuoWndProc
, come tutti gli altri messaggi. - Dal momento che non si gestisce questo messaggio, si passa a Windows (dal momento che il
WndProc
più che probabile chiamaDefWindowProc
) - Per quanto l'operazione di impostazione predefinita, Windows richiama il menu e inizia un altro ciclo di messaggi di default che non chiamerà
DoSomething()
- Questo ciclo recupera i messaggi destinati per l'applicazione e li invia alla propria applicazione chiamando
WndProc
, quindi l'applicazione non congelare e continua a funzionare (meno la chiamataDoSomething()
). - Una volta che il menu è chiuso, il controllo verrà restituito al ciclo di messaggi (solo a questo punto sarà la chiamata
DispatchMessage()
dal ritorno fin dall'inizio)
In altre parole, quando viene visualizzato un menu, il vostro ciclo di messaggi viene sostituito da uno di default che assomiglia a questo (per esempio)
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
, che, come si può vedere, non chiamare il metodo di DoSomething()
.
Per verificare ciò, provare a mettere in pausa il codice in un debugger quando viene visualizzato nessun menu, e mentre uno è. Se si vede lo stack di chiamate, si vedrà che, quando viene visualizzato un menu, i messaggi vengono elaborati da un ciclo di messaggi di Windows, non dal sottoscritto.
L'unica soluzione mi viene in mente (senza multithreading) è se si avvia un timer e gestire il messaggio WM_TIMER
chiamando DoSomething()
, ma che non sarebbe una soluzione perfetta (in quanto presumo il vostro intento è quello di chiamare DoSomething()
solo quando c'è sono messaggi lasciati per elaborare).
Altri suggerimenti
Spin off traduzione e spedizione dei Msg in un thread separato.
Finché DoSomething non dipende spedizione dei Msg.
Anche se potrei voler capire perché la spedizione è il blocco; è questo comportamento normale atteso?