Crear aplicaciones Win32 (C++)

Actualización: noviembre 2007

La API Win32, también conocida como API de Windows, es un marco de trabajo basado en C que permite crear aplicaciones para Windows y que existe desde Windows 1.0. Podrá encontrar amplia información sobre esta API en API de Windows.

En este procedimiento, crearemos una aplicación Win32 sencilla que muestra el texto "Hello, World!" en una ventana. Los pasos de procedimiento son idénticos para todas las aplicaciones Win32. Después de completar este procedimiento, puede utilizar el código que ha creado aquí como un esqueleto para crear cualquier otra aplicación Win32.

En este tema se da por supuesto que conoce los fundamentos del lenguaje C++. Si está empezando a aprender C++, le recomendamos el libro "C++ Beginner's Guide" escrito por Herb Schildt, disponible en línea en http://go.microsoft.com/fwlink/?LinkId=115303.

vínculo a vídeo Para obtener una demostración en vídeo, vea Video How to: Creating Win32 Applications (C++).

Para crear un nuevo proyecto Win32

  1. En el menú Archivo, haga clic en Nuevo y, a continuación, haga clic en Proyecto….

  2. En el panel Tipos de proyecto, seleccione Win32 en el nodo Visual C++ y, a continuación, seleccione Proyecto Win32 en el panel Plantillas.

    Escriba un nombre para el proyecto, como win32app. Puede aceptar la ubicación predeterminada, escribir una ubicación o buscar un directorio donde desee guardar el proyecto.

  3. En el Asistente para aplicaciones Win32, seleccione Siguiente.

  4. En el Asistente para aplicaciones Win32, en Tipo de aplicación, seleccione Aplicación para Windows. En Opciones adicionales, seleccione Proyecto vacío. Deje las opciones restantes como están. Haga clic en Finalizar para crear el proyecto.

  5. Agregue un archivo C++ al proyecto seleccionando Agregar nuevo elemento... en el menú Proyecto. En el cuadro de diálogo Agregar nuevo elemento, seleccione Archivo C++ (.cpp). Escriba un nombre para el archivo, como GT_HelloWorldWin32.cpp, y haga clic en Agregar.

Para iniciar un aplicaciones Win32

  1. Como ya sabe, toda aplicación de C y C++ debe contener una función main. Esta función es el punto de inicio de la aplicación. De modo similar, en una aplicación Win32, cada aplicación debe tener una función WinMain. La sintaxis de WinMain es la siguiente:

    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow);
    

    Para obtener una explicación de los parámetros y el valor devuelto de esta función, vea WinMain Función.

  2. Además de WinMain, cada aplicación Win32 también debe tener una segunda función que normalmente se denomina WndProc, y que significa procedimiento de ventana. La sintaxis de WndProc es la siguiente:

    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    

    El propósito de esta función es procesar cualquier mensaje que su aplicación reciba del sistema operativo. ¿Cuándo recibe su aplicación mensajes del sistema operativo? Continuamente. Por ejemplo, imagine que hemos creado un cuadro de diálogo que tiene un botón Aceptar. Cuando el usuario hace clic en ese botón, el sistema operativo envía un mensaje a nuestra aplicación que nos permite saber que un usuario ha presionado este botón. La función WndProc es la responsable de contestar a ese evento. En nuestro ejemplo, la respuesta adecuada podría ser cerrar el cuadro de diálogo.

    Para obtener más información, vea Procedimientos de ventanas.

Para agregar funcionalidad a WinMain

  1. Primero, cree dentro de la función WinMain una estructura de clase de ventana de tipo WNDCLASSEX. Esta estructura contiene información sobre la ventana, tal como el icono de la aplicación, el color de fondo de la ventana, el nombre que aparece en la barra de título, el nombre de la función de procedimiento de ventana, etc. Una estructura WNDCLASSEX típica es la siguiente:

        WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    

    Para obtener una explicación de los campos de esta estructura, vea WNDCLASSEX.

  2. Ahora que ya ha creado su clase de ventana, debe registrarla. Utilice la función RegisterClassEx y pase la estructura de clase de ventana como un argumento:

        if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL,
                _T("Call to RegisterClassEx failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
  3. Ahora que ya ha registrado su clase, es el momento de crear una ventana. Use la función CreateWindow del siguiente modo:

    static TCHAR szWindowClass[] = _T("win32app");
    static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
    // The parameters to CreateWindow explained:
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application dows not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 100,
        NULL,
        NULL,
        hInstance,
        NULL
    );
    if (!hWnd)
    {
        MessageBox(NULL,
            _T("Call to CreateWindow failed!"),
            _T("Win32 Guided Tour"),
            NULL);
    
        return 1;
    }
    

    Esta función devuelve un HWND, que es un identificador de una ventana. Para obtener más información, vea Tipos de datos de Windows.

  4. Ahora que ya hemos creado la ventana, podemos mostrarla en pantalla utilizando el siguiente código:

    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd,
        nCmdShow);
    UpdateWindow(hWnd);
    

    Hasta ahora, esta ventana no mostrará mucho, ya que no hemos implementado todavía la función WndProc.

  5. El paso final de WinMain es el bucle de mensajes. El propósito de este bucle es detectar mensajes enviados por el sistema operativo. Cuando la aplicación recibe un mensaje, el mensaje se envía a la función WndProc para procesarlo. El bucle de mensajes es similar a éste:

        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    

    Para obtener más información sobre las estructuras y funciones que se utilizan en el bucle de mensajes, vea MSG, GetMessage, TranslateMessage y DispatchMessage.

  6. Los pasos que ha completado son comunes a la mayoría de las aplicaciones Win32. En este punto, su función WinMain debería ser similar a ésta:

    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
        WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    
        if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL,
                _T("Call to RegisterClassEx failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
        hInst = hInstance; // Store instance handle in our global variable
    
        // The parameters to CreateWindow explained:
        // szWindowClass: the name of the application
        // szTitle: the text that appears in the title bar
        // WS_OVERLAPPEDWINDOW: the type of window to create
        // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
        // 500, 100: initial size (width, length)
        // NULL: the parent of this window
        // NULL: this application dows not have a menu bar
        // hInstance: the first parameter from WinMain
        // NULL: not used in this application
        HWND hWnd = CreateWindow(
            szWindowClass,
            szTitle,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            500, 100,
            NULL,
            NULL,
            hInstance,
            NULL
        );
    
        if (!hWnd)
        {
            MessageBox(NULL,
                _T("Call to CreateWindow failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
        // The parameters to ShowWindow explained:
        // hWnd: the value returned from CreateWindow
        // nCmdShow: the fourth parameter from WinMain
        ShowWindow(hWnd,
            nCmdShow);
        UpdateWindow(hWnd);
    
        // Main message loop:
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    }
    

Para agregar funcionalidad a WndProc

  1. El propósito de la función WndProc es el de procesar los mensajes que recibe la aplicación. Normalmente, esto se implementa mediante una función switch.

    El primer mensaje que procesaremos es el mensaje WM_PAINT. Su aplicación recibe este mensaje cuando una parte de la ventana de la aplicación debe ser actualizada. Cuando se crea una ventana por primera vez, la ventana se debe actualizar entera, y esto se indica mediante ese mensaje.

    A la hora de procesar un mensaje WM_PAINT, lo primero que debería hacer es llamar a BeginPaint, y lo ultimo llamar a EndPaint. Entre estas dos llamadas a función, deberá escribir toda la lógica necesaria para colocar y organizar el texto, los botones y otros controles de la ventana. Para esta aplicación, mostramos la cadena " Hello, World!" dentro de la ventana. Para mostrar texto, utilice la función TextOut, como se indica a continuación:

    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, World!");
    
    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
    
        // Here your application is laid out.
        // For this introduction, we just print out "Hello, World!"
        // in the top left corner.
        TextOut(hdc,
            5, 5,
            greeting, _tcslen(greeting));
        // End application-specific layout section.
    
        EndPaint(hWnd, &ps);
        break;
    }
    
  2. Su aplicación procesará normalmente muchos otros mensajes, tales como WM_CREATE y WM_DESTROY. A continuación, se indica una función WndProc simple pero completa:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
        TCHAR greeting[] = _T("Hello, World!");
    
        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
    
            // Here your application is laid out.
            // For this introduction, we just print out "Hello, World!"
            // in the top left corner.
            TextOut(hdc,
                5, 5,
                greeting, _tcslen(greeting));
            // End application specific layout section.
    
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
            break;
        }
    
        return 0;
    }
    

Descripción

Una vez completados todos los pasos, su código se debería parecer al siguiente. Para generar la aplicación, seleccione Generar solución en el menú Generar. Si su aplicación se compila sin ningún error, puede ejecutarla presionando F5. Una ventana con el texto "Hello, World!" aparecerá en la pantalla cerca de la esquina superior izquierda.

Código

// GT_HelloWorldWin32.cpp
// compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

// Global variables

// The main window class name.
static TCHAR szWindowClass[] = _T("win32app");

// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("Win32 Guided Tour Application");

HINSTANCE hInst;

// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL,
            _T("Call to RegisterClassEx failed!"),
            _T("Win32 Guided Tour"),
            NULL);

        return 1;
    }

    hInst = hInstance; // Store instance handle in our global variable

    // The parameters to CreateWindow explained:
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application dows not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 100,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (!hWnd)
    {
        MessageBox(NULL,
            _T("Call to CreateWindow failed!"),
            _T("Win32 Guided Tour"),
            NULL);

        return 1;
    }

    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd,
        nCmdShow);
    UpdateWindow(hWnd);

    // Main message loop:
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, World!");

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        // Here your application is laid out.
        // For this introduction, we just print out "Hello, World!"
        // in the top left corner.
        TextOut(hdc,
            5, 5,
            greeting, _tcslen(greeting));
        // End application-specific layout section.

        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }

    return 0;
}

Adiciones de comunidad

Mostrar: