Sviluppo

Come faccio? - parte XI

Gianni Ceccarelli
 

stesura originale in inglese di Eric Slaats - liberamente tradotto da Gianni Ceccarelli
comparso per la prima volta su Os/2 e-Zine! volume 2 numero 9

Salve, bentornati! In questi utlimi tempi ho pensato a come portare avanti questi articoli. Finora ho fatto un paio di articoli 'teorici' sul Presentation Manager e un sacco di articoli pratici. Gli articoli pratici contenevano a volte un po' di teoria sul funzionamento di alcuni aspetti. Penso che sia un bene inframezzare le parti teoriche con quelle pratiche, perciò questo approccio sarà mantenuto. Ad ogni modo, ho deciso di inserire di tanto in tanto un articolo più teorico per dare una conoscenza più profonda del PM. Far funzionare le cose è importante, ma comprenderle è assolutamente neccessario.

Bene, cosa faremo questo mese? Ci sono molte parti del PM che vengono usate quasi senza pensarci. L'intero paradigma dei messagi è un esempio di ciò. Altri esempi sono i thread, i metodi post e send, e la WPS. Prima di continuare il discorso sui dialog iniziato qualche mese fa, considereremo di nuovo la gestione dei messaggi.

Un flusso di messaggi

Come detto nell'articolo sul paradigma dei messaggi, tutti gli eventi (come un click o un movimento del mouse, la pressione di un tasto, il ridimensiomaneto di una finestra, ecc.) sono gestiti dal meccanismo dei messaggi. Tutte queste azioni generano un messaggio che viene inserito nella coda eventi di sistema. Ogni messaggio contiene l'handle di una finestra, così il sistema sa a quale finestra inviarlo. Abbiamo visto che ogni finestra ha una window-procedure che gestisce tutti i messaggi inviati alla finestra. La conseguenza ultima di ciò è che se vogliamo qualcosa da una finestra, dobbiamo semplicemente inviarle un messaggio che sarà gestito dalla window-procedure di quella finestra, che eseguirà le azioni del caso.

Come ho detto, ogni finestra ha una window-procedure. Per le nostre applicazioni, scriveremo noi le window-procedure per la client window. Controlli come pulsanti, MLE ecc. hanno le loro window procedure automatiche. Perciò se vogliamo un'azione da un certo controllo, possiamo chiederglielo inviandogli un messaggio.

L'enorme quantità di messaggi che il PM può gestire è elencato nella documentazione di OS/2, dove queste informazioni sono divise tra i vari controlli standard. Il fatto che possiamo inviare messaggi ai controlli significa che non solo gli eventi generano messaggi, ma anche i programmi ne produrranno una grande quantità. Stiamo osservando un gran flusso di messaggi! Come possiamo fare in modo che siano gestiti in maniera ottimale?

Send e post

Ci sono due metodi principali per far giungere un messaggio ad una window procedure: "send" e "post". Parliamo genericamente di "inviare" un messaggio senza specificare cosa facciamo realmente. Vediamo ciascuno dei due metodi.

Per usare il metodo post dobbiamo usare la funzione WinPostMsg. (C'è un'altro metodo, ma non è molto importante ora.) Per prima cosa il messaggio viene inserito nella giusta coda messaggi (la coda messaggi che è associata all'applicazione proprietaria della finestra cui è indirizzato il messaggio).

I messaggi inviati in questo modo sono chiamati "messaggi accodati". Questi messaggi sono usati per la gestione asincorna. Eh? Beh, devo dire che suona complicato, ma non è poi così difficile da capire. Queando viene inviato un messaggio, WinPostMsg ritorna immediatamente: l'unica azione eseguita è inserire il messaggio nella coda. Non aspetta che il messaggio venga gestito, per cui il programma continua subito dopo la chiamata a WinPostMsg.

La gestione dei messaggi è eseguita dal "dispatcher" che estrae un messaggio dalla coda lo invia alla window procedure appropriata. "Asincrono" significa che il programma non sa esattamente quando il messaggio verrà gestito. La gestione del messaggio è asincorna alla funzione che ha inviato il messaggio.

Possiamo inviare un messaggi a una finestra anche chiamando WinSendMsg. In questo caso il messaggio non verrà inserito nella coda. Passerà in testa alla coda e verrà gestito immediatamente. WinSendMsg aspetterà fino al termine della gestione e ritornerà il valore di ritorno del messaggio. Questo modo di gestire i messaggi viene chiamato "sincrono". Il motivo è che il programma chiamante sa sempre quando il messaggio viene gestito. (Semplicemente, quando viene effettuata la chiamata, il messaggio viene gestito subito.)

Quando usare cosa?

Questa è una domanda semplice in un senso e molto complessa in un altro. La differenza fondamentale è che WinSendMsg sarà eseguita immediatamente mentre WinPostMsg verrà gestita quando la finestra estrarrà il messaggio dalla coda. Ci sono però alcune difficoltà.

Poichè WinSendMsg aspetta che la procedura sia completata, bloccherà il vostro programma in attesa che il messsaggio venga gestito. Se questa è un'oprazione lunga, non è consigliabile usare WinSendMsg. La vostra applicazione non risponderà agli eventi finchè non avrà completamente gestito il messaggio. (Nota: usare WinSendMsg con i controlli standard di OS/2 è di solito sicuro. I controlli gestiscono rapidamente i messaggi.)

I messaggi possono essere usati anche per ottenere informazioni da un controllo. Molti messaggi ritorneranno un valore o assegneranno qualcosa a un puntatore passato come parametro. Specialmente quando si usano puntatori, è preferibile usare WinSendMsg. In questo modo potete essere sicuri che il puntatore punti a qualcosa di valido quando il messaggio viene gestito.

WinPostMsg dovrebbe essere usata quando non vi interessa il valore di ritorno o il momento esatto della gestione del messaggio. (Potete essere piuttosto sicuri che non ci vorrà molto a gestire i messaggi accodati. È per questo che il PM risponde rapidamente.)

In generale, usate WinPostMsg perché è una procedura molto più sicura. Comunque, vedrete che nella maggior parte dei casi viene usata WinSendMsg.

L'esempio di questo mese e il multithreading

È difficle pensare a un esempio per mostrare il comportamento di post e send in modo chiaro, poichè voglio tenere questi articoli semplici e non abbiamo ancora parlato del multithreading. L'uso del metodo post ha un grande impatto. Ne discutiamo tra un momento: prima l'esempio. Nell'esempio di questo mese (ZIP, 14k), ho creato un finestra con un menu. Nel menu ci sono due voci: una invierà un messaggio con post, l'altro con send. Il messaggio inviato è un cosiddetto "messaggio utente". (Sì, possiamo definire i nostri messaggi e usarli per quello che vogliamo.) Quando definiamo un messaggio utente, usiamo un numero base (ricordate, un messaggio è solo un numero long) che il PM ha lasciato libero per i messaggi utente. Questo numero è definito come WM_USER. Quindi definiamo i nostri messaggi come segue:

#define UM_BEEP            WM_USER + 1 // Messaggio utente

Indovinare cosa faccia questo messaggio nell'esempio di questo mese non dovrebbe essere troppo difficile. Infatti, attiva un funzione che produce una serie di beep.

Per chiarire cosa appare realmente, il codice attivato dalle voci di menu "Send" e "Post" cambia anche il testo del titolo dell'applicazione. Entrambi eseguono il codice seguente dopo aver inviato il messaggio:

WinSetWindowText(hwndFrame, "This");

DosSleep(500);

WinSetWindowText(hwndFrame, "This is");

DosSleep(500);

WinSetWindowText(hwndFrame, "This is a");

DosSleep(500);

WinSetWindowText(hwndFrame, "This is a test");

Se provate, vedrete che la voce "post" scrive nella barra del titolo. Dopo aver completato questo, il dispatcher riesce ad eseguire il messaggio utente. Quindi si sentiranno dei beep dopo il cambio del titolo. Quando viene usato send, accade esattamente l'opposto. I beep arrivano prima delle scritte sul titolo. Questo mostra che il programma sta aspettando che l'elaborazione del messaggio termini.

Potreste anche notare un altro comportamento. In entrambi i casi non potete usare il menu dopo aver selezionato l'azione. In effetti, non potete fare niente con il sistema mentre il codice è in esecuzione. Questo può essere efficacemente evitato con il multithreading. Ogni buon programma OS/2 usa i thread!

Considerate questo: se un programma ha un secondo thread per eseguire cose come i beep e le scritte sul titolo, il thread principale potrà continuare a gestire altri messaggi, così l'interfaccia continuerà a reagire agli eventi generati dall'utente. Pensandoci alla luce dell'esempio di questo mese, il multithreading è spesso necessario. Perciò nei futuri articoli cercherò un modo semplice di rendere multithreaded i nostri programmi.

Per questo mese concludiamo qui. Spero che la teoria aggiuntiva di questo mese non abbia reso troppo pesante l'articolo. Il prossimo mese continueremo la nostra esplorazione sui dialog, e prima o poi riprenderemo i thread.


[Pagina precedente] [Sommario] [Pagina successiva]