Acerca de las clases de ventana

Cada clase de ventana tiene un procedimiento de ventana asociado compartido por todas las ventanas de la misma clase. El procedimiento de ventana procesa mensajes para todas las ventanas de esa clase y, por tanto, controla su comportamiento y apariencia. Para más información, vea Procedimientos de ventanas.

Un proceso debe registrar una clase de ventana para poder crear una ventana de esa clase. El registro de una clase de ventana asocia un procedimiento de ventana, estilos de clase y otros atributos de clase con un nombre de clase. Cuando un proceso especifica un nombre de clase en la función CreateWindow o CreateWindowEx , el sistema crea una ventana con el procedimiento de ventana, los estilos y otros atributos asociados a ese nombre de clase.

En esta sección se describen los temas siguientes.

Tipos de clases de ventana

Hay tres tipos de clases de ventana:

Estos tipos difieren en el ámbito y en cuándo y cómo se registran y destruyen.

Clases del sistema

Una clase del sistema es una clase de ventana registrada por el sistema. Muchas clases del sistema están disponibles para todos los procesos que se van a usar, mientras que otras solo las usa internamente el sistema. Dado que el sistema registra estas clases, un proceso no puede destruirlas.

El sistema registra las clases del sistema para un proceso la primera vez que uno de sus subprocesos llama a una función User o Windows Graphics Device Interface (GDI).

Cada aplicación recibe su propia copia de las clases del sistema. Todas las aplicaciones basadas en Windows de 16 bits en las mismas clases del sistema de VDM comparten, igual que en Windows de 16 bits.

En la tabla siguiente se describen las clases del sistema que están disponibles para su uso por todos los procesos.

Clase Descripción
Botón Clase para un botón.
ComboBox Clase para un cuadro combinado.
Editar Clase para un control de edición.
ListBox Clase de un cuadro de lista.
MDIClient Clase para una ventana de cliente MDI.
ScrollBar Clase para una barra de desplazamiento.
estática Clase para un control estático.

 

En la tabla siguiente se describen las clases del sistema que solo están disponibles para su uso por parte del sistema. Se enumeran aquí por motivos de integridad.

Clase Descripción
ComboLBox Clase para el cuadro de lista contenido en un cuadro combinado.
DDEMLEvent La clase para eventos de la Biblioteca de administración de Intercambio de datos dinámicos (DDEML).
Message Clase para una ventana de solo mensaje.
#32768 Clase para un menú.
#32769 Clase para la ventana de escritorio.
#32770 Clase de un cuadro de diálogo.
#32771 Clase para la ventana del modificador de tareas.
#32772 Clase para títulos de icono.

 

Clases globales de aplicaciones

Una clase global de aplicación es una clase de ventana registrada por un archivo ejecutable o DLL que está disponible para todos los demás módulos del proceso. Por ejemplo, el .dll puede llamar a la función RegisterClassEx para registrar una clase de ventana que define un control personalizado como una clase global de aplicación para que un proceso que cargue la .dll pueda crear instancias del control personalizado.

Para crear una clase que se pueda usar en cada proceso, cree la clase de ventana en un .dll y cargue el .dll en cada proceso. Para cargar el .dll en cada proceso, agregue su nombre al valor AppInit_DLLs en la siguiente clave del Registro:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Currentversion\Windows

Cada vez que se inicia un proceso, el sistema carga el .dll especificado en el contexto del proceso recién iniciado antes de llamar a su función de punto de entrada. El .dll debe registrar la clase durante su procedimiento de inicialización y debe especificar el estilo CS_GLOBALCLASS . Para obtener más información, vea Estilos de clase.

Para quitar una clase global de aplicación y liberar el almacenamiento asociado, use la función UnregisterClass .

Clases locales de aplicación

Una clase local de aplicación es cualquier clase de ventana que un archivo ejecutable o .dll registra para su uso exclusivo. Aunque puede registrar cualquier número de clases locales, es habitual registrar solo una. Esta clase de ventana admite el procedimiento de ventana de la ventana principal de la aplicación.

El sistema destruye una clase local cuando se cierra el módulo que registró. Una aplicación también puede usar la función UnregisterClass para quitar una clase local y liberarle el almacenamiento asociado.

Cómo el sistema localiza una clase window

El sistema mantiene una lista de estructuras para cada uno de los tres tipos de clases de ventana. Cuando una aplicación llama a la función CreateWindow o CreateWindowEx para crear una ventana con una clase especificada, el sistema usa el siguiente procedimiento para buscar la clase .

  1. Busque en la lista de clases locales de aplicación una clase con el nombre especificado cuyo identificador de instancia coincida con el identificador de instancia del módulo. (Varios módulos pueden usar el mismo nombre para registrar las clases locales en el mismo proceso).
  2. Si el nombre no está en la lista de clases locales de la aplicación, busque en la lista de clases globales de la aplicación.
  3. Si el nombre no está en la lista de clases globales de la aplicación, busque la lista de clases del sistema.

Todas las ventanas creadas por la aplicación usan este procedimiento, incluidas las ventanas creadas por el sistema en nombre de la aplicación, como los cuadros de diálogo. Es posible invalidar las clases del sistema sin afectar a otras aplicaciones. Es decir, una aplicación puede registrar una clase local de aplicación que tenga el mismo nombre que una clase del sistema. Esto reemplaza la clase del sistema en el contexto de la aplicación, pero no impide que otras aplicaciones usen la clase del sistema.

Registrar una clase window

Una clase de ventana define los atributos de una ventana, como su estilo, icono, cursor, menú y procedimiento de ventana. El primer paso para registrar una clase de ventana es rellenar una estructura WNDCLASSEX con la información de clase de ventana. Para obtener más información, vea Elementos de una clase Window. A continuación, pase la estructura a la función RegisterClassEx . Para obtener más información, vea Uso de clases de ventana.

Para registrar una clase global de aplicación, especifique el estilo CS_GLOBALCLASS en el miembro style de la estructura WNDCLASSEX . Al registrar una clase local de aplicación, no especifique el estilo CS_GLOBALCLASS .

Si registra la clase de ventana mediante la versión ANSI de RegisterClassEx, RegisterClassExA, la aplicación solicita que el sistema pase parámetros de texto de mensajes a las ventanas de la clase creada mediante el juego de caracteres ANSI; Si registra la clase mediante la versión Unicode de RegisterClassEx, RegisterClassExW, la aplicación solicita que el sistema pase parámetros de texto de mensajes a las ventanas de la clase creada mediante el juego de caracteres Unicode. La función IsWindowUnicode permite a las aplicaciones consultar la naturaleza de cada ventana. Para obtener más información sobre las funciones ANSI y Unicode, vea Convenciones para prototipos de función.

El archivo ejecutable o DLL que registró la clase es el propietario de la clase . El sistema determina la propiedad de clase del miembro hInstance de la estructura WNDCLASSEX que se pasa a la función RegisterClassEx cuando se registra la clase. Para los archivos DLL, el miembro hInstance debe ser el identificador de la instancia de .dll.

La clase no se destruye cuando se descarga el .dll que posee. Por lo tanto, si el sistema llama al procedimiento de ventana para una ventana de esa clase, provocará una infracción de acceso, ya que el .dll que contiene el procedimiento de ventana ya no está en memoria. El proceso debe destruir todas las ventanas que usan la clase antes de descargar el .dll y llamar a la función UnregisterClass .

Elementos de una clase Window

Los elementos de una clase de ventana definen el comportamiento predeterminado de las ventanas que pertenecen a la clase . La aplicación que registra una clase de ventana asigna elementos a la clase estableciendo los miembros adecuados en una estructura WNDCLASSEX y pasando la estructura a la función RegisterClassEx . Las funciones GetClassInfoEx y GetClassLong recuperan información sobre una clase de ventana determinada. La función SetClassLong cambia los elementos de una clase local o global que la aplicación ya ha registrado.

Aunque una clase de ventana completa consta de muchos elementos, el sistema solo requiere que una aplicación proporcione un nombre de clase, la dirección de procedimiento de ventana y un identificador de instancia. Use los demás elementos para definir atributos predeterminados para ventanas de la clase, como la forma del cursor y el contenido del menú de la ventana. Debe inicializar todos los miembros sin usar de la estructura WNDCLASSEX en cero o NULL. Los elementos de la clase window se muestran en la tabla siguiente.

Elemento Propósito
Nombre de la clase Distingue la clase de otras clases registradas.
Dirección del procedimiento de ventana Puntero a la función que procesa todos los mensajes enviados a ventanas de la clase y define el comportamiento de la ventana.
Identificador de instancia Identifica la aplicación o .dll que registró la clase .
Cursor de clase Define el cursor del mouse que el sistema muestra para una ventana de la clase .
Iconos de clase Define el icono grande y el icono pequeño.
Pincel de fondo de clase Define el color y el patrón que rellenan el área cliente cuando se abre o pinta la ventana.
Menú Clase Especifica el menú predeterminado para ventanas que no definen explícitamente un menú.
Estilos de clase Define cómo actualizar la ventana después de moverla o cambiar su tamaño, cómo procesar los doble clics del mouse, cómo asignar espacio para el contexto del dispositivo y otros aspectos de la ventana.
Memoria de clase adicional Especifica la cantidad de memoria adicional, en bytes, que el sistema debe reservar para la clase . Todas las ventanas de la clase comparten la memoria adicional y pueden usarla para cualquier propósito definido por la aplicación. El sistema inicializa esta memoria en cero.
Memoria de ventana adicional Especifica la cantidad de memoria adicional, en bytes, que el sistema debe reservar para cada ventana que pertenezca a la clase . La memoria adicional se puede usar para cualquier propósito definido por la aplicación. El sistema inicializa esta memoria en cero.

 

Class Name (Nombre de clase)

Cada clase de ventana necesita un nombre de clase para distinguir una clase de otra. Asigne un nombre de clase estableciendo el miembro lpszClassName de la estructura WNDCLASSEX en la dirección de una cadena terminada en null que especifica el nombre. Dado que las clases de ventana son específicas del proceso, los nombres de clase de ventana deben ser únicos solo dentro del mismo proceso. Además, dado que los nombres de clase ocupan espacio en la tabla atom privada del sistema, debe mantener las cadenas de nombre de clase lo más cortas posible.

La función GetClassName recupera el nombre de la clase a la que pertenece una ventana determinada.

Dirección del procedimiento de ventana

Cada clase necesita una dirección de procedimiento de ventana para definir el punto de entrada del procedimiento de ventana que se usa para procesar todos los mensajes de las ventanas de la clase . El sistema pasa mensajes al procedimiento cuando requiere que la ventana lleve a cabo tareas, como pintar su área cliente o responder a la entrada del usuario. Un proceso asigna un procedimiento de ventana a una clase copiando su dirección al miembro lpfnWndProc de la estructura WNDCLASSEX . Para más información, vea Procedimientos de ventanas.

Identificador de instancia

Cada clase de ventana requiere un identificador de instancia para identificar la aplicación o .dll que registró la clase. El sistema requiere identificadores de instancia para realizar un seguimiento de todos los módulos. El sistema asigna un identificador a cada copia de un ejecutable en ejecución o .dll.

El sistema pasa un identificador de instancia a la función de punto de entrada de cada archivo ejecutable (consulte WinMain) y .dll (consulte DllMain). El ejecutable o .dll asigna este identificador de instancia a la clase copiándolo al miembro hInstance de la estructura WNDCLASSEX .

Cursor de clase

El cursor de clase define la forma del cursor cuando está en el área cliente de una ventana de la clase . El sistema establece automáticamente el cursor en la forma especificada cuando el cursor entra en el área cliente de la ventana y garantiza que mantiene esa forma mientras permanece en el área cliente. Para asignar una forma de cursor a una clase de ventana, cargue una forma de cursor predefinida mediante la función LoadCursor y, a continuación, asigne el identificador de cursor devuelto al miembro hCursor de la estructura WNDCLASSEX . Como alternativa, proporcione un recurso de cursor personalizado y use la función LoadCursor para cargarlo desde los recursos de la aplicación.

El sistema no requiere un cursor de clase. Si una aplicación establece el miembro hCursor de la estructura WNDCLASSEX en NULL, no se define ningún cursor de clase. El sistema supone que la ventana establece la forma del cursor cada vez que el cursor se mueve a la ventana. Una ventana puede establecer la forma del cursor llamando a la función SetCursor cada vez que la ventana recibe el mensaje WM_MOUSEMOVE . Para obtener más información sobre los cursores, vea Cursores.

Iconos de clase

Un icono de clase es una imagen que el sistema usa para representar una ventana de una clase determinada. Una aplicación puede tener dos iconos de clase: uno grande y otro pequeño. El sistema muestra el icono de clase grande de una ventana en la ventana del conmutador de tareas que aparece cuando el usuario presiona ALT+TAB y, en las vistas de iconos grandes de la barra de tareas y el explorador. El icono de clase pequeña aparece en la barra de título de una ventana y en las vistas de icono pequeños de la barra de tareas y el explorador.

Para asignar un icono grande y pequeño a una clase de ventana, especifique los identificadores de los iconos de los miembros hIcon y hIconSm de la estructura WNDCLASSEX . Las dimensiones de icono deben ajustarse a las dimensiones necesarias para los iconos de clase grandes y pequeños. Para un icono de clase grande, puede determinar las dimensiones necesarias especificando los valores de SM_CXICON y SM_CYICON en una llamada a la función GetSystemMetrics . Para un icono de clase pequeña, especifique los valores de SM_CXSMICON y SM_CYSMICON . Para obtener información, vea Iconos.

Si una aplicación establece los miembros hIcon y hIconSm de la estructura WNDCLASSEX en NULL, el sistema usa el icono de aplicación predeterminado como iconos de clase grande y pequeño para la clase de ventana. Si especifica un icono de clase grande pero no uno pequeño, el sistema crea un icono de clase pequeño basado en el grande. Sin embargo, si especifica un icono de clase pequeño pero no uno grande, el sistema usa el icono de aplicación predeterminado como el icono de clase grande y el icono especificado como el icono de clase pequeña.

Puede invalidar el icono de clase grande o pequeña para una ventana determinada mediante el mensaje WM_SETICON . Puede recuperar el icono actual de clase grande o pequeña mediante el mensaje WM_GETICON .

Pincel de fondo de clase

Un pincel en segundo plano de clase prepara el área cliente de una ventana para el dibujo posterior de la aplicación. El sistema usa el pincel para rellenar el área de cliente con un color sólido o patrón, quitando así todas las imágenes anteriores de esa ubicación tanto si pertenecen a la ventana como si no. El sistema notifica a una ventana que debe pintarse su fondo enviando el mensaje WM_ERASEBKGND a la ventana. Para obtener más información, vea Pinceles.

Para asignar un pincel de fondo a una clase, cree un pincel mediante las funciones GDI adecuadas y asigne el identificador de pincel devuelto al miembro hbrBackground de la estructura WNDCLASSEX .

En lugar de crear un pincel, una aplicación puede establecer el miembro hbrBackground en uno de los valores de color del sistema estándar. Para obtener una lista de los valores de color del sistema estándar, vea SetSysColors.

Para usar un color del sistema estándar, la aplicación debe aumentar el valor de color de fondo en uno. Por ejemplo, COLOR_BACKGROUND + 1 es el color de fondo del sistema. Como alternativa, puede usar la función GetSysColorBrush para recuperar un identificador a un pincel que corresponda a un color del sistema estándar y, a continuación, especificar el identificador en el miembro hbrBackground de la estructura WNDCLASSEX .

El sistema no requiere que una clase de ventana tenga un pincel de fondo de clase. Si este parámetro se establece en NULL, la ventana debe pintar su propio fondo siempre que reciba el mensaje WM_ERASEBKGND .

Menú Clase

Un menú de clase define el menú predeterminado que usarán las ventanas de la clase si no se especifica ningún menú explícito cuando se crean las ventanas. Un menú es una lista de comandos desde los que un usuario puede elegir acciones para que la aplicación realice.

Puede asignar un menú a una clase estableciendo el miembro lpszMenuName de la estructura WNDCLASSEX en la dirección de una cadena terminada en null que especifica el nombre del recurso del menú. Se supone que el menú es un recurso de la aplicación especificada. El sistema carga automáticamente el menú cuando es necesario. Si el recurso de menú se identifica mediante un entero y no por un nombre, la aplicación puede establecer el miembro lpszMenuName en ese entero aplicando la macro MAKEINTRESOURCE antes de asignar el valor.

El sistema no requiere un menú de clase. Si una aplicación establece el miembro lpszMenuName de la estructura WNDCLASSEX en NULL, las ventanas de la clase no tienen barras de menú. Incluso si no se proporciona ningún menú de clase, una aplicación todavía puede definir una barra de menús para una ventana cuando crea la ventana.

Si se asigna un menú para una clase y se crea una ventana secundaria de esa clase, se omite el menú. Para obtener más información, vea Menús.

Estilos de clase

Los estilos de clase definen elementos adicionales de la clase window. Se pueden combinar dos o más estilos mediante el operador OR (|) bit a bit. Para asignar un estilo a una clase de ventana, asigne el estilo al miembro style de la estructura WNDCLASSEX . Para obtener una lista de estilos de clase, vea Estilos de clase de ventana.

Clases y contextos de dispositivo

Un contexto de dispositivo es un conjunto especial de valores que las aplicaciones usan para dibujar en el área cliente de sus ventanas. El sistema requiere un contexto de dispositivo para cada ventana de la pantalla, pero permite cierta flexibilidad en la forma en que el sistema almacena y trata ese contexto de dispositivo.

Si no se especifica explícitamente ningún estilo de contexto de dispositivo, el sistema asume que cada ventana usa un contexto de dispositivo recuperado de un grupo de contextos mantenidos por el sistema. En tales casos, cada ventana debe recuperar e inicializar el contexto del dispositivo antes de pintarlo y liberarlo después de pintar.

Para evitar recuperar un contexto de dispositivo cada vez que necesite pintar dentro de una ventana, una aplicación puede especificar el estilo CS_OWNDC para la clase de ventana. Este estilo de clase dirige al sistema para crear un contexto de dispositivo privado, es decir, para asignar un contexto de dispositivo único para cada ventana de la clase . La aplicación solo necesita recuperar el contexto una vez y, a continuación, usarlo para todas las pinturas posteriores.

Memoria de clase adicional

El sistema mantiene internamente una estructura WNDCLASSEX para cada clase de ventana del sistema. Cuando una aplicación registra una clase de ventana, puede dirigir al sistema para asignar y anexar un número de bytes adicionales de memoria al final de la estructura WNDCLASSEX . Esta memoria se denomina memoria de clase adicional y la comparten todas las ventanas que pertenecen a la clase . Use la memoria de clase adicional para almacenar cualquier información relacionada con la clase .

Dado que se asigna memoria adicional desde el montón local del sistema, una aplicación debe usar memoria de clase adicional con moderación. Se produce un error en la función RegisterClassEx si la cantidad de memoria de clase adicional solicitada es superior a 40 bytes. Si una aplicación requiere más de 40 bytes, debe asignar su propia memoria y almacenar un puntero a la memoria en la memoria adicional.

Las funciones SetClassWord y SetClassLong copian un valor en la memoria de clase adicional. Para recuperar un valor de la memoria de clase adicional, use las funciones GetClassWord y GetClassLong . El miembro cbClsExtra de la estructura WNDCLASSEX especifica la cantidad de memoria de clase adicional que se va a asignar. Una aplicación que no usa memoria de clase adicional debe inicializar el miembro cbClsExtra en cero.

Memoria de ventana adicional

El sistema mantiene una estructura de datos interna para cada ventana. Al registrar una clase de ventana, una aplicación puede especificar un número de bytes adicionales de memoria, denominada memoria de ventana adicional. Al crear una ventana de la clase , el sistema asigna y anexa la cantidad especificada de memoria de ventana adicional al final de la estructura de la ventana. Una aplicación puede usar esta memoria para almacenar datos específicos de la ventana.

Dado que se asigna memoria adicional desde el montón local del sistema, una aplicación debe usar memoria de ventana adicional con moderación. Se produce un error en la función RegisterClassEx si la cantidad de memoria de ventana adicional solicitada es superior a 40 bytes. Si una aplicación requiere más de 40 bytes, debe asignar su propia memoria y almacenar un puntero a la memoria en la memoria adicional de la ventana.

La función SetWindowLong copia un valor en la memoria adicional. La función GetWindowLong recupera un valor de la memoria adicional. El miembro cbWndExtra de la estructura WNDCLASSEX especifica la cantidad de memoria de ventana adicional que se va a asignar. Una aplicación que no usa la memoria debe inicializar cbWndExtra en cero.