Sviluppo

Come faccio? - parte X

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 8
Il mese scorsoho dato una rapida introduzione agli editor di dialogs e, soprattutto, su come usare l'attributo WS_GROUP. Ho detto il mese scorso che questa caratteristica non è molto nota. Per sottolineare la mia idea, guardate ad esempio PMMail. Provate a inserire un nuovo indirizzo nella rubrica e poi provate a passare alla linea successiva con tasto cursore giù. Vedrete cosa voglio dire. Gli esempi di questo comportamento sono tantissimi (spero che l'articolo scorso sia utile a qualcosa).

Quello che abbiamo fatto il mese scorso non riesce comunque a far funzionare i dialogs. È come con Delphi, Visual Cafe e altri strumenti visuali: diesgnare le finestre è semplice (ma non sottovalutate questo aspetto: un'interfaccia accattivante è una cosa grossa). Non c'è bisogno di programmare. Ma per far sì che un dialog faccia qualcosa, è proprio necessario programmare.

Questo mese e il prossimo tratteremo la costruzione di programmi per i dialogs. Questo significa che dovremo esaminarne la struttura generale, proprio come abbiamo fatto per le frame windows. E vedremo cosa succede quando un dialog viene chiamato con WinLoadDlg o WinDlgBox. Infine, vedremo che è persino possibile scrivere un'applicazione fatta interamente di dialogs (la cosa interessante è che non dobbiamo preoccuparci dei controlli di frame). Ma tutto questo più tardi. Andiamo con ordine.

Il mese scorso abbiamo imparato alcune cose essenziali sui dialogs. Abbiamo visto due modi per aprirli, ma anche che un dialog ha una sua propria window procedure. La window procedure di default, inoltre, non è la stessa delle normali finestre. Nel caso dei dialogs è WinDefDlgProc. Ripeto il mio avvertimento del mese scorso: non usate WinDefWindowProc per i dialogs; può darsi che qualche volta funzioni, ma può provocare comportamenti strani e imprevedibili. Ed è un errore molto difficile da scoprire!

In che modo la window procedure dei dialogs è diversa da quella di una normale finestra? Per noi programmatori semplici c'è solo un particolare davvero interressante. Un dialog non riceve il messaggio WM_CREATE come una normale finestra quando viene creato. Riceve invece il messaggio WM_INITDLG. Vediamo per prima una parte importante di questo messaggio, il parametro mp2.

Il secondo parametro del messaggio WM_INITDLG contiene un puntatore (pCreate) a un'area dati definita dal programma. Cos'è questo puntatore e per cosa lo usiamo? In effetti, non è proprio un puntatore, è un intero lungo. Poiché un "long" e un puntatore sono entrambi numeri di 32 bit, possono essere scambiati (fate comunque attenzione). Il valore ricevuto in mp2 viene impostato chiamando WinLoadDlg o WinDlgBox.

WinDlgBox(HWND_DESKTOP,         // Parent
          hwnd,                 // Owner
          WinDefDlgProc,        // Window procedure
          NULLHANDLE,           // Dov'è la risorsa?
          DIALOG1,              // Dialog Resource ID
--------> 0);                   // Parametro di creazione (usato in WM_INITDLG)

WinLoadDlg(HWND_DESKTOP,        // Parent
           hwnd,                // Owner
           WinDefDlgProc,       // Window procedure
           NULLHANDLE,          // Dov'` la risorsa?
           DIALOG1,             // Dialog Resource ID
-------->  0);                  // Parametro di creazione (usato in WM_INITDLG)
Negli esempi, il parametro di creazione è posto a zero, ma al suo posto possiamo inserire un puntatore. Potete metterci qualsiasi long e questo verrà passato come mp2 nel messaggio WM_INITDLG. Nella maggior parte dei casi le informazioni passate vengono usate per inizializzare il dialog. Ad ogni modo, è a questo che serve WM_INITDLG (approfondiremo l'inizializzazione il mese prossimo).

Comunque, se vogliamo usare le informazioni puntate da mp2 per gestire i messaggi inviati al dialog, ci imbattiamo in un problema: mp2 è valido solo durante la gestione di WM_INITDLG. In altri messaggi, mp2 ha altri significati! Beh, nessun problema, salviamo questa informazione in una variabile temporanea.

Si può fare. Basta creare una variabile long (o meglio PVOID) e assegnarci mp2 durante WM_INITDLG.

Questo porta però a un altro problema. La window procedure termina dopo la gestione di ogni messaggio. Quindi la variabile verrà distrutta e avrà un valore casuale la prossima volta che la funzione verrà chiamata, ad esempio per un WM_COMMAND.

Questo fenomeno si può vedre nell'esempio di questo mese (ZIP, 15k). Nell'esempio viene creata una stringa nella window procedure della frame window. Un puntatore a questa stringa viene passato al dialog. Durante WM_INITDLG, il contenuto della stringa viene scritto in ENTRYFIELD1 e ne viene fatta una copia nella variabile PVOID mp2Pointer2. Se si preme OK, viene inviato un WM_COMMAND al dialog e questo cercherà di scrivere il contenuto della stringa puntata da mp2Pointer2 in ENTRYFIELD2. Noterete che non viene scritta la stringa giusta.

Per superare questo problema si usa una variabile statica. Una variabile statica può essere vista come una variabile globale nel senso che il suo valore viene mantenuto anche oltre il termine della procedura. Ha però solo visibilità locale. Quindi la prossima volta che la procedura viene chiamata, la variabile statica avrà ancora il suo valore. Possiamo vedere l'effetto di ciò in ENTRYFIELD3, dove viene scritto il contenuto di questa variabile statica. Se provate, vedrete che il valore resta inalterato.


[Pagina precedente] [Sommario] [Pagina successiva]