Scrittura della procedura finestra

La funzione DispatchMessage chiama la routine finestra della finestra che rappresenta la destinazione del messaggio. La procedura della finestra ha la firma seguente.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

Esistono quattro parametri:

  • hwnd è un handle per la finestra.
  • uMsg è il codice del messaggio. Ad esempio, il messaggio WM_SIZE indica che la finestra è stata ridimensionata.
  • wParam e lParam contengono dati aggiuntivi relativi al messaggio. Il significato esatto dipende dal codice del messaggio.

LRESULT è un valore intero restituito dal programma a Windows. Contiene la risposta del programma a un determinato messaggio. Il significato di questo valore dipende dal codice del messaggio. CALLBACK è la convenzione di chiamata per la funzione.

Una routine di finestra tipica è semplicemente un'istruzione switch di grandi dimensioni che attiva il codice del messaggio. Aggiungere casi per ogni messaggio che si vuole gestire.

switch (uMsg)
{
    case WM_SIZE: // Handle window resizing

    // etc
}

I dati aggiuntivi per il messaggio sono contenuti nei parametri lParam e wParam . Entrambi i parametri sono valori interi la dimensione di una larghezza del puntatore (32 bit o 64 bit). Il significato di ognuno dipende dal codice del messaggio (uMsg). Per ogni messaggio, sarà necessario cercare il codice del messaggio in MSDN ed eseguire il cast dei parametri al tipo di dati corretto. In genere i dati sono un valore numerico o un puntatore a una struttura. Alcuni messaggi non contengono dati.

Ad esempio, la documentazione per il messaggio WM_SIZE indica che:

  • wParam è un flag che indica se la finestra è stata ridotta a icona, ingrandita o ridimensionata.
  • lParam contiene la nuova larghezza e l'altezza della finestra come valori a 16 bit compressi in un numero a 32 o 64 bit. Per ottenere questi valori, sarà necessario eseguire alcune operazioni di spostamento dei bit. Fortunatamente, il file di intestazione WinDef.h include macro helper che eseguono questa operazione.

Una tipica procedura di finestra gestisce decine di messaggi, quindi può crescere abbastanza a lungo. Un modo per rendere il codice più modulare consiste nell'inserire la logica per la gestione di ogni messaggio in una funzione separata. Nella procedura della finestra eseguire il cast dei parametri wParam e lParam al tipo di dati corretto e passare tali valori alla funzione. Ad esempio, per gestire il messaggio di WM_SIZE , la routine della finestra sarà simile alla seguente:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_SIZE:
        {
            int width = LOWORD(lParam);  // Macro to get the low-order word.
            int height = HIWORD(lParam); // Macro to get the high-order word.

            // Respond to the message:
            OnSize(hwnd, (UINT)wParam, width, height);
        }
        break;
    }
}

void OnSize(HWND hwnd, UINT flag, int width, int height)
{
    // Handle resizing
}

Le macro LOWORD e HIWORD ottengono i valori di larghezza e altezza a 16 bit da lParam. È possibile cercare questi tipi di dettagli nella documentazione MSDN per ogni codice di messaggio. La procedura della finestra estrae la larghezza e l'altezza e quindi passa questi valori alla OnSize funzione.

Gestione dei messaggi predefinita

Se non si gestisce un messaggio specifico nella procedura della finestra, passare i parametri del messaggio direttamente alla funzione DefWindowProc. Questa funzione esegue l'azione predefinita per il messaggio, che varia in base al tipo di messaggio.

return DefWindowProc(hwnd, uMsg, wParam, lParam);

Evitare colli di bottiglia nella procedura finestra

Mentre viene eseguita la routine della finestra, blocca tutti gli altri messaggi per le finestre create nello stesso thread. Pertanto, evitare un'elaborazione lunga all'interno della routine della finestra. Si supponga, ad esempio, che il programma apra una connessione TCP e attenda a tempo indeterminato che il server risponda. Se si esegue questa operazione all'interno della procedura della finestra, l'interfaccia utente non risponderà fino al completamento della richiesta. Durante questo periodo, la finestra non può elaborare l'input del mouse o della tastiera, riavformare se stesso o addirittura chiudere.

È invece consigliabile spostare il lavoro in un altro thread, usando una delle funzionalità multitasking integrate in Windows:

  • Creare un nuovo thread.
  • Usare un pool di thread.
  • Usare chiamate di I/O asincrone.
  • Usare chiamate di procedura asincrone.

Avanti

Disegnare la finestra