Acerca de los procedimientos de ventana

Cada ventana es miembro de una clase de ventana determinada. La clase de ventana determina el procedimiento de ventana predeterminado que usa una ventana individual para procesar sus mensajes. Todas las ventanas que pertenecen a la misma clase usan el mismo procedimiento de ventana predeterminado. Por ejemplo, el sistema define un procedimiento de ventana para la clase de cuadro combinado (COMBOBOX); todos los cuadros combinados usan ese procedimiento de ventana.

Normalmente, una aplicación registra al menos una nueva clase de ventana y su procedimiento de ventana asociado. Después de registrar una clase, la aplicación puede crear muchas ventanas de esa clase, todas las cuales usan el mismo procedimiento de ventana. Dado que esto significa que varios orígenes podrían llamar simultáneamente al mismo fragmento de código, debe tener cuidado al modificar los recursos compartidos desde un procedimiento de ventana. Para más información, consulte Winnt.

Los procedimientos de ventana para los cuadros de diálogo (denominados procedimientos de cuadro de diálogo) tienen una estructura similar y funcionan como procedimientos de ventana normales. Todos los puntos que hacen referencia a los procedimientos de ventana de esta sección también se aplican a los procedimientos del cuadro de diálogo. Para obtener más información, consulte Cuadros de diálogo.

En esta sección se describen los temas siguientes:

Estructura de un procedimiento de ventana

Un procedimiento de ventana es una función que tiene cuatro parámetros y devuelve un valor firmado. Los parámetros constan de un identificador de ventana, un identificador de mensaje UINT y dos parámetros de mensaje declarados con los tipos de datos WPARAM y LPARAM. Para más información, consulte WindowProc.

Los parámetros de mensaje suelen contener información en sus palabras de orden bajo y de orden alto. Hay varias macros que una aplicación puede usar para extraer información de los parámetros del mensaje. La macroLOWORD, por ejemplo, extrae la palabra de orden bajo (bits de 0 a 15) de un parámetro de mensaje. Otras macros incluyen HIWORD, LOBYTEy MACRO HIBYTE.

La interpretación del valor devuelto depende del mensaje concreto. Consulte la descripción de cada mensaje para determinar el valor devuelto adecuado.

Dado que es posible llamar a un procedimiento de ventana de forma recursiva, es importante minimizar el número de variables locales que usa. Al procesar mensajes individuales, una aplicación debe llamar a funciones fuera del procedimiento de ventana para evitar el uso excesivo de variables locales, lo que puede provocar que la pila se desborde durante la recursividad profunda.

Procedimiento de ventana predeterminado

La función de procedimiento de ventana predeterminada, DefWindowProcdefine cierto comportamiento fundamental compartido por todas las ventanas. El procedimiento de ventana predeterminado proporciona la funcionalidad mínima para una ventana. Un procedimiento de ventana definido por la aplicación debe pasar los mensajes que no procese a la función DefWindowProc para el procesamiento predeterminado.

Subclases de procedimiento de ventana

Cuando una aplicación crea una ventana, el sistema asigna un bloque de memoria para almacenar información específica de la ventana, incluida la dirección del procedimiento de ventana que procesa los mensajes de la ventana. Cuando el sistema necesita pasar un mensaje a la ventana, busca la información específica de la ventana para la dirección del procedimiento de ventana y pasa el mensaje a ese procedimiento.

La subclasificación es una técnica que permite a una aplicación interceptar y procesar mensajes enviados o publicados en una ventana determinada antes de que la ventana tenga la oportunidad de procesarlos. Al subclasar una ventana, una aplicación puede aumentar, modificar o supervisar el comportamiento de la ventana. Una aplicación puede subclase una ventana que pertenezca a una clase global del sistema, como un control de edición o un cuadro de lista. Por ejemplo, una aplicación podría subclase un control de edición para evitar que el control acepte determinados caracteres. Sin embargo, no se puede subclase una ventana o clase que pertenezca a otra aplicación. Todas las subclases deben realizarse dentro del mismo proceso.

Una aplicación subclase una ventana reemplazando la dirección del procedimiento de ventana original de la ventana por la dirección de un nuevo procedimiento de ventana, llamado procedimiento de subclase. Después, el procedimiento de subclase recibe los mensajes enviados o publicados en la ventana.

El procedimiento de subclase puede realizar tres acciones al recibir un mensaje: puede pasar el mensaje al procedimiento de ventana original, modificar el mensaje y pasarlo al procedimiento de ventana original, o procesar el mensaje y no pasarlo al procedimiento de ventana original. Si el procedimiento de subclase procesa un mensaje, puede hacerlo antes, después o tanto antes como después de pasar el mensaje al procedimiento de ventana original.

El sistema proporciona dos tipos de subclases: instancia y global. En las subclases de instancia, una aplicación reemplaza la dirección del procedimiento de ventana de una sola instancia de una ventana. Una aplicación debe usar subclases de instancia para subclasar una ventana existente. En la subclase global, una aplicación reemplaza la dirección del procedimiento de ventana en la estructura WNDCLASSEX de una clase de ventana. Todas las ventanas posteriores creadas con la clase tienen la dirección del procedimiento de subclase, pero las ventanas existentes de la clase no se ven afectadas.

Subclases de instancia

Una aplicación crea subclases de una instancia de una ventana mediante la función SetWindowLongPtr. La aplicación transfiere la marca GWL_WNDPROC, el identificador de la ventana a la subclase y la dirección del procedimiento de subclase a SetWindowLongPtr. El procedimiento de subclase puede residir en el archivo ejecutable de la aplicación o en un archivo DLL.

Cuando se transfiere la marca GWL_WNDPROC, SetWindowLongPtr devuelve la dirección del procedimiento de ventana original de la ventana. La aplicación debe guardar esta dirección y usarla en llamadas posteriores a la función CallWindowProc para transferir los mensajes interceptados al procedimiento de ventana original. La aplicación también debe tener la dirección del procedimiento de ventana original para quitar la subclase de la ventana. Para quitar la subclase, la aplicación vuelve a llamar a SetWindowLongPtr y transfiere la dirección del procedimiento de ventana original con la marca GWL_WNDPROC y el identificador a la ventana.

El sistema posee las clases globales del sistema y los aspectos de los controles pueden cambiar de una versión del sistema a la siguiente. Si la aplicación debe subclase una ventana que pertenezca a una clase global del sistema, es posible que el desarrollador tenga que actualizar la aplicación cuando se publique una nueva versión del sistema.

Dado que la subclasificación de instancia se produce después de crear una ventana, no se pueden agregar bytes adicionales a la ventana. Las aplicaciones que subclasen una ventana deberían usar la lista de propiedades de la ventana para almacenar cualquier dato necesario para una instancia de la ventana de la subclase. Para obtener más información, consulte Propiedades de ventana.

Cuando una aplicación realiza una subclase de una ventana con subclases, debe eliminar las subclases en el orden inverso al que se realizaron. Si el orden de eliminación no se invierte, puede producirse un error irrecuperable del sistema.

Subclases globales

Para subclase globalmente una clase de ventana, la aplicación debe tener un identificador para una ventana de la clase. La aplicación también necesita el identificador para quitar la subclase. Para obtener el identificador, una aplicación normalmente crea una ventana oculta de la clase que se va a subclasar. Después de obtener el identificador, la aplicación llama a la función SetClassLongPtr, especificando el identificador, la marca GCL_WNDPROC y la dirección del procedimiento de subclase. SetClassLongPtr devuelve la dirección del procedimiento de ventana original para la clase.

La dirección del procedimiento de ventana original se usa en subclases globales de la misma manera que se usa en subclases de instancia. El procedimiento de subclase pasa mensajes al procedimiento de ventana original llamando a CallWindowProc. La aplicación quita la subclase de la clase de ventana llamando de nuevo a SetClassLongPtr, especificando la dirección del procedimiento de ventana original, la marca GCL_WNDPROC y el identificador de una ventana de la clase que se va a subclasificar. Una aplicación que subclase globalmente una clase de control debe eliminar la subclase cuando la aplicación termine; en caso contrario, puede producirse un error irrecuperable del sistema.

Las subclases globales tienen las mismas limitaciones que las subclases de instancia, además de algunas restricciones adicionales. Una aplicación no debe usar los bytes adicionales para la clase o la instancia de ventana sin saber exactamente cómo los usa el procedimiento de ventana original. Si la aplicación debe asociar datos a una ventana, debe usar las propiedades de la ventana.

Superclase de procedimiento de ventana

Superclase es una técnica que permite a una aplicación crear una nueva clase de ventana con la funcionalidad básica de la clase existente, además de mejoras proporcionadas por la aplicación. Una superclase se basa en una clase de ventana existente denominada clase base. Con frecuencia, la clase base es una clase de ventana global del sistema, como un control de edición, pero puede ser cualquier clase de ventana.

Una superclase tiene su propio procedimiento de ventana, denominado procedimiento superclase. El procedimiento de superclase puede realizar tres acciones al recibir un mensaje: puede pasar el mensaje al procedimiento de ventana original, modificar el mensaje y pasarlo al procedimiento de ventana original, o procesar el mensaje y no pasarlo al procedimiento de ventana original. Si el procedimiento de superclase procesa un mensaje, puede hacerlo antes, después o tanto antes como después de pasar el mensaje al procedimiento de ventana original.

A diferencia de un procedimiento de subclase, un procedimiento de superclase puede procesar mensajes de creación de ventanas (WM_NCCREATE, WM_CREATE, etc.), pero también debe pasarlos al procedimiento de ventana de clase base original para que el procedimiento de ventana de clase base pueda realizar su procedimiento de inicialización.

Para superclasificar una clase de ventana, una aplicación llama primero a la función GetClassInfoEx para recuperar información sobre la clase base. GetClassInfoEx rellena una estructura WNDCLASSEX con los valores de la estructura WNDCLASSEX de la clase base. A continuación, la aplicación copia su propio identificador de instancia en el miembro hInstance de la estructura WNDCLASSEX y copia el nombre de la superclase en el miembro lpszClassName. Si la clase base tiene un menú, la aplicación debe proporcionar un nuevo menú con los mismos identificadores de menú y copiar el nombre del menú en el miembrolpszMenuName. Si el procedimiento superclase procesa el mensaje WM_COMMAND y no lo pasa al procedimiento de ventana de la clase base, el menú no necesita tener identificadores correspondientes. GetClassInfoEx no devuelve el miembro lpszMenuName, lpszClassName o hInstance de la estructura WNDCLASSEX.

Una aplicación también debe establecer el miembro lpfnWndProc de la estructura WNDCLASSEX. La función GetClassInfoEx rellena este miembro con la dirección del procedimiento de ventana original de la clase. La aplicación debe guardar esta dirección para pasar mensajes al procedimiento de ventana original y a continuación, copiar la dirección del procedimiento superclase en el miembro lpfnWndProc. La aplicación puede, si es necesario, modificar cualquier otro miembro de la estructura WNDCLASSEX. Una vez que rellena la estructura WNDCLASSEX, la aplicación registra la superclase transfiriendo la dirección de la estructura a la función RegisterClassEx. A continuación, se puede usar la superclase para crear ventanas.

Dado que el superclase registra una nueva clase de ventana, una aplicación puede agregar tanto a los bytes de clase adicionales como a los bytes de ventana adicionales. La superclase no debe usar los bytes adicionales originales para la clase base o la ventana por las mismas razones por las que una subclase de instancia o una subclase global no deben usarlas. Además, si la aplicación agrega bytes adicionales para su uso a la clase o a la instancia de ventana, debe hacer referencia a los bytes adicionales en relación con el número de bytes adicionales utilizados por la clase base original. Dado que el número de bytes usados por la clase base puede variar de una versión de la clase base a la siguiente, el desplazamiento inicial de los bytes adicionales de la superclase también puede variar de una versión de la clase base a la siguiente.