Como gravar o procedimento de janela

A função DispatchMessage chama o procedimento de janela da janela que é o destino da mensagem. O procedimento de janela tem a assinatura a seguir.

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

Existem quatro parâmetros:

  • hwnd é um identificador para a janela.
  • uMsg é o código da mensagem, por exemplo, a mensagem WM_SIZE indica que a janela foi redimensionada.
  • wParam e lParam contêm dados adicionais que pertencem à mensagem. O significado exato depende do código da mensagem.

LRESULT é um valor inteiro que seu programa retorna ao Windows. Ele contém a resposta do programa para uma mensagem específica. O significado desse valor depende do código da mensagem. CALLBACK é a convenção de chamada para a função.

Um procedimento de janela comum é simplesmente uma instrução switch grande que é alternado no código da mensagem. Adicionar ocorrências para cada mensagem que você deseja identificar.

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

    // etc
}

Dados adicionais para a mensagem estão presentes nos parâmetros lParam e wParam. Os dois parâmetros são valores inteiros do tamanho de uma largura de ponteiro (32 bits ou 64 bits). O significado de cada depende do código de mensagem (uMsg). Para cada mensagem, você precisará pesquisar o código da mensagem no MSDN e converter os parâmetros para o tipo de dados correto. Normalmente, os dados são um valor numérico ou um ponteiro para uma estrutura. Algumas mensagens não têm dados.

Por exemplo, a documentação da mensagem WM_SIZE indica que:

  • wParam é um sinalizador que indica se a janela foi minimizada, maximizada ou redimensionada.
  • lParam contém a nova largura e altura da janela como valores de 16 bits compactados em um número de 32 ou 64 bits. Você precisará realizar algumas mudanças de bits para obter esses valores. Felizmente, o arquivo de cabeçalho WinDef.h inclui macros auxiliares que fazem isso.

Um procedimento de janela comum lida com dezenas de mensagens, para que ele possa crescer bastante. Uma maneira de tornar seu código mais modular é colocando a lógica para tratar cada mensagem em uma função separada. No procedimento de janela, converta os parâmetros wParam e lParam para o tipo de dados correto e passe esses valores para a função. Por exemplo, para lidar com a mensagem WM_SIZE, o procedimento de janela seria assim:

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
}

As macros LOWORD e HIWORD obtêm os valores de largura e altura de 16 bits de lParam. (Você pode pesquisar esses tipos de detalhes na documentação do MSDN para cada código de mensagem.) O procedimento de janela extrai a largura e a altura e passa esses valores para a função OnSize.

Manipulação de mensagens padrão

Se você não manipular uma mensagem específica em seu procedimento de janela, passe os parâmetros de mensagem diretamente para a função DefWindowProc. Essa função executa a ação padrão para a mensagem, que varia de acordo com o tipo de mensagem.

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

Evitando gargalos no procedimento de janela

Enquanto o procedimento de janela é executado, ele bloqueia todas as outras mensagem para janelas criadas no mesmo thread. Portanto, evite o processamento demorado dentro do procedimento de janela. Por exemplo, imagine que seu programa abriu uma conexão TCP e aguarda indefinidamente para que o servidor responda. Se você fizer isso dentro do procedimento de janela, sua interface do usuário não responderá até que a solicitação seja concluída. Durante esse tempo, a janela não pode processar a entrada do mouse ou teclado, repintar a si mesma ou até mesmo fechar.

Em vez disso, você deve mover o trabalho para outro thread, usando uma das instalações multitarefa que são incorporadas ao Windows:

  • Criar uma thread nova.
  • Use um pool de thread.
  • Use chamadas de E/S assíncronas.
  • Use chamadas de procedimento assíncronas.

Próximo

Como pintar a janela