Partilhar via


Sobre os procedimentos de janela

Cada janela é um membro de uma classe de janela específica. A classe de janela determina o procedimento de janela padrão que uma janela individual usa para processar suas mensagens. Todas as janelas pertencentes à mesma classe usam o mesmo procedimento de janela padrão. Por exemplo, o sistema define um procedimento de janela para a classe da caixa de combinação (COMBOBOBOX); todas as caixas de combinação usam esse procedimento de janela.

Normalmente, um aplicativo registra pelo menos uma nova classe de janela e seu procedimento de janela associado. Depois de registrar uma classe, o aplicativo pode criar muitas janelas dessa classe, todas elas usando o mesmo procedimento de janela. Como isso significa que várias fontes podem chamar simultaneamente o mesmo trecho de código, é preciso ter cuidado ao modificar os recursos compartilhados de um procedimento de janela. Para obter mais informações, confira Classes de janela.

Os procedimentos de janela para caixas de diálogo (chamados de procedimentos de caixa de diálogo) têm estrutura e função semelhantes às dos procedimentos de janela comuns. Todos os pontos referentes aos procedimentos de janela nesta seção também se aplicam aos procedimentos de caixa de diálogo. Para obter mais informações, confira Caixas de diálogo.

Esta seção aborda os seguintes tópicos.

Estrutura de um procedimento de janela

Um procedimento de janela é uma função que tem quatro parâmetros e retorna um valor assinado. Os parâmetros consistem em um identificador de janela, um identificador de mensagem UINT e dois parâmetros de mensagem declarados com os tipos de dados WPARAM e LPARAM. Para obter mais informações, confira WindowProc.

Os parâmetros de mensagem geralmente contêm informações em suas palavras de ordem baixa e alta. Há várias macros que um aplicativo pode usar para extrair informações dos parâmetros da mensagem. A macro LOWORD, por exemplo, extrai a palavra de ordem inferior (bits 0 a 15) de um parâmetro de mensagem. Outras macros incluem HIWORD, LOBYTE e HIBYTE macro.

A interpretação do valor retornado depende da mensagem específica. Consulte a descrição de cada mensagem para determinar o valor retornado apropriado.

Como é possível chamar um procedimento de janela recursivamente, é importante minimizar o número de variáveis locais que ele usa. Ao processar mensagens individuais, um aplicativo deve chamar funções fora do procedimento da janela para evitar o uso excessivo de variáveis locais, o que pode causar o estouro da pilha durante a recursão profunda.

Procedimento de janela padrão

A função padrão de procedimento da janela, DefWindowProc, define determinados comportamentos fundamentais compartilhados por todas as janelas. O procedimento da janela padrão fornece a funcionalidade mínima para uma janela. Um procedimento de janela definido pelo aplicativo deve passar todas as mensagens que não forem processadas para a função DefWindowProc para o processamento padrão.

Subclassificação de Procedimentos de Janela

Quando um aplicativo cria uma janela, o sistema aloca um bloco de memória para armazenar informações específicas da janela, incluindo o endereço do procedimento de janela que processa as mensagens da janela. Quando o sistema precisa passar uma mensagem para a janela, ele pesquisa nas informações específicas da janela o endereço do procedimento da janela e passa a mensagem para esse procedimento.

Subclassificação é uma técnica que permite que um aplicativo intercepte e processe mensagens enviadas ou postadas em uma determinada janela antes que a janela tenha a chance de processá-las. Ao criar uma subclassificação de uma janela, um aplicativo pode aumentar, modificar ou monitorar o comportamento da janela. Um aplicativo pode criar uma subclasse de uma janela pertencente a uma classe global do sistema, como um controle de edição ou uma caixa de listagem. Por exemplo, um aplicativo pode criar uma subclasse de um controle de edição para impedir que o controle aceite determinados caracteres. No entanto, você não pode criar uma subclasse de uma janela ou classe que pertença a outro aplicativo. Todas as subclassificações devem ser executadas no mesmo processo.

Um aplicativo cria a subclasse de uma janela substituindo o endereço do procedimento original da janela pelo endereço de um novo procedimento de janela, chamado de procedimento de subclasse. Depois disso, o procedimento de subclasse recebe todas as mensagens enviadas ou postadas na janela.

O procedimento de subclasse pode executar três ações ao receber uma mensagem: pode passar a mensagem para o procedimento de janela original, modificar a mensagem e passá-la para o procedimento de janela original ou processar a mensagem e não passá-la para o procedimento de janela original. Se o procedimento de subclasse processar uma mensagem, ele poderá fazê-lo antes, depois ou antes e depois de passar a mensagem para o procedimento de janela original.

O sistema oferece dois tipos de subclassificação: instância e global. Em subclassificação da instância, um aplicativo substitui o endereço do procedimento de janela de uma única instância de uma janela. Um aplicativo deve usar a subclassificação da instância para subclassificar uma janela existente. Na subclassificação global, um aplicativo substitui o endereço do procedimento de janela na estrutura WNDCLASSEX de uma classe de janela. Todas as janelas subsequentes criadas com a classe têm o endereço do procedimento de subclasse, mas as janelas existentes da classe não são afetadas.

Subclasse da Instância

Um aplicativo subclasse uma instância de uma janela usando a função SetWindowLongPtr. O aplicativo passa o sinalizador GWL_WNDPROC, o identificador para a janela para subclasse e o endereço do procedimento de subclasse para SetWindowLongPtr. O procedimento de subclasse pode residir no executável do aplicativo ou em uma DLL.

Quando passado o sinalizador GWL_WNDPROC, SetWindowLongPtr retorna o endereço do procedimento de janela original da janela. O aplicativo deve salvar esse endereço, usando-o em chamadas subsequentes para a função CallWindowProc , para passar mensagens interceptadas para o procedimento de janela original. O aplicativo também deve ter o endereço original do procedimento da janela para remover a subclasse da janela. Para remover a subclasse, o aplicativo chama SetWindowLongPtr novamente, passando o endereço do procedimento de janela original com o sinalizador GWL_WNDPROC e o identificador para a janela.

O sistema possui as classes globais do sistema, e os aspectos dos controles podem serv alterados de uma versão do sistema para outra. Se o aplicativo precisar criar uma subclasse de uma janela que pertença a uma classe global do sistema, o desenvolvedor talvez precise atualizar o aplicativo quando uma nova versão do sistema for lançada.

Como a subclassificação de instância ocorre depois que uma janela é criada, você não pode adicionar bytes extras à janela. Os aplicativos que criam subclasses de uma janela devem usar a lista de propriedades da janela para armazenar todos os dados necessários para uma instância da janela de subclasse. Para obter mais informações, confira Propriedades da janela.

Quando um aplicativo cria subclasses de uma janela de subclasse, ele deve remover as subclasses na ordem inversa em que foram executadas. Se a ordem de remoção não for revertida, poderá ocorrer um erro irrecuperável do sistema.

Subclassificação Global

Para criar uma subclasse global de uma classe de janela, o aplicativo deve ter um identificador para uma janela de classe. O aplicativo também precisa do identificador para remover a subclasse. Para obter o identificador, um aplicativo normalmente cria uma janela oculta da classe a ser subclassificada. Depois de obter o identificador, o aplicativo chama a função SetClassLongPtr, especificando o identificador, o sinalizador de GCL_WNDPROC e o endereço do procedimento de subclasse. SetClassLongPtr retorna o endereço do procedimento de janela original para a classe.

O endereço original do procedimento da janela é utilizado na subclassificação global da mesma forma que é utilizado na subclassificação de instâncias. O procedimento da subclasse passa mensagens para o procedimento da janela original chamando CallWindowProc. O aplicativo remove a subclasse da classe de janela chamando SetClassLongPtr novamente, especificando o endereço do procedimento de janela original, o sinalizador de GCL_WNDPROC e o identificador para uma janela da classe que está sendo subclassificada. Um aplicativo que cria a subclasse global de uma classe de controle deve remover a subclasse quando o aplicativo for encerrado; caso contrário, poderá ocorrer um erro irrecuperável do sistema.

A subclassificação global tem as mesmas limitações da subclasse de instância, além de algumas restrições adicionais. Um aplicativo não deve usar os bytes extras para a classe ou para a instância da janela sem saber exatamente como o procedimento original da janela os utiliza. Se o aplicativo precisar associar dados a uma janela, ele deverá usar as propriedades da janela.

Superclassificação de Procedimentos de Janela

Superclassificação é uma técnica que permite que um aplicativo crie uma nova classe de janela com a funcionalidade básica da classe existente, além dos aprimoramentos fornecidos pelo aplicativo. Uma superclasse é baseada em uma classe de janela existente chamada classe base. Frequentemente, a classe base é uma classe de janela global do sistema, como um controle de edição, mas pode ser qualquer classe de janela.

Uma superclasse tem seu próprio procedimento de janela, chamado de procedimento de superclasse. O procedimento de superclasse pode executar três ações ao receber uma mensagem: ele pode passar a mensagem para o procedimento de janela original, modificar a mensagem e passá-la para o procedimento de janela original ou processar a mensagem e não passá-la para o procedimento de janela original. Se o procedimento da superclasse processar uma mensagem, ele poderá fazê-lo antes, depois ou antes e depois de passar a mensagem para o procedimento da janela original.

Ao contrário de um procedimento de subclasse, um procedimento de superclasse pode processar mensagens de criação de janela (WM_NCCREATE, WM_CREATE e assim por diante), mas também deve passá-las para o procedimento de janela de classe base original para que o procedimento de janela de classe base possa executar seu procedimento de inicialização.

Para superclassificar uma classe de janela, um aplicativo primeiro chama a função GetClassInfoEx para recuperar informações sobre a classe base. GetClassInfoEx preenche uma estrutura WNDCLASSEX com os valores da estrutura WNDCLASSEX da classe base. Em seguida, o aplicativo copia seu próprio identificador de instância para o membro hInstance da estrutura WNDCLASSEX e copia o nome da superclasse para o membro lpszClassName. Se a classe base tiver um menu, o aplicativo deverá fornecer um novo menu com os mesmos identificadores de menu e copiar o nome do menu no membro lpszMenuName. Se o procedimento da superclasse processar a mensagem WM_COMMAND e não a passar para o procedimento de janela da classe base, o menu não precisará ter os identificadores correspondentes. GetClassInfoEx não retorna o lpszMenuName, lpszClassName ou hInstance membro da estrutura WNDCLASSOX.

Um aplicativo também deve definir o membro lpfnWndProc da estrutura WNDCLASSEX . A função GetClassInfoEx preenche esse membro com o endereço do procedimento de janela original para a classe. O aplicativo deve salvar esse endereço para passar mensagens para o procedimento original da janela e, em seguida, copiar o endereço do procedimento da superclasse para o membro lpfnWndProc. O aplicativo pode, se necessário, modificar quaisquer outros membros da estrutura WNDCLASSEX . Depois de preencher a estrutura WNDCLASSEX, o aplicativo registra a superclasse passando o endereço da estrutura para a função RegisterClassEx. A superclasse pode então ser usada para criar janelas.

Como a superclassificação registra uma nova classe de janela, um aplicativo pode adicionar bytes extras de classe e bytes extras de janela. A superclasse não deve usar os bytes extras originais para a classe base ou a janela pelos mesmos motivos que uma subclasse de instância ou uma subclasse global não deve usá-los. Além disso, se o aplicativo adicionar bytes extras para seu uso na classe ou na instância da janela, ele deverá fazer referência aos bytes extras em relação ao número de bytes extras utilizados pela classe base original. Como o número de bytes utilizados pela classe base pode variar de uma versão para outra da classe base, o deslocamento inicial para os bytes extras da própria superclasse também pode variar de uma versão para outra da classe base.