Acerca de los procedimientos de ventana
Cada ventana es miembro de una clase de ventana determinada. La clase window 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 obtener más información, vea Clases de ventana.
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, vea Cuadros de diálogo.
En esta sección se describen los temas siguientes.
- Estructura de un procedimiento de ventana
- Procedimiento de ventana predeterminado
- Subclases de procedimiento de ventana
- Superclase de procedimiento de ventana
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 obtener más información, vea 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 macro LOWORD , por ejemplo, extrae la palabra de orden bajo (bits de 0 a 15) de un parámetro de mensaje. Otras macros incluyen HIWORD, LOBYTE y 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, DefWindowProc define 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 su 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 en la información específica de la ventana la dirección del procedimiento de ventana y pasa el mensaje a ese procedimiento.
La subclase 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 subclase de 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, denominado 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 ambos antes y 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 subclase una ventana existente. En la subclase global, una aplicación reemplaza la dirección del procedimiento de ventana en la estructura WNDCLASS 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 subclases una instancia de una ventana mediante la función SetWindowLong . La aplicación pasa la marca GWL_WNDPROC , el identificador a la ventana a la subclase y la dirección del procedimiento de subclase a SetWindowLong. El procedimiento de subclase puede residir en el ejecutable de la aplicación o en un archivo DLL.
SetWindowLong devuelve la dirección del procedimiento de ventana original de la ventana. La aplicación debe guardar la dirección, usándola en llamadas posteriores a la función CallWindowProc , para pasar 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 llama a SetWindowLong de nuevo, pasando 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 subclases de instancia se produce después de crear una ventana, no se pueden agregar bytes adicionales a la ventana. Las aplicaciones que subclase una ventana deben usar la lista de propiedades de la ventana para almacenar los datos necesarios para una instancia de la ventana con subclases. Para obtener más información, vea Propiedades de la ventana.
Cuando una aplicación subclase una ventana con subclases, debe quitar las subclases en el orden inverso en que se realizaron. Si no se invierte el orden de eliminación, 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 SetClassLong , especificando el identificador, la marca GCL_WNDPROC y la dirección del procedimiento de subclase. SetClassLong devuelve la dirección del procedimiento de ventana original de la clase .
La dirección del procedimiento de ventana original se usa en las subclases globales de la misma manera que se usa en las 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 a SetClassLong de nuevo, especificando la dirección del procedimiento de ventana original, la marca GCL_WNDPROC y el identificador a una ventana de la clase que se está subclasizando. Una aplicación que subclase globalmente una clase de control debe quitar la subclase cuando finaliza la aplicación; De lo 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
La 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 de 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 ambos antes y 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 superclase una clase de ventana, una aplicación llama primero a la función GetClassInfo para recuperar información sobre la clase base. GetClassInfo rellena una estructura WNDCLASS con los valores de la estructura WNDCLASS de la clase base. A continuación, la aplicación copia su propio identificador de instancia en el miembro hInstance de la estructura WNDCLASS 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 miembro lpszMenuName . Si el procedimiento de superclase procesa el mensaje de WM_COMMAND y no lo pasa al procedimiento de ventana de la clase base, el menú no necesita tener identificadores correspondientes. GetClassInfo no devuelve el miembro lpszMenuName, lpszClassName ni hInstance de la estructura WNDCLASS .
Una aplicación también debe establecer el miembro lpfnWndProc de la estructura WNDCLASS . La función GetClassInfo 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 de superclase en el miembro lpfnWndProc . La aplicación puede, si es necesario, modificar cualquier otro miembro de la estructura WNDCLASS . Después de rellenar la estructura WNDCLASS , la aplicación registra la superclase pasando la dirección de la estructura a la función RegisterClass . A continuación, la superclase se puede usar para crear ventanas.
Dado que la 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 los mismos motivos por los 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 relativos al 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.