Compartilhar 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 de caixa de combinação (COMBOBOX); em seguida, todas as caixas de combinação usam esse procedimento de janela.

Um aplicativo normalmente 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 as quais usam o mesmo procedimento de janela. Como isso significa que várias fontes podem chamar simultaneamente o mesmo código, você deve ter cuidado ao modificar 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 procedimentos de caixa de diálogo) têm uma estrutura e função semelhantes aos procedimentos de janela regulares. Todos os pontos referentes aos procedimentos de janela nesta seção também se aplicam a procedimentos de caixa de diálogo. Para obter mais informações, consulte Caixas de diálogo.

Esta seção discute os tópicos a seguir.

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, consulte 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 de mensagem. A macro LOWORD , por exemplo, extrai a palavra de ordem baixa (bits 0 a 15) de um parâmetro de mensagem. Outras macros incluem HIWORD, LOBYTE e macro HIBYTE.

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 de procedimento de janela padrão, DefWindowProc , define determinado comportamento fundamental compartilhado por todas as janelas. O procedimento de janela padrão fornece a funcionalidade mínima para uma janela. Um procedimento de janela definido pelo aplicativo deve passar mensagens que ele não processa para a função DefWindowProc para 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 para a janela, incluindo o endereço do procedimento de janela que processa mensagens para a janela. Quando o sistema precisa passar uma mensagem para a janela, ele pesquisa as informações específicas da janela para encontrar o endereço do procedimento e passa a mensagem para esse procedimento.

Subclasseamento é uma técnica que permite que um aplicativo intercepte e processe mensagens enviadas ou postadas em uma janela específica antes que a janela tenha a chance de processá-las. Ao subclassificar uma janela, um aplicativo pode aumentar, modificar ou monitorar o comportamento da janela. Um aplicativo pode subclasse 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 subclasse um controle de edição para impedir que o controle aceite determinados caracteres. No entanto, você não pode subclasse uma janela ou classe que pertença a outro aplicativo. Todas as subclassificações devem ser realizadas no mesmo processo.

Um aplicativo subclassifica uma janela substituindo o endereço do procedimento de janela original pelo endereço de um novo procedimento de janela, chamado 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: 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 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 fornece dois tipos de subclasse: instância e global. Em subclassificação de instâncias, um aplicativo substitui o endereço do procedimento de janela de uma única instância de uma janela. Um aplicativo deve usar subclassificação de instância para subclassificar uma janela existente. Na subclassificação global, um aplicativo substitui o endereço do procedimento da 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.

Subclassificação de instâncias

Um aplicativo cria uma subclasse de uma instância de uma janela usando a função SetWindowLongPtr. O aplicativo transmite o sinalizador GWL_WNDPROC, o identificador da janela a ser subclassificada 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 o sinalizador GWL_WNDPROC é transmitido, SetWindowLongPtr exibe o endereço do procedimento 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 de procedimento da janela original para remover a subclasse da janela. Para remover a subclasse, o aplicativo chama SetWindowLongPtr novamente, transmitindo 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 mudar de uma versão do sistema para a próxima. Se o aplicativo precisar subclasse uma janela que pertença a uma classe global do sistema, talvez o desenvolvedor precise atualizar o aplicativo quando uma nova versão do sistema for lançada.

Como a subclasse de instância ocorre depois que uma janela é criada, você não pode adicionar bytes extras à janela. Os aplicativos que subclassem uma janela devem usar a lista de propriedades da janela para armazenar os dados necessários para uma instância da janela subclasse. Para obter mais informações, consulte 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 subclassificar globalmente uma classe de janela, o aplicativo deve ter um identificador para uma janela dessa 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 GCL_WNDPROC e o endereço do procedimento de subclasse. SetClassLongPtr retorna o endereço do procedimento de janela original da 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 de subclasse passa mensagens para o procedimento de 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 GCL_WNDPROC e o identificador de uma janela da classe que está sendo subclassificada. Um aplicativo que subclasse globalmente uma classe de controle deve remover a subclasse quando o aplicativo for encerrado; caso contrário, pode ocorrer um erro irrecuperável do sistema.

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

Superclassificação de Procedimentos de Janela

A superclasse é uma técnica que permite que um aplicativo crie uma nova classe de janela com a funcionalidade básica da classe existente, além de 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 superclasse 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 para o membro lpszMenuName . Se o procedimento de 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 identificadores correspondentes. GetClassInfoEx não retorna o membro lpszMenuName, lpszClassName ou hInstance da estrutura WNDCLASSEX .

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 da classe. O aplicativo deve salvar esse endereço para passar mensagens para o procedimento de janela original, e depois copiar o endereço do procedimento de superclasse para o membro lpfnWndProc. O aplicativo pode, se necessário, modificar outros membros da estrutura WNDCLASSEX . Depois de preencher a estrutura WNDCLASSEX , o aplicativo registrará a superclasse passando o endereço da estrutura para a função RegisterClassEx . A superclasse pode 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 pelos quais uma subclasse de instância ou uma subclasse global não devem usá-los. Além disso, se o aplicativo adicionar bytes extras para seu uso à classe ou à instância da janela, ele deverá referenciar os bytes extras relativos ao número de bytes extras usados pela classe base original. Como o número de bytes usados pela classe base pode variar de uma versão da classe base para a próxima, o deslocamento inicial para os bytes extras da superclasse também pode variar de uma versão da classe base para a próxima.