2009-05-08 6 views
9

Ho un problema molto simile a quello descritto qui: (? 5 secondi) http://www.eggheadcafe.com/software/aspnet/30579866/prevent-vista-from-markin.aspxIn che modo Windows (in particolare, Vista) determina se la mia applicazione è bloccata?

Quel filo suggerisce che Task Manager invia WM_NULL al processo e si aspetta che il processo di consumare questo messaggio entro limiti di timeout. Quando google per "WM_NULL appeso" ci sono molti riferimenti alla stessa tecnica.

Tuttavia non vedo alcun messaggio WM_NULL nella coda della mia applicazione mentre funziona su una lunga operazione - Ho un thread secondario che passa al thread principale ogni 0,5 secondi e chiama PeekMessage() alla ricerca di WM_NULL, e non ne trova!

Quindi, qual è il metodo utilizzato da Windows (Vista) per determinare se un'applicazione è bloccata?

Quali messaggi devono essere utilizzati dalla mia applicazione in modo che Windows ritenga che l'applicazione sia reattiva?

maggiori dettagli:

Insieme con PeekMessage() in cerca di WM_NULL, abbiamo anche chiamare PeekMessage() per gli eventi del mouse, dal momento che anche noi vogliamo capire se l'utente selezionato certa area della finestra, in cui un segnale di stop è disegnato. Se l'area viene selezionata, impostiamo un flag che controlla periodicamente la lunga operazione nel thread principale, e si fermerà se viene selezionato il segnale di stop. Il problema di Vista è che quando dichiara applicazione come non risponde, sostituisce la sua finestra con una finestra fantasma - vedi description of PeekMessage():

Se una finestra di livello superiore smette di rispondere ai messaggi per più di qualche secondo, il sistema considera la finestra non risponde e la sostituisce con una finestra fantasma che ha lo stesso ordine z, posizione, dimensioni e attributi visivi. Ciò consente all'utente di spostarlo, ridimensionarlo o persino chiudere l'applicazione. Tuttavia, queste sono le sole azioni disponibili perché l'applicazione non sta rispondendo. Durante il debug di un'applicazione, il sistema non genera una finestra fantasma.

Questa finestra fantasma non consente al mouse di passare attraverso la nostra finestra, perché la finestra non è più sullo schermo! Quindi il mio obiettivo è quello di evitare che questa finestra fantasma di apparire in primo luogo ...

dopo un po 'più indagini:

Dopo aver aggiunto il codice Michael suggerito nella sua risposta a questa domanda

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
{ 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 

l'applicazione non è più considerata bloccata da Windows; tuttavia non posso usare questa soluzione perché l'applicazione inizia a reagire a scelte su vari pulsanti, ecc (cosa che non dovrebbe accadere). Così ho provato a vedere quali messaggi stanno arrivando. Ho usato Spy ++ e anche il debug di stampa, ed entrambi hanno mostrato solo due tipi di messaggi: WM_TIMER e 0x0118 (WM_SYSTIMER). Così ho modificato il codice come questo

while (PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) || 
     PeekMessage(&msg, NULL, 0x0118, 0x0118, PM_REMOVE)) 
{ 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 

Sorprendentemente, l'applicazione si blocca di nuovo !!

Ora sono davvero bloccato. Se sto intercettando gli unici messaggi che arrivano, e lascia che la loro applicazione li elabori, come mai Windows pensa ancora che l'applicazione non elabori gli eventi ??

Qualsiasi suggerimento significativo sarebbe apprezzato GRANDE.

+1

Che cosa stai facendo sul thread dell'interfaccia utente? Hai considerato di provare a spostare le operazioni di blocco su thread in background invece di provare a decodificare il window manager? –

+1

Il thread UI è occupato nel calcolo di qualcosa. Sfortunatamente, come con molte applicazioni enormi, fare enormi quantità di codice vecchio multi-thread non è un compito banale ... :( –

+0

Aggiornato la mia risposta. Assicurati di svuotare tutti i messaggi per garantire che tu sia smascherato – Michael

risposta

4

TaskManager utilizza probabilmente IsHungAppWindow per determinare se un'applicazione è bloccata. Per MSDN, un'applicazione viene considerata bloccata se non è in attesa di input, non è in elaborazione di avvio o non ha elaborato i messaggi entro 5 secondi. Quindi non è necessario alcun WM_NULL.

Non è necessario utilizzare alcun messaggio specifico: basta pompare regolarmente messaggi e spostare lunghe attività dal thread dell'interfaccia utente. Se è possibile ottenere PeekMessage di essere chiamato ogni 0,5 secondi, sostituirlo con qualcosa di simile:

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
{ 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 

che sarà completamente svuotare la coda dei messaggi e farà apparire più sensibili per l'utente. Non filtrare singoli messaggi come i messaggi del mouse. Dovresti farlo più di ogni 0,5 secondi se possibile, e nel lungo termine cercare di spostare il lungo lavoro fuori dal thread dell'interfaccia utente.

+0

Come ho detto, la mia applicazione chiama PeekMessage() ogni 0,5 secondi, quindi IsHungAppWindow() non dovrebbe riportarlo come bloccato ... –

+0

Specifica PM_REMOVE o gli dai un filtro specifico WM_NULL? Credo che MSDN sia fuorviante qui, è necessario prelevare effettivamente i messaggi di input dalla coda. – Michael

+0

Sì, specifica PM_REMOVE e fornisco anche il filtro: sia mix che max sono WM_NULL. –

0

La soluzione è una chiamata aggiuntiva dopo l'invio dei messaggi.


// check for my messages 
while (PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) || 
     PeekMessage(&msg, NULL, 0x0118, 0x0118, PM_REMOVE)) 
{ 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 

// only to prevent ghost-window on vista! 
// we dont use the result and let the message in the queue (PM_NOREMOVE) 
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);