Newsgroup: it.comp.programmare.win32
Titolo: problema con PeekMessage

Salve a tutti,
ho un problema che mi sta facendo perdere ore e ore. Fondamentalmente
la situazione è questa (sviluppo con Borland C++ Builder 5):
Nel costruttore di una classe TMainForm (che deriva da TForm ed è il
form di partenza - nonchè l'unico - dell'applicazione) creo un secondo
thread (tramite le API di Win32, niente VCL) che gestisce delle
comunicazioni via seriale. Per bloccare il thread faccio una chiamata
a PostThreadMessage, quindi all'interno del thread ho una PeekMessage
per verificare che non sia arrivato WM_CLOSE.
/* chiude il thread */
::PostThreadMessage(thread_id, WM_CLOSE, 0, 0);
/* ... */
/* dentro al thread */
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE)  {
   if (msg.message == WM_QUIT)
      ExitThread(0L);
}
/* ... */
Il problema è che per qualche arcano motivo, dentro quella PeekMessage
mi arrivano anche dei WM_PAINT relativi ad un componente (TTabSheet)
che è contenuto dentro un TFrame, contenuto a sua volta dentro il
TMainForm di cui sopra, e non riesco a capirne il perchè, in fondo
quel thread che avvio non crea nessuna finestra! Qualcuno potrebbe
gentilmente illuminarmi e spiegarmi dove sbaglio?

 quel thread che avvio non crea nessuna finestra!
Detta cosi` effettivamente appare una strana cosa, ma e` possibile che
ti sia sfuggita una qualche funzione/relazione fra il tuo thread e
quelle finestre.
Per risolvere il problema, anziche` specificare NULL (e pescare tutti i
messaggi del thread) usa INVALID_HANDLE_VALUE. In questo modo potrai
spedire i tuoi messaggi di sincronizzazione con PostThreadMessage() e
riceverai soltanto quelli.
In ogni caso usare i messaggi in casi come questi e` solo una delle
alternative, e probabilmente e` una delle piu` contorte. Piuttosto io
userei un mutex e WaitForSingleObject() per verificare quando passa allo
stato segnalato.
--
Lorenzo

 stato segnalato.
Già, ma così il problema non viene risolto. Per non avere problemi non
dovrei creare thread secondari! Boh..

 quelle finestre.
Ok, allora vediamo se ho trovato il problema.. Se un thread X modifica
una finestra in qualche modo (e quindi c'č bisogno di un repaint), ma
non č stato il thread X a costruire quella finestra, chi riceve il
messaggio WM_PAINT? Chi l'ha effettivamente costruita o il thread X?

 thread X?
Domanda interessante, non ci avevo pensato. In effetti se si fa un
update sincrono e` possibile che il messaggio venga spedito al thread
che chiama UpdateWindow(), perche` tutto il "giro" e` fatto direttamente
con delle chiamate di funzione e non tramite il ciclo dei messaggi.
Forse il tuo problema e` dovuto al fatto che stai provando a forzare il
ridisegno (con UpdateWindow() o con API che a loro volta la utilizzano)
dal tuo thread.
Se e` questo il caso, non e` una buona prassi; meglio delegare il
ridisegno direttamente alla finestra interessata, ad esempio
*postandole* (altrimenti sei al punto di partenza :-)) un messaggio
custom che le dica di farlo.
--
Lorenzo

 custom che le dica di farlo.
Già, a tal proposito ho trovato un articolo online su MSJ che mi pare
parli proprio di questa cosa, o comunque di qualcosa di correlato:
[...]
I experimented with a multithreaded version of CWaitDialog that used a
separate user interface (UI) thread to process messages to the dialog,
but gave up on it after learning firsthand that 32-bit Windows doesn't
like it when a dialog runs in one thread and its owner runs in
another. UI threads are fine when each thread creates a top-level
window, but using multiple UI threads for child windows and owned
windows can lead to some strange behavior. For one thing, a dialog
running in thread B can't disable an owner window running in thread A
because Win32® stores activation states and other information (such as
who has the input focus) on a per-thread basis.
[...]
L'articolo intero, se a qualcuno dovesse interessare, è reperibile
all'indirizzo:
http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0297/wicked/wicked0297.htm&nav=/msj/0297/newnav.htm

 parli proprio di questa cosa, o comunque di qualcosa di correlato:
Windows dovrebbe spedire i messaggi al thread che ha creato la
finestra e *solo* ad essa.  In ogni caso, a mio avviso, non e'
buona regola lasciare una gestione mista VCL/API.
Ti suggerisco di usare la classe TThread.
In ogni caso, l'uso di PeekMessage piu' corretto e' quello
con INVALID_HANDLE_VALUE, in quanto in questo modo la funzione
estrae i messaggi con handle nullo (quelli spediti da 
PostThreadMessage).
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 PostThreadMessage).
Ok, ma questo uso non mi sembra documentato nell'SDK. Almeno, questo č
quello che leggo:
If hWnd is NULL, PeekMessage retrieves messages for any window that
belongs to the current thread making the call. (PeekMessage does not
retrieve messages for windows that belong to other threads.) If hWnd
is -1, PeekMessage only returns messages with a hWnd value of NULL, as
posted by the PostAppMessage function.
Non vedo tracce di INVALID_HANDLE_VALUE, oppure č quel -1?

 Non vedo tracce di INVALID_HANDLE_VALUE, oppure è quel -1?
Esatto.
Tratto da MSDN:
"If hWnd is NULL, PeekMessage retrieves messages for 
 any window that belongs to the current thread. If hWnd 
 is INVALID_HANDLE_VALUE, PeekMessage retrieves messages 
 whose hWnd value is NULL, as posted by the PostThreadMessage 
 function."
