Uso de Windows

En los ejemplos de esta sección se describe cómo realizar las siguientes tareas:

Crear una ventana principal

La primera ventana que crea una aplicación suele ser la ventana principal. Puede crear la ventana principal mediante la función CreateWindowEx , especificando la clase de ventana, el nombre de la ventana, los estilos de ventana, el tamaño, la posición, el identificador de menú, el identificador de instancia y los datos de creación. Una ventana principal pertenece a una clase de ventana definida por la aplicación, por lo que debe registrar la clase de ventana y proporcionar un procedimiento de ventana para la clase antes de crear la ventana principal.

La mayoría de las aplicaciones suelen usar el estilo WS_OVERLAPPEDWINDOW para crear la ventana principal. Este estilo proporciona a la ventana una barra de título, un menú de ventana, un borde de ajuste de tamaño y minimizar y maximizar botones. La función CreateWindowEx devuelve un identificador que identifica de forma única la ventana.

En el ejemplo siguiente se crea una ventana principal que pertenece a una clase de ventana definida por la aplicación. El nombre de la ventana, Ventana principal, aparecerá en la barra de título de la ventana. Al combinar los estilos WS_VSCROLL y WS_HSCROLL con el estilo WS_OVERLAPPEDWINDOW , la aplicación crea una ventana principal con barras de desplazamiento horizontales y verticales, además de los componentes proporcionados por el estilo WS_OVERLAPPEDWINDOW . Las cuatro apariciones del CW_USEDEFAULT constante establecen el tamaño inicial y la posición de la ventana en los valores predeterminados definidos por el sistema. Al especificar NULL en lugar de un identificador de menú, la ventana tendrá definido el menú para la clase de ventana.

HINSTANCE hinst; 
HWND hwndMain; 
 
// Create the main window. 
 
hwndMain = CreateWindowEx( 
    0,                      // no extended styles           
    "MainWClass",           // class name                   
    "Main Window",          // window name                  
    WS_OVERLAPPEDWINDOW |   // overlapped window            
             WS_HSCROLL |   // horizontal scroll bar        
             WS_VSCROLL,    // vertical scroll bar          
    CW_USEDEFAULT,          // default horizontal position  
    CW_USEDEFAULT,          // default vertical position    
    CW_USEDEFAULT,          // default width                
    CW_USEDEFAULT,          // default height               
    (HWND) NULL,            // no parent or owner window    
    (HMENU) NULL,           // class menu used              
    hinst,                  // instance handle              
    NULL);                  // no window creation data      
 
if (!hwndMain) 
    return FALSE; 
 
// Show the window using the flag specified by the program 
// that started the application, and send the application 
// a WM_PAINT message. 
 
ShowWindow(hwndMain, SW_SHOWDEFAULT); 
UpdateWindow(hwndMain); 

Observe que el ejemplo anterior llama a la función ShowWindow después de crear la ventana principal. Esto se hace porque el sistema no muestra automáticamente la ventana principal después de crearla. Al pasar la marca de SW_SHOWDEFAULT a ShowWindow, la aplicación permite al programa que inició la aplicación establecer el estado de presentación inicial de la ventana principal. La función UpdateWindow envía la ventana su primer mensaje de WM_PAINT .

Crear, enumerar y cambiar el tamaño de ventanas secundarias

Puede dividir el área cliente de una ventana en diferentes áreas funcionales mediante ventanas secundarias. Crear una ventana secundaria es como crear una ventana principal: se usa la función CreateWindowEx . Para crear una ventana de una clase de ventana definida por la aplicación, debe registrar la clase de ventana y proporcionar un procedimiento de ventana antes de crear la ventana secundaria. Debe proporcionar a la ventana secundaria el estilo WS_CHILD y especificar una ventana primaria para la ventana secundaria al crearla.

En el ejemplo siguiente se divide el área cliente de la ventana principal de una aplicación en tres áreas funcionales mediante la creación de tres ventanas secundarias de igual tamaño. Cada ventana secundaria tiene el mismo alto que el área cliente de la ventana principal, pero cada una tiene un tercio de ancho. La ventana principal crea las ventanas secundarias en respuesta al mensaje WM_CREATE , que recibe la ventana principal durante su propio proceso de creación de ventanas. Dado que cada ventana secundaria tiene el estilo WS_BORDER , cada una tiene un borde de línea fino. Además, dado que no se especifica el estilo de WS_VISIBLE , cada ventana secundaria se oculta inicialmente. Observe también que a cada ventana secundaria se le asigna un identificador de ventana secundaria.

El tamaño de la ventana principal y coloca las ventanas secundarias en respuesta al mensaje WM_SIZE , que recibe la ventana principal cuando cambia su tamaño. En respuesta a WM_SIZE, la ventana principal recupera las dimensiones de su área de cliente mediante la función GetClientRect y, a continuación, pasa las dimensiones a la función EnumChildWindows . EnumChildWindows pasa el identificador a cada ventana secundaria, a su vez, a la función de devolución de llamada EnumChildProc definida por la aplicación. Esta función ajusta y coloca cada ventana secundaria llamando a la función MoveWindow ; el tamaño y la posición se basan en las dimensiones del área cliente de la ventana principal y el identificador de la ventana secundaria. Después, EnumChildProc llama a la función ShowWindow para que la ventana sea visible.

#define ID_FIRSTCHILD  100 
#define ID_SECONDCHILD 101 
#define ID_THIRDCHILD  102 
 
LONG APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    RECT rcClient; 
    int i; 
 
    switch(uMsg) 
    { 
        case WM_CREATE: // creating main window  
 
            // Create three invisible child windows. 

            for (i = 0; i < 3; i++) 
            { 
                CreateWindowEx(0, 
                               "ChildWClass", 
                               (LPCTSTR) NULL, 
                               WS_CHILD | WS_BORDER, 
                               0,0,0,0, 
                               hwnd, 
                               (HMENU) (int) (ID_FIRSTCHILD + i), 
                               hinst, 
                               NULL); 
            }
 
            return 0; 
 
        case WM_SIZE:   // main window changed size 
 
            // Get the dimensions of the main window's client 
            // area, and enumerate the child windows. Pass the 
            // dimensions to the child windows during enumeration. 
 
            GetClientRect(hwnd, &rcClient); 
            EnumChildWindows(hwnd, EnumChildProc, (LPARAM) &rcClient); 
            return 0; 

        // Process other messages. 
    } 
    return DefWindowProc(hwnd, uMsg, wParam, lParam); 
} 
 
BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam) 
{ 
    LPRECT rcParent; 
    int i, idChild; 
 
    // Retrieve the child-window identifier. Use it to set the 
    // position of the child window. 
 
    idChild = GetWindowLong(hwndChild, GWL_ID); 
 
    if (idChild == ID_FIRSTCHILD) 
        i = 0; 
    else if (idChild == ID_SECONDCHILD) 
        i = 1; 
    else 
        i = 2; 
 
    // Size and position the child window.  
 
    rcParent = (LPRECT) lParam; 
    MoveWindow(hwndChild, 
               (rcParent->right / 3) * i, 
               0, 
               rcParent->right / 3, 
               rcParent->bottom, 
               TRUE); 
 
    // Make sure the child window is visible. 
 
    ShowWindow(hwndChild, SW_SHOW); 
 
    return TRUE;
}

Destruir una ventana

Puede usar la función DestroyWindow para destruir una ventana. Normalmente, una aplicación envía el mensaje WM_CLOSE antes de destruir una ventana, lo que proporciona a la ventana la oportunidad de pedir al usuario confirmación antes de que se destruya la ventana. Una ventana que incluye un menú de ventana recibe automáticamente el mensaje de WM_CLOSE cuando el usuario hace clic en Cerrar en el menú de la ventana. Si el usuario confirma que se debe destruir la ventana, la aplicación llama a DestroyWindow. El sistema envía el mensaje WM_DESTROY a la ventana después de quitarlo de la pantalla. En respuesta a WM_DESTROY, la ventana guarda sus datos y libera los recursos asignados. Una ventana principal concluye su procesamiento de WM_DESTROY llamando a la función PostQuitMessage para salir de la aplicación.

En el ejemplo siguiente se muestra cómo solicitar confirmación del usuario antes de destruir una ventana. En respuesta a WM_CLOSE, el ejemplo muestra un cuadro de diálogo que contiene los botones Sí, No y Cancelar . Si el usuario hace clic en , se llama a DestroyWindow ; de lo contrario, la ventana no se destruye. Dado que la ventana que se destruye es una ventana principal, el ejemplo llama a PostQuitMessage en respuesta a WM_DESTROY.

case WM_CLOSE: 
 
    // Create the message box. If the user clicks 
    // the Yes button, destroy the main window. 
 
    if (MessageBox(hwnd, szConfirm, szAppName, MB_YESNOCANCEL) == IDYES) 
        DestroyWindow(hwndMain); 
    else 
        return 0; 
 
case WM_DESTROY: 
 
    // Post the WM_QUIT message to 
    // quit the application terminate. 
 
    PostQuitMessage(0); 
    return 0;

Uso de Windows superpuesta

Para que un cuadro de diálogo aparezca como una ventana translúcida, cree primero el cuadro de diálogo como de costumbre. A continuación, en WM_INITDIALOG, establezca el bit en capas del estilo extendido de la ventana y llame a SetLayeredWindowAttributes con el valor alfa deseado. El código podría tener este aspecto:

// Set WS_EX_LAYERED on this window 
SetWindowLong(hwnd, 
              GWL_EXSTYLE, 
              GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);

// Make this window 70% alpha
SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);

Tenga en cuenta que el tercer parámetro de SetLayeredWindowAttributes es un valor que va de 0 a 255, con 0 haciendo que la ventana sea completamente transparente y 255 lo haga completamente opaco. Este parámetro imita la función BLENDFUNCTION más versátil de la función AlphaBlend .

Para que esta ventana vuelva a opaca, quite el bit de WS_EX_LAYERED llamando a SetWindowLong y, a continuación, pida a la ventana que vuelva a pintar. Se desea quitar el bit para informar al sistema de que puede liberar memoria asociada a la capa y el redireccionamiento. El código podría tener este aspecto:

// Remove WS_EX_LAYERED from this window styles
SetWindowLong(hwnd, 
              GWL_EXSTYLE,
              GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);

// Ask the window and its children to repaint
RedrawWindow(hwnd, 
             NULL, 
             NULL, 
             RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);

Para usar ventanas secundarias superpuestas, la aplicación debe declararse Windows 8 compatible con el manifiesto.

Para windows 10/11, puede incluir este fragmento de código de compatibilidad en para app.manifest que sea compatible con Windows 10 :

...
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- Windows 10 GUID -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
    </application>
</compatibility>
...

Puede leer más sobre cómo modificar el manifiesto de aplicación aquí: Manifiestos de aplicación