Usar procedimientos de ventana

En esta sección se explica cómo realizar las siguientes tareas asociadas a los procedimientos de ventana.

Diseño de un procedimiento de ventana

En el ejemplo siguiente se muestra la estructura de un procedimiento de ventana típico. El procedimiento de ventana usa el argumento message en una instrucción switch con mensajes individuales administrados por instrucciones case independientes. Observe que cada caso devuelve un valor específico para cada mensaje. Para los mensajes que no procesa, el procedimiento de ventana llama a la función DefWindowProc .

LRESULT CALLBACK MainWndProc(
    HWND hwnd,        // handle to window
    UINT uMsg,        // message identifier
    WPARAM wParam,    // first message parameter
    LPARAM lParam)    // second message parameter
{ 
 
    switch (uMsg) 
    { 
        case WM_CREATE: 
            // Initialize the window. 
            return 0; 
 
        case WM_PAINT: 
            // Paint the window's client area. 
            return 0; 
 
        case WM_SIZE: 
            // Set the size and position of the window. 
            return 0; 
 
        case WM_DESTROY: 
            // Clean up window-specific data objects. 
            return 0; 
 
        // 
        // Process other messages. 
        // 
 
        default: 
            return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } 
    return 0; 
} 

El mensaje de WM_NCCREATE se envía justo después de crear la ventana, pero si una aplicación responde a este mensaje devolviendo FALSE, se produce un error en la función CreateWindowEx . El WM_CREATE mensaje se envía una vez creada la ventana.

El WM_DESTROY mensaje se envía cuando la ventana está a punto de destruirse. La función DestroyWindow se encarga de destruir las ventanas secundarias de la ventana que se destruyen. El WM_NCDESTROY mensaje se envía justo antes de que se destruya una ventana.

Al menos, un procedimiento de ventana debe procesar el WM_PAINT mensaje para dibujarse a sí mismo. Normalmente, también debe controlar los mensajes del mouse y del teclado. Consulte las descripciones de mensajes individuales para determinar si el procedimiento de ventana debe controlarlos.

La aplicación puede llamar a la función DefWindowProc como parte del procesamiento de un mensaje. En tal caso, la aplicación puede modificar los parámetros del mensaje antes de pasar el mensaje a DefWindowProc, o puede continuar con el procesamiento predeterminado después de realizar sus propias operaciones.

Un procedimiento de cuadro de diálogo recibe un mensaje de WM_INITDIALOG en lugar de un mensaje de WM_CREATE y no pasa mensajes sin procesar a la función DefDlgProc . De lo contrario, un procedimiento de cuadro de diálogo es exactamente el mismo que un procedimiento de ventana.

Asociación de un procedimiento de ventana con una clase Window

Al registrar la clase , se asocia un procedimiento de ventana a una clase de ventana. Debe rellenar una estructura WNDCLASS con información sobre la clase y el miembro lpfnWndProc debe especificar la dirección del procedimiento de ventana. Para registrar la clase, pase la dirección de la estructura WNDCLASS a la función RegisterClass . Una vez registrada la clase de ventana, el procedimiento de ventana se asocia automáticamente a cada nueva ventana creada con esa clase.

En el ejemplo siguiente se muestra cómo asociar el procedimiento de ventana en el ejemplo anterior con una clase de ventana.

int APIENTRY WinMain( 
    HINSTANCE hinstance,  // handle to current instance 
    HINSTANCE hinstPrev,  // handle to previous instance 
    LPSTR lpCmdLine,      // address of command-line string 
    int nCmdShow)         // show-window type 
{ 
    WNDCLASS wc; 
 
    // Register the main window class. 
    wc.style = CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc = (WNDPROC) MainWndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hinstance; 
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName =  "MainMenu"; 
    wc.lpszClassName = "MainWindowClass"; 
 
    if (!RegisterClass(&wc)) 
       return FALSE; 
 
    // 
    // Process other messages. 
    // 
 
} 

Subclase de una ventana

Para subclase una instancia de una ventana, llame a la función SetWindowLong y especifique el identificador de la ventana para subclase la marca GWL_WNDPROC y un puntero al procedimiento de subclase. SetWindowLong devuelve un puntero al procedimiento de ventana original; use este puntero para pasar mensajes al procedimiento original. El procedimiento de ventana de subclase debe usar la función CallWindowProc para llamar al procedimiento de ventana original.

Nota

Para escribir código compatible con versiones de 32 y 64 bits de Windows, use la función SetWindowLongPtr .

 

En el ejemplo siguiente se muestra cómo subclase una instancia de un control de edición en un cuadro de diálogo. El procedimiento de ventana de subclase permite que el control de edición reciba todas las entradas del teclado, incluidas las teclas ENTRAR y TAB, siempre que el control tenga el foco de entrada.

WNDPROC wpOrigEditProc; 
 
LRESULT APIENTRY EditBoxProc(
    HWND hwndDlg, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam) 
{ 
    HWND hwndEdit; 
 
    switch(uMsg) 
    { 
        case WM_INITDIALOG: 
            // Retrieve the handle to the edit control. 
            hwndEdit = GetDlgItem(hwndDlg, ID_EDIT); 
 
            // Subclass the edit control. 
            wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit, 
                GWL_WNDPROC, (LONG) EditSubclassProc); 
            // 
            // Continue the initialization procedure. 
            // 
            return TRUE; 
 
        case WM_DESTROY: 
            // Remove the subclass from the edit control. 
            SetWindowLong(hwndEdit, GWL_WNDPROC, 
                (LONG) wpOrigEditProc); 
            // 
            // Continue the cleanup procedure. 
            // 
            break; 
    } 
    return FALSE; 
        UNREFERENCED_PARAMETER(lParam); 
} 
 
// Subclass procedure 
LRESULT APIENTRY EditSubclassProc(
    HWND hwnd, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam) 
{ 
    if (uMsg == WM_GETDLGCODE) 
        return DLGC_WANTALLKEYS; 
 
    return CallWindowProc(wpOrigEditProc, hwnd, uMsg, 
        wParam, lParam); 
}