Sobre mensagens e filas de mensagens

Ao contrário dos aplicativos baseados em MS-DOS, os aplicativos baseados em Windows são controlados por eventos. Eles não fazem chamadas de função explícitas (como chamadas de biblioteca em tempo de execução C) para obter entrada. Em vez disso, eles esperam que o sistema passe a entrada para eles.

O sistema passa todas as entradas de um aplicativo para as várias janelas do aplicativo. Cada janela tem uma função, chamada de procedimento de janela, que o sistema chama sempre que tem entrada para a janela. O procedimento de janela processa a entrada e retorna o controle para o sistema. Para obter mais informações sobre procedimentos de janela, consulte Procedimentos de janela.

Se uma janela de nível superior parar de responder às mensagens por mais de vários segundos, o sistema considerará que a janela não está respondendo. Nesse caso, o sistema oculta a janela e a substitui por uma janela fantasma que tem os mesmos atributos de ordem, local, tamanho e visual Z. Isso permite que o usuário o mova, redimensione-o ou até mesmo feche o aplicativo. No entanto, essas são as únicas ações disponíveis porque o aplicativo realmente não está respondendo. Quando estiver no modo de depurador, o sistema não gerará uma janela fantasma.

Esta seção discute os seguintes tópicos:

Mensagens do Windows

O sistema passa a entrada para um procedimento de janela na forma de uma mensagem. As mensagens são geradas pelo sistema e pelos aplicativos. O sistema gera uma mensagem em cada evento de entrada, por exemplo, quando o usuário digita, move o mouse ou clica em um controle como uma barra de rolagem. O sistema também gera mensagens em resposta a alterações no sistema geradas por um aplicativo, como quando um aplicativo altera o pool de recursos de fonte do sistema ou redimensiona uma de suas janelas. Um aplicativo pode gerar mensagens para direcionar suas próprias janelas para executar tarefas ou se comunicar com janelas em outros aplicativos.

O sistema envia uma mensagem para um procedimento de janela com um conjunto de quatro parâmetros: um identificador de janela, um identificador de mensagem e dois valores chamados parâmetros de mensagem. O identificador de janela identifica a janela para a qual a mensagem se destina. O sistema o usa para determinar qual procedimento de janela deve receber a mensagem.

Um identificador de mensagem é uma constante nomeada que identifica a finalidade de uma mensagem. Quando um procedimento de janela recebe uma mensagem, ele usa um identificador de mensagem para determinar como processar a mensagem. Por exemplo, o identificador de mensagem WM_PAINT informa ao procedimento de janela que a área de cliente da janela foi alterada e deve ser repintada.

Os parâmetros de mensagem especificam dados ou o local dos dados usados por um procedimento de janela ao processar uma mensagem. O significado e o valor dos parâmetros de mensagem dependem da mensagem. Um parâmetro de mensagem pode conter um número inteiro, sinalizadores de bits empacotados, um ponteiro para uma estrutura que contém dados adicionais e assim por diante. Quando uma mensagem não usa parâmetros de mensagem, elas normalmente são definidas como NULL. Um procedimento de janela deve marcar o identificador de mensagem para determinar como interpretar os parâmetros de mensagem.

Tipos de mensagem

Esta seção descreve os dois tipos de mensagens:

mensagens System-Defined

O sistema envia ou posta uma mensagem definida pelo sistema quando se comunica com um aplicativo. Ele usa essas mensagens para controlar as operações de aplicativos e para fornecer entrada e outras informações para os aplicativos processarem. Um aplicativo também pode enviar ou postar mensagens definidas pelo sistema. Os aplicativos geralmente usam essas mensagens para controlar a operação das janelas de controle criadas usando classes de janela pré-registrados.

Cada mensagem definida pelo sistema tem um identificador de mensagem exclusivo e uma constante simbólica correspondente (definida nos arquivos de cabeçalho do SDK (software development kit) que declara a finalidade da mensagem. Por exemplo, o WM_PAINT solicitações constantes de que uma janela pinte seu conteúdo.

Constantes simbólicas especificam a categoria à qual as mensagens definidas pelo sistema pertencem. O prefixo da constante identifica o tipo de janela que pode interpretar e processar a mensagem. A seguir estão os prefixos e suas categorias de mensagem relacionadas.

Prefixo Categoria de mensagem Documentação
ABM e ABN Barra de ferramentas da área de trabalho do aplicativo Mensagens e notificações do Shell
ACM e ACN Controle de animação Mensagens de controle de animação e notificações de controle de animação
BCM, BCN, BM e BN Controle de botão Mensagens de controle de botão e notificações de controle de botão
CB e CBN Controle ComboBox Mensagens de controle ComboBox e notificações de controle ComboBox
CBEM e CBEN Controle ComboBoxEx Mensagens comboBoxEx e notificações comboBoxEx
CCM Controle geral Controlar mensagens
CDM Caixa de diálogo comum Mensagens comuns da caixa de diálogo
DFM Menu de contexto padrão Mensagens e notificações do Shell
DL Caixa de listagem arrastar Arrastar notificações da caixa de listagem
DM Controle de botão de push padrão Mensagens da caixa de diálogo
DTM e DTN Controle do seletor de data e hora Mensagens do seletor de data e hora e notificações do seletor de data e hora
EM e EN Controle de edição Editar mensagens de controle, editar notificações de controle, mensagens de edição avançada e notificações de edição avançada
HDM e HDN Controle de cabeçalho Mensagens de controle de cabeçalho e notificações de controle de cabeçalho
HKM Controle de tecla de acesso Mensagens de controle de teclas de acesso
IPM e IPN Controle de endereço IP Mensagens de endereço IP e notificações de endereço IP
LB e LBN Controle de caixa de listagem Mensagens de caixa de listagem e notificações de caixa de listagem
LM Controle SysLink Mensagens de controle SysLink
LVM e LVN Controle de exibição de lista Mensagens de exibição de lista e notificações de exibição de lista
MCM e MCN Controle de calendário de mês Mensagens do calendário do mês e notificações de calendário do mês
PBM Barra de progresso Mensagens da barra de progresso
PGM e PGN Controle pager Mensagens de controle de pager e notificações de controle de pager
PSM e PSN Folha de propriedades Mensagens da folha de propriedades e notificações de folha de propriedades
RB e RBN Controle rebar Mensagens de controle rebar e notificações de controle rebar
SB e SBN Janela da barra de status Mensagens da barra de status e notificações da barra de status
SBM Controle de barra de rolagem Mensagens da barra de rolagem
SMC Menu Shell Mensagens e notificações do Shell
STM e STN Controle estático Mensagens de controle estático e notificações de controle estático
TB e TBN Barra de ferramentas Mensagens de controle da barra de ferramentas e notificações de controle da barra de ferramentas
TBM e TRBN Controle trackbar Mensagens de controle trackbar e notificações de controle trackbar
TCM e TCN Controle guia Mensagens de controle guia e notificações de controle guia
TDM e TDN Caixa de diálogo Tarefa Mensagens de caixa de diálogo da tarefa e notificações da caixa de diálogo da tarefa
TTM e TTN Controle de dica de ferramenta Mensagens de controle de dica de ferramenta e notificações de controle de dica de ferramenta
TVM e TVN Controle de exibição de árvore Mensagens de exibição de árvore e notificações de exibição de árvore
UDM e UDN Controle para cima e para baixo Mensagens para cima e notificações para cima para baixo
WM Geral
Mensagens da área de transferência
Notificações da área de transferência
Notificações comuns da caixa de diálogo
Notificações de cursor
Mensagem de Cópia de Dados
Mensagens do Gerenciador de Janelas da Área de Trabalho
mensagens Gerenciamento de Dispositivos
Notificações da caixa de diálogo
Mensagens dinâmicas de troca de dados
Notificações dinâmicas de troca de dados
Notificações de gancho
Mensagens de acelerador de teclado
Notificações do acelerador de teclado
Mensagens de entrada do teclado
Notificações de entrada do teclado
Notificações do menu
Notificações de entrada do mouse
Várias mensagens da interface do documento
Notificações de entrada brutas
Notificações da barra de rolagem
Notificações do temporizador
Mensagens de janela
Notificações de janela

As mensagens de janela geral abrangem uma ampla variedade de informações e solicitações, incluindo mensagens para entrada de mouse e teclado, entrada de menu e caixa de diálogo, criação e gerenciamento de janelas e DDE (Troca Dinâmica de Dados).

mensagens Application-Defined

Um aplicativo pode criar mensagens a serem usadas por suas próprias janelas ou para se comunicar com janelas em outros processos. Se um aplicativo criar suas próprias mensagens, o procedimento de janela que as recebe deverá interpretar as mensagens e fornecer o processamento apropriado.

Os valores de identificador de mensagem são usados da seguinte maneira:

  • O sistema reserva valores de identificador de mensagem no intervalo 0x0000 até 0x03FF (o valor de WM_USER – 1) para mensagens definidas pelo sistema. Os aplicativos não podem usar esses valores para mensagens privadas.
  • Os valores no intervalo 0x0400 (o valor de WM_USER) por meio de 0x7FFF estão disponíveis para identificadores de mensagem para classes de janela privada.
  • Se o aplicativo estiver marcado como versão 4.0, você poderá usar valores de identificador de mensagem no intervalo 0x8000 (WM_APP) por meio de 0xBFFF para mensagens privadas.
  • O sistema retorna um identificador de mensagem no intervalo 0xC000 até 0xFFFF quando um aplicativo chama a função RegisterWindowMessage para registrar uma mensagem. O identificador de mensagem retornado por essa função tem a garantia de ser exclusivo em todo o sistema. O uso dessa função impede conflitos que podem surgir se outros aplicativos usarem o mesmo identificador de mensagem para fins diferentes.

Roteamento de mensagem

O sistema usa dois métodos para rotear mensagens para um procedimento de janela: postar mensagens em uma fila inicial chamada fila de mensagens, um objeto de memória definido pelo sistema que armazena temporariamente mensagens e enviar mensagens diretamente para um procedimento de janela.

Uma mensagem postada em uma fila de mensagens é chamada de mensagem enfileirada. Eles são principalmente o resultado da entrada do usuário inserida por meio do mouse ou teclado, como mensagens de WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN e WM_CHAR . Outras mensagens na fila incluem o temporizador, a pintura e as mensagens de encerramento: WM_TIMER, WM_PAINT e WM_QUIT. A maioria das outras mensagens, que são enviadas diretamente para um procedimento de janela, são chamadas de mensagens não enfileiradas.

Mensagens enfileiradas

O sistema pode exibir qualquer número de janelas por vez. Para rotear a entrada do mouse e do teclado para a janela apropriada, o sistema usa filas de mensagens.

O sistema mantém uma única fila de mensagens do sistema e uma fila de mensagens específica de thread para cada thread de GUI. Para evitar a sobrecarga de criação de uma fila de mensagens para threads não GUI, todos os threads são criados inicialmente sem uma fila de mensagens. O sistema cria uma fila de mensagens específica do thread somente quando o thread faz sua primeira chamada para uma das funções de usuário específicas; nenhuma chamada de função gui resulta na criação de uma fila de mensagens.

Sempre que o usuário move o mouse, clica nos botões do mouse ou em tipos no teclado, o driver do dispositivo para o mouse ou teclado converte a entrada em mensagens e as coloca na fila de mensagens do sistema. O sistema remove as mensagens, uma de cada vez, da fila de mensagens do sistema, as examina para determinar a janela de destino e, em seguida, as posta na fila de mensagens do thread que criou a janela de destino. A fila de mensagens de um thread recebe todas as mensagens de mouse e teclado para as janelas criadas pelo thread. O thread remove mensagens de sua fila e direciona o sistema para enviá-las para o procedimento de janela apropriado para processamento.

Com exceção da mensagem WM_PAINT , a mensagem WM_TIMER e a mensagem WM_QUIT , o sistema sempre posta mensagens no final de uma fila de mensagens. Isso garante que uma janela receba suas mensagens de entrada na sequência FIFO (primeiro a entrar e sair) adequada. A mensagem WM_PAINT , a mensagem WM_TIMER e a mensagem WM_QUIT , no entanto, são mantidas na fila e são encaminhadas para o procedimento de janela somente quando a fila não contém outras mensagens. Além disso, várias mensagens WM_PAINT para a mesma janela são combinadas em uma única mensagem WM_PAINT , consolidando todas as partes inválidas da área do cliente em uma única área. A combinação de mensagens WM_PAINT reduz o número de vezes que uma janela deve redesenhar o conteúdo de sua área de cliente.

O sistema posta uma mensagem na fila de mensagens de um thread preenchendo uma estrutura MSG e copiando-a para a fila de mensagens. As informações no MSG incluem: o identificador da janela para a qual a mensagem se destina, o identificador de mensagem, os dois parâmetros de mensagem, a hora em que a mensagem foi postada e a posição do cursor do mouse. Um thread pode postar uma mensagem em sua própria fila de mensagens ou na fila de outro thread usando a função PostMessage ou PostThreadMessage .

Um aplicativo pode remover uma mensagem de sua fila usando a função GetMessage . Para examinar uma mensagem sem removê-la de sua fila, um aplicativo pode usar a função PeekMessage . Essa função preenche o MSG com informações sobre a mensagem.

Depois de remover uma mensagem de sua fila, um aplicativo pode usar a função DispatchMessage para direcionar o sistema para enviar a mensagem para um procedimento de janela para processamento. DispatchMessage usa um ponteiro para MSG que foi preenchido por uma chamada anterior para a função GetMessage ou PeekMessage . DispatchMessage passa o identificador de janela, o identificador de mensagem e os dois parâmetros de mensagem para o procedimento de janela, mas não passa a hora em que a mensagem foi postada ou a posição do cursor do mouse. Um aplicativo pode recuperar essas informações chamando as funções GetMessageTime e GetMessagePos durante o processamento de uma mensagem.

Um thread pode usar a função WaitMessage para gerar controle para outros threads quando não tiver mensagens em sua fila de mensagens. A função suspende o thread e não retorna até que uma nova mensagem seja colocada na fila de mensagens do thread.

Você pode chamar a função SetMessageExtraInfo para associar um valor à fila de mensagens do thread atual. Em seguida, chame a função GetMessageExtraInfo para obter o valor associado à última mensagem recuperada pela função GetMessage ou PeekMessage .

Mensagens não enfileiradas

Mensagens não enfileiradas são enviadas imediatamente para o procedimento de janela de destino, ignorando a fila de mensagens do sistema e a fila de mensagens de thread. O sistema normalmente envia mensagens não enfileiradas para notificar uma janela de eventos que o afetam. Por exemplo, quando o usuário ativa uma nova janela de aplicativo, o sistema envia à janela uma série de mensagens, incluindo WM_ACTIVATE, WM_SETFOCUS e WM_SETCURSOR. Essas mensagens notificam a janela de que ela foi ativada, que a entrada do teclado está sendo direcionada para a janela e que o cursor do mouse foi movido dentro das bordas da janela. Mensagens não enfileiradas também podem resultar quando um aplicativo chama determinadas funções do sistema. Por exemplo, o sistema envia a mensagem WM_WINDOWPOSCHANGED depois que um aplicativo usa a função SetWindowPos para mover uma janela.

Algumas funções que enviam mensagens não enviadas são BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeout e SendNotifyMessage.

Tratamento de mensagens

Um aplicativo deve remover e processar mensagens postadas nas filas de mensagens de seus threads. Um aplicativo de thread único geralmente usa um loop de mensagem em sua função WinMain para remover e enviar mensagens para os procedimentos de janela apropriados para processamento. Aplicativos com vários threads podem incluir um loop de mensagem em cada thread que cria uma janela. As seções a seguir descrevem como funciona um loop de mensagem e explicam a função de um procedimento de janela:

Loop de Mensagem

Um loop de mensagem simples consiste em uma chamada de função para cada uma dessas três funções: GetMessage, TranslateMessage e DispatchMessage. Observe que, se houver um erro, GetMessage retornará –1, portanto, a necessidade do teste especial.

MSG msg;
BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}

A função GetMessage recupera uma mensagem da fila e a copia para uma estrutura do tipo MSG. Ele retorna um valor diferente de zero, a menos que encontre a mensagem WM_QUIT , nesse caso, retorna FALSE e encerra o loop. Em um aplicativo de thread único, encerrar o loop de mensagem geralmente é a primeira etapa para fechar o aplicativo. Um aplicativo pode encerrar seu próprio loop usando a função PostQuitMessage, normalmente em resposta à mensagem WM_DESTROY no procedimento de janela da janela main do aplicativo.

Se você especificar um identificador de janela como o segundo parâmetro de GetMessage, somente as mensagens para a janela especificada serão recuperadas da fila. GetMessage também pode filtrar mensagens na fila, recuperando apenas as mensagens que se enquadram em um intervalo especificado. Para obter mais informações sobre como filtrar mensagens, consulte Filtragem de Mensagens.

O loop de mensagem de um thread deve incluir TranslateMessage se o thread deve receber entrada de caractere do teclado. O sistema gera mensagens de tecla virtual (WM_KEYDOWN e WM_KEYUP) sempre que o usuário pressiona uma tecla. Uma mensagem de tecla virtual contém um código de tecla virtual que identifica qual tecla foi pressionada, mas não seu valor de caractere. Para recuperar esse valor, o loop de mensagem deve conter TranslateMessage, que converte a mensagem de chave virtual em uma mensagem de caractere (WM_CHAR) e a coloca novamente na fila de mensagens do aplicativo. Em seguida, a mensagem de caractere pode ser removida após uma iteração subsequente do loop de mensagem e enviada para um procedimento de janela.

A função DispatchMessage envia uma mensagem para o procedimento de janela associado ao identificador de janela especificado na estrutura MSG . Se o identificador de janela for HWND_TOPMOST, DispatchMessage enviará a mensagem para os procedimentos de janela de todas as janelas de nível superior no sistema. Se o identificador de janela for NULL, DispatchMessage não fará nada com a mensagem.

O thread main de um aplicativo inicia seu loop de mensagem depois de inicializar o aplicativo e criar pelo menos uma janela. Depois de iniciado, o loop de mensagem continua a recuperar mensagens da fila de mensagens do thread e a expedir para as janelas apropriadas. O loop de mensagem termina quando a função GetMessage remove a mensagem WM_QUIT da fila de mensagens.

Apenas um loop de mensagem é necessário para uma fila de mensagens, mesmo que um aplicativo contenha muitas janelas. DispatchMessage sempre envia a mensagem para a janela adequada; isso ocorre porque cada mensagem na fila é uma estrutura MSG que contém o identificador da janela à qual a mensagem pertence.

Você pode modificar um loop de mensagem de várias maneiras. Por exemplo, você pode recuperar mensagens da fila sem expedir para uma janela. Isso é útil para aplicativos que postam mensagens que não especificam uma janela. Você também pode direcionar GetMessage para pesquisar mensagens específicas, deixando outras mensagens na fila. Isso será útil se você precisar ignorar temporariamente a ordem FIFO usual da fila de mensagens.

Um aplicativo que usa teclas de acelerador deve ser capaz de traduzir mensagens de teclado em mensagens de comando. Para fazer isso, o loop de mensagem do aplicativo deve incluir uma chamada para a função TranslateAccelerator . Para obter mais informações sobre teclas de acelerador, consulte Aceleradores de teclado.

Se um thread usar uma caixa de diálogo modeless, o loop de mensagem deverá incluir a função IsDialogMessage para que a caixa de diálogo possa receber entrada de teclado.

Procedimento de janela

Um procedimento de janela é uma função que recebe e processa todas as mensagens enviadas para a janela. Cada classe de janela tem um procedimento de janela e cada janela criada com essa classe usa o mesmo procedimento de janela para responder às mensagens.

O sistema envia uma mensagem para um procedimento de janela passando os dados da mensagem como argumentos para o procedimento. Em seguida, o procedimento de janela executa uma ação apropriada para a mensagem; ele verifica o identificador de mensagem e, ao processar a mensagem, usa as informações especificadas pelos parâmetros de mensagem.

Um procedimento de janela geralmente não ignora uma mensagem. Se ele não processar uma mensagem, ele deverá enviar a mensagem de volta ao sistema para processamento padrão. O procedimento de janela faz isso chamando a função DefWindowProc , que executa uma ação padrão e retorna um resultado de mensagem. Em seguida, o procedimento de janela deve retornar esse valor como seu próprio resultado de mensagem. A maioria dos procedimentos de janela processa apenas algumas mensagens e passa as outras para o sistema chamando DefWindowProc.

Como um procedimento de janela é compartilhado por todas as janelas pertencentes à mesma classe, ele pode processar mensagens para várias janelas diferentes. Para identificar a janela específica afetada pela mensagem, um procedimento de janela pode examinar o identificador de janela passado com uma mensagem. Para obter mais informações sobre procedimentos de janela, consulte Procedimentos de janela.

Filtragem de Mensagem

Um aplicativo pode escolher mensagens específicas para recuperar da fila de mensagens (ignorando outras mensagens) usando a função GetMessage ou PeekMessage para especificar um filtro de mensagem. O filtro é um intervalo de identificadores de mensagem (especificados por um primeiro e último identificador), um identificador de janela ou ambos. GetMessage e PeekMessage usam um filtro de mensagem para selecionar quais mensagens recuperar da fila. A filtragem de mensagens será útil se um aplicativo precisar pesquisar mensagens na fila de mensagens que chegaram mais tarde na fila. Também será útil se um aplicativo precisar processar mensagens de entrada (hardware) antes de processar mensagens postadas.

As constantes WM_KEYFIRST e WM_KEYLAST podem ser usadas como valores de filtro para recuperar todas as mensagens de teclado; as constantes WM_MOUSEFIRST e WM_MOUSELAST podem ser usadas para recuperar todas as mensagens do mouse.

Qualquer aplicativo que filtre mensagens deve garantir que uma mensagem que satisfaz o filtro de mensagem possa ser postada. Por exemplo, se um aplicativo filtrar uma mensagem WM_CHAR em uma janela que não recebe entrada de teclado, a função GetMessage não retorna. Isso efetivamente "trava" o aplicativo.

Postando e enviando mensagens

Qualquer aplicativo pode postar e enviar mensagens. Assim como o sistema, um aplicativo posta uma mensagem copiando-a em uma fila de mensagens e envia uma mensagem passando os dados da mensagem como argumentos para um procedimento de janela. Para postar mensagens, um aplicativo usa a função PostMessage . Um aplicativo pode enviar uma mensagem chamando a função SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage ou SendDlgItemMessage .

Postando mensagens

Um aplicativo normalmente posta uma mensagem para notificar uma janela específica para executar uma tarefa. O PostMessage cria uma estrutura MSG para a mensagem e copia a mensagem para a fila de mensagens. O loop de mensagem do aplicativo eventualmente recupera a mensagem e a envia para o procedimento de janela apropriado.

Um aplicativo pode postar uma mensagem sem especificar uma janela. Se o aplicativo fornecer um identificador de janela NULL ao chamar PostMessage, a mensagem será postada na fila associada ao thread atual. Como nenhum identificador de janela é especificado, o aplicativo deve processar a mensagem no loop de mensagem. Essa é uma maneira de criar uma mensagem que se aplica a todo o aplicativo, em vez de a uma janela específica.

Ocasionalmente, talvez você queira postar uma mensagem em todas as janelas de nível superior no sistema. Um aplicativo pode postar uma mensagem em todas as janelas de nível superior chamando PostMessage e especificando HWND_TOPMOST no parâmetro hwnd .

Um erro de programação comum é assumir que a função PostMessage sempre posta uma mensagem. Isso não é verdade quando a fila de mensagens está cheia. Um aplicativo deve marcar o valor retornado da função PostMessage para determinar se a mensagem foi postada e, se não tiver sido, repostá-la.

enviando mensagens

Um aplicativo normalmente envia uma mensagem para notificar um procedimento de janela para executar uma tarefa imediatamente. A função SendMessage envia a mensagem para o procedimento de janela correspondente à janela fornecida. A função aguarda até que o procedimento de janela conclua o processamento e retorne o resultado da mensagem. As janelas pai e filho geralmente se comunicam enviando mensagens umas para as outras. Por exemplo, uma janela pai que tem um controle de edição como sua janela filho pode definir o texto do controle enviando uma mensagem para ele. O controle pode notificar a janela pai de alterações no texto que são executadas pelo usuário enviando mensagens de volta para o pai.

A função SendMessageCallback também envia uma mensagem para o procedimento de janela correspondente à janela fornecida. No entanto, essa função retorna imediatamente. Depois que o procedimento de janela processa a mensagem, o sistema chama a função de retorno de chamada especificada. Para obter mais informações sobre a função de retorno de chamada, consulte a função SendAsyncProc .

Ocasionalmente, talvez você queira enviar uma mensagem para todas as janelas de nível superior no sistema. Por exemplo, se o aplicativo alterar a hora do sistema, ele deverá notificar todas as janelas de nível superior sobre a alteração enviando uma mensagem WM_TIMECHANGE . Um aplicativo pode enviar uma mensagem para todas as janelas de nível superior chamando SendMessage e especificando HWND_TOPMOST no parâmetro hwnd . Você também pode transmitir uma mensagem para todos os aplicativos chamando a função BroadcastSystemMessage e especificando BSM_APPLICATIONS no parâmetro lpdwRecipients .

Usando a função InSendMessage ou InSendMessageEx , um procedimento de janela pode determinar se ele está processando uma mensagem enviada por outro thread. Essa funcionalidade é útil quando o processamento de mensagens depende da origem da mensagem.

Deadlocks de mensagem

Um thread que chama a função SendMessage para enviar uma mensagem para outro thread não pode continuar sendo executado até que o procedimento de janela que recebe a mensagem retorne. Se o thread de recebimento produzir controle durante o processamento da mensagem, o thread de envio não poderá continuar em execução, pois está aguardando o retorno de SendMessage . Se o thread de recebimento estiver anexado à mesma fila que o remetente, ele poderá fazer com que um deadlock do aplicativo ocorra. (Observe que os ganchos de diário anexam threads à mesma fila.)

Observe que o thread receptor não precisa produzir controle explicitamente; chamar qualquer uma das funções a seguir pode fazer com que um thread gere controle implicitamente.

Para evitar possíveis deadlocks em seu aplicativo, considere usar as funções SendNotifyMessage ou SendMessageTimeout . Caso contrário, um procedimento de janela pode determinar se uma mensagem recebida foi enviada por outro thread chamando a função InSendMessage ou InSendMessageEx . Antes de chamar qualquer uma das funções na lista anterior durante o processamento de uma mensagem, o procedimento de janela deve primeiro chamar InSendMessage ou InSendMessageEx. Se essa função retornar TRUE, o procedimento de janela deverá chamar a função ReplyMessage antes de qualquer função que faça com que o thread gere controle.

Mensagens de difusão

Cada mensagem consiste em um identificador de mensagem e dois parâmetros, wParam e lParam. O identificador de mensagem é um valor exclusivo que especifica a finalidade da mensagem. Os parâmetros fornecem informações adicionais específicas da mensagem, mas o parâmetro wParam geralmente é um valor de tipo que fornece mais informações sobre a mensagem.

Uma transmissão de mensagem é simplesmente o envio de uma mensagem para vários destinatários no sistema. Para transmitir uma mensagem de um aplicativo, use a função BroadcastSystemMessage , especificando os destinatários da mensagem. Em vez de especificar destinatários individuais, você deve especificar um ou mais tipos de destinatários. Esses tipos são aplicativos, drivers instaláveis, drivers de rede e drivers de dispositivo no nível do sistema. O sistema envia mensagens de transmissão para todos os membros de cada tipo especificado.

O sistema normalmente transmite mensagens em resposta a alterações que ocorrem em drivers de dispositivo no nível do sistema ou componentes relacionados. O driver ou componente relacionado transmite a mensagem para aplicativos e outros componentes para notificá-los sobre a alteração. Por exemplo, o componente responsável pelas unidades de disco transmite uma mensagem sempre que o driver do dispositivo para a unidade de disco disquete detecta uma alteração de mídia, como quando o usuário insere um disco na unidade.

O sistema transmite mensagens aos destinatários nesta ordem: drivers de dispositivo no nível do sistema, drivers de rede, drivers instaláveis e aplicativos. Isso significa que os drivers de dispositivo no nível do sistema, se escolhidos como destinatários, sempre têm a primeira oportunidade de responder a uma mensagem. Dentro de um determinado tipo de destinatário, nenhum driver tem a garantia de receber uma determinada mensagem antes de qualquer outro driver. Isso significa que uma mensagem destinada a um driver específico deve ter um identificador de mensagem global exclusivo para que nenhum outro driver a processe involuntariamente.

Você também pode transmitir mensagens para todas as janelas de nível superior especificando HWND_BROADCAST na função SendMessage, SendMessageCallback, SendMessageTimeout ou SendNotifyMessage .

Os aplicativos recebem mensagens por meio do procedimento de janela de suas janelas de nível superior. As mensagens não são enviadas para janelas filho. Os serviços podem receber mensagens por meio de um procedimento de janela ou seus manipuladores de controle de serviço.

Observação

Os drivers de dispositivo no nível do sistema usam uma função relacionada no nível do sistema para transmitir mensagens do sistema.

Mensagens de consulta

Você pode criar suas próprias mensagens personalizadas e usá-las para coordenar atividades entre seus aplicativos e outros componentes no sistema. Isso é especialmente útil se você tiver criado seus próprios drivers instaláveis ou drivers de dispositivo no nível do sistema. Suas mensagens personalizadas podem transportar informações de e para o driver e os aplicativos que usam o driver.

Para sondar os destinatários para obter permissão para executar uma determinada ação, use uma mensagem de consulta. Você pode gerar suas próprias mensagens de consulta definindo o valor BSF_QUERY no parâmetro dwFlags ao chamar BroadcastSystemMessage. Cada destinatário da mensagem de consulta deve retornar TRUE para que a função envie a mensagem para o próximo destinatário. Se algum destinatário retornar BROADCAST_QUERY_DENY, a transmissão terminará imediatamente e a função retornará um zero.