Tutorial: crear aplicaciones de escritorio de Windows (C++)

 

Para obtener la documentación más reciente de Visual Studio 2017 RC, consulte Documentación de Visual Studio 2017 RC.

Este tutorial muestra cómo crear una aplicación básica de escritorio de Win32 que muestra "Hello, World!" en una ventana. Puede utilizar el código que va a desarrollar en este tutorial como modelo para crear otras aplicaciones de escritorio de Windows.

La API de Win32 (también conocida como la API de Windows) es un marco basado en C para crear aplicaciones Windows. Para obtener más información acerca de la API de Win32, vea API de Windows.

System_CAPS_ICON_important.jpg Importante

Para poder explicar con mayor claridad los segmentos de código específicos de los pasos de este documento, puede que tengamos que omitir algunas instrucciones de código que serían necesarias para una aplicación operativa; por ejemplo, directivas de inclusión y declaraciones de variable global. La sección Ejemplo al final de este documento muestra el código completo.

Para completar este tutorial, debe comprender los conceptos básicos del lenguaje C++.

Para obtener una demostración en vídeo, vea el vídeo acerca de cómo crear aplicaciones Win32 (C++) en la documentación de Visual Studio 2008.

Para crear un proyecto basado en Win32

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

  2. En el cuadro de diálogo Nuevo proyecto, en el panel de la izquierda, haga clic en Plantillas instaladas, haga clic en Visual C++ y, a continuación, seleccione Win32. En el panel central, seleccione Proyecto Win32.

    En el cuadro Nombre, escriba un nombre para el proyecto; por ejemplo, win32app. Haga clic en Aceptar.

  3. En la página de bienvenida del Asistente para aplicaciones Win32, haga clic en Siguiente.

  4. En la página Configuración de la aplicación, en Tipo de aplicación, seleccione Aplicación para Windows. En Opciones adicionales, seleccione Proyecto vacío. Haga clic en Finalizar para crear el proyecto.

  5. En el Explorador de soluciones, haga clic con el botón secundario del mouse en el proyecto Win32app, haga clic en Agregar y, a continuación, en Nuevo elemento. En el cuadro de diálogo Agregar nuevo elemento, seleccione Archivo C++ (.cpp). En el cuadro Nombre, escriba un nombre para el archivo; por ejemplo, GT_HelloWorldWin32.cpp. Haga clic en Agregar.

Para iniciar una aplicación de escritorio de Windows

  1. Al igual que todas las aplicaciones de C y C++ deben tener una función main como punto de partida, todas las aplicaciones basadas en Win32 deben tener una función WinMain.WinMain tiene la siguiente sintaxis.

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

    Para obtener información sobre los parámetros y el valor devuelto de esta función, vea WinMain (Función).

  2. Debido a que el código de aplicación debe utilizar las definiciones existentes, agregue instrucciones de inclusión al archivo.

    #include <windows.h> #include <stdlib.h> #include <string.h> #include <tchar.h>  
    
    
  3. Además de la función WinMain, todas las aplicaciones de escritorio de Windows deben tener una función de procedimiento de ventana. Esta función normalmente se denomina WndProc.WndProc tiene la siguiente sintaxis.

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

    Esta función controla los abundantes mensajes que una aplicación recibe del sistema operativo. Por ejemplo, en una aplicación que tiene un cuadro de diálogo con un botón Aceptar, cuando el usuario hace clic en el botón, el sistema operativo envía a la aplicación un mensaje que informa de que se hizo clic en el botón.WndProc es responsable de responder a ese evento. En el ejemplo, la respuesta adecuada podría ser cerrar el cuadro de diálogo.

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

Para agregar funcionalidad a la función WinMain

  1. En la función WinMain, cree una estructura de clase de ventana de tipo WNDCLASSEX. Esta estructura contiene información sobre la ventana, por ejemplo, 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. El ejemplo siguiente muestra una estructura típica de WNDCLASSEX.

    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 información sobre los campos de esta estructura, vea WNDCLASSEX.

  2. Ahora que ya ha creado una clase de ventana, debe registrarla. Use la función RegisterClassEx y pase la estructura de clase de ventana como argumento.

    if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL); return 1; }  
    
    
  3. Ahora puede crear una ventana. Use la función CreateWindow.

    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 does 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, utilice el código siguiente para mostrar la ventana.

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

    En este punto, la ventana que se muestra no tendrá mucho contenido porque todavía no ha implementado la función WndProc.

  5. Ahora agregue un bucle de mensajes para escuchar los mensajes que envía el sistema operativo. Cuando la aplicación recibe un mensaje, este bucle lo envía a la función WndProc que se va a controlar. El bucle de mensajes es similar al código siguiente.

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

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

    En este punto, la función WinMain debe ser similar al código siguiente.

    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 la función WndProc

  1. Para habilitar la función WndProc a fin de controlar los mensajes que recibe la aplicación, implemente una instrucción switch.

    El primer mensaje que se va a controlar es el mensaje WM_PAINT. La aplicación recibe este mensaje cuando debe actualizarse la parte de su ventana mostrada. (Cuando se muestra por primera vez la ventana, toda ella se debe actualizar).

    Para controlar un mensaje WM_PAINT, primero llame a BeginPaint, controle toda la lógica para mostrar el texto, los botones y otros controles de la ventana y luego llame a EndPaint. Para esta aplicación, la lógica entre la llamada inicial y la llamada final consiste en mostrar la cadena "Hello, World!" en la ventana. En el siguiente código, observe que la función TextOut se usa para mostrar la cadena.

    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. Una aplicación normalmente controla muchos otros mensajes, por ejemplo, WM_CREATE y WM_DESTROY. El código siguiente muestra una función WndProc básica 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; }  
    
    

Para compilar este ejemplo

  1. Cree un proyecto basado en Win32 como se muestra en "Para crear un proyecto basado en Win32" anteriormente en este tutorial.

  2. Copie el código que se incluye después de estos pasos y, a continuación, péguelo en el archivo de origen GT_HelloWorldWin32.cpp.

  3. En el menú Compilar, haga clic en Compilar solución.

  4. Para ejecutar la aplicación, presione F5. Una ventana que contiene el texto "Hola a todos" debe aparecer en la esquina superior izquierda de la pantalla.

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 does 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; }  

Aplicaciones de escritorio de Windows

Mostrar: