演练:创建传统的 Windows 桌面应用程序 (C++)

本演练演示如何在 Visual Studio 中创建传统的 Windows 桌面应用程序。 你创建的应用程序使用 Windows API 在窗口中显示“Hello, Windows desktop!”。 可以将在本演练中开发的代码作为模式来创建 Windows 桌面应用程序。

Windows API(也称为 Win32 API、Windows 桌面 API 和 Windows Classic API)是用于创建 Windows 应用程序的基于 C 语言的框架。 几十年来,它一直用于创建 Windows 应用程序。 在 Windows API 的基础上,构建了更高级、更易于编程的框架。 例如,MFC、ATL、.NET 框架。 即使是用 C++/WinRT 针对 UWP 和应用商店应用编写的最现代的 Windows 运行时代码,也使用底层的 Windows API。 有关 Windows API 的详细信息,请参阅 Windows API 索引

重要

本文档末尾的生成代码部分显示了完整代码。 本演练涵盖了 Windows 应用中的多个代码段,但你不要边演练边编写代码,因为代码片段中省略了一些详细信息,以专注于最重要的部分。 可以复制完整的代码并在最后将其粘贴到项目中。

先决条件

  • 运行 Microsoft Windows 7 或更高版本的计算机。 为了获得最佳开发体验,建议使用 Windows 11 或更高版本。

  • 一份 Visual Studio 副本。 有关如何下载和安装 Visual Studio 的信息,请参阅安装 Visual Studio。 运行安装程序时,请务必选中“使用 C++ 的桌面开发”工作负载。 如果在安装 Visual Studio 时未安装此工作负载,请不要担心。 可以再次运行安装程序并立即安装。

    Visual Studio 安装程序中 C++ 工作负载的桌面开发屏幕截图,上面显示了:使用 Visual C++ 工具集的强大功能构建基于 Windows 的经典应用

  • 对使用 Visual Studio IDE 有基本的了解。 如果你之前使用过 Windows 桌面应用,可能具备一定的相关知识。 有关简介,请参阅 Visual Studio IDE 功能导览

  • 了解足够的 C++ 语言基础知识以供继续操作。 别担心,我们不会执行过于复杂的操作。

创建 Windows 桌面项目

按照以下步骤创建你的第一个 Windows 桌面项目。 根据本演练开头的注释,完整的代码可在本演练末尾的生成代码部分中找到。 继续执行创建项目的步骤,但不要粘贴以下代码部分,直到最后显示完整的应用程序代码。 代码片段中省略了一些详细信息,以专注于最重要的部分。 可以复制完整的代码并在最后将其粘贴到项目中。

简化解释。 若要查看 Visual Studio 首选项的文档,请使用“版本”选择器控件。 它位于此页面上目录的顶部。

在 Visual Studio 中创建 Windows 桌面项目

  1. 在主菜单中,选择“文件”>“新建”>“项目”,打开“创建新项目”对话框

  2. 在对话框顶部,将“语言”设置为“C++”,将“平台”设置为“Windows”,将“项目类型”设置为“桌面”

  3. 从经过筛选的项目类型列表中,选择“Windows 桌面向导”,然后选择“下一步”。 在下一页中,输入项目的名称,例如 DesktopApp

  4. 选择“创建”按钮创建项目。

  5. 随即显示“Windows 桌面项目”对话框。 在“应用程序类型”下拉列表中,确保选择“桌面应用程序(.exe)”。 由于我们正在制作 Windows 应用程序,因此选择“控制台应用程序”会导致项目无法根据我们将要使用的代码进行生成。 然后,在“附加选项”下,选择“空项目”。 选择“确定”,创建项目

  6. 在解决方案资源管理器中,右键单击“DesktopApp”项目,选择“添加”,然后选择“新项”

    显示向 Visual Studio 2019 中的 DesktopApp 项目添加新项的动画。

    动画显示在解决方案资源管理器中右键单击项目名称,在出现的菜单中选择“添加”,然后选择“新建项”。

  7. 在“添加新项” 对话框中选择“C++ 文件(.cpp)” 。 在“名称”框中,键入文件名,例如 HelloWindowsDesktop.cpp。 选择“添加” 。

    Visual Studio 2019 中“添加新项”对话框的屏幕截图。选中了“C++ 文件 (.cpp)”选项。名称字段设置为 Hello Windows Desktop.cpp。

现已创建项目,源文件在编辑器中打开。

在 Visual Studio 2017 中创建 Windows 桌面项目

  1. 在“文件”菜单上选择“新建”,再选择“项目”。

  2. 在“新建项目”对话框的左窗格中,展开“已安装”>“Visual C++”,然后选择“Windows 桌面”。 在中间窗格中,选择“Windows 桌面向导”

    在“名称”框中,键入项目名称,例如 DesktopApp。 选择 “确定”

    Visual Studio 2017 中“新建项目”对话框的屏幕截图。已选中“Windows 桌面向导”项。名称文本框显示 DesktopApp。

  3. 在“Windows 桌面项目”对话框的“应用程序类型”下,选择“Windows 应用程序(.exe)”。 在“附加选项” 下,选择“空项目” 。 确保未选择“预编译标头”。 选择“确定”,创建项目

  4. 在解决方案资源管理器中,右键单击“DesktopApp”项目,选择“添加”,然后选择“新项”

    显示向 Visual Studio 2017 中的 DesktopApp 项目添加新项的动画。

    动画显示在解决方案资源管理器中右键单击项目名称,在出现的菜单中选择“添加”,然后选择“新建项”。

  5. 在“添加新项” 对话框中选择“C++ 文件(.cpp)” 。 在“名称”框中,键入文件名,例如 HelloWindowsDesktop.cpp。 选择“添加” 。

    Visual Studio 2017 中“添加新项”对话框的屏幕截图。左侧已选择已安装 > 的 Visual C++,并突出显示了“C++ 文件”选项。

现已创建项目,源文件在编辑器中打开。

在 Visual Studio 2015 中创建 Windows 桌面项目

  1. 在“文件”菜单上选择“新建”,再选择“项目”。

  2. 在“新建项目”对话框的左窗格中,展开“已安装”>“模板”>“Visual C++”,然后选择“Win32”。 在中间窗格中,选择“Win32 项目”

    在“名称”框中,键入项目名称,例如 DesktopApp。 选择 “确定”

    Visual Studio 2015 中“新建项目”对话框的屏幕截图,其中选中了“已安装”>“模板”>“Visual C++”>“Win32”,突出显示了“Win32 项目”选项,并且在“名称”文本框中键入了 DesktopApp。

  3. 在“Win32 应用程序向导”的“概述”页面上,选择“下一步”

    在 Win32 应用程序向导概览页中创建 DesktopApp。

  4. 在“应用程序设置”页面的“应用程序类型”下,选择“Windows 应用程序”。 在“其他选项”下,取消选中“预编译标头”,然后选中“空项目”。 选择“完成”以创建项目

  5. 在解决方案资源管理器中,右键单击 DesktopApp 项目,选择“添加”,然后选择“新建项”

    显示向 Visual Studio 2015 中的 DesktopApp 项目添加新项的动画。

    动画显示在解决方案资源管理器中右键单击项目名称,在出现的菜单中选择“添加”,然后选择“新建项”。

  6. 在“添加新项” 对话框中选择“C++ 文件(.cpp)” 。 在“名称”框中,键入文件名,例如 HelloWindowsDesktop.cpp。 选择“添加” 。

    Visual Studio 2015 中“添加新项”对话框的屏幕截图,其中选中了“已安装”>“Visual C++”并突出显示了“C++ 文件”选项。

现已创建项目,源文件在编辑器中打开。

代码

接下来介绍如何在 Visual Studio 中为 Windows 桌面应用程序创建代码。

代码在 Windows 桌面应用程序中开始运行的位置

  1. 正如每个 C 应用程序和 C++ 应用程序在起始点必须具有 main 函数,每个 Windows 桌面应用程序也必须具有 WinMain 函数。 WinMain 具有以下语法。

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

    有关此函数的参数和返回值的信息,请参阅 WinMain 入口点

    注意

    这些额外的单词(如 WINAPICALLBACKHINSTANCE_In_)是什么? 传统的 Windows API 广泛使用 typedef 和预处理器宏,来抽象化类型和特定于平台的代码的一些详细信息,例如调用约定、__declspec 声明和编译器 pragma。 在 Visual Studio 中,可以使用 IntelliSense 快速信息功能查看这些 typedef 和宏定义的内容。 将鼠标悬停在感兴趣的单词上,或选择它并按 Ctrl+K、Ctrl+I 打开一个包含定义的小型弹出窗口。 有关详细信息,请参阅使用 IntelliSense。 参数和返回类型通常使用 SAL 注释来帮助捕获编程错误。 有关详细信息,请参阅使用 SAL 批注以减少 C/C++ 代码缺陷

  2. Windows 桌面程序需要 <windows.h>。 你还会经常看到 #include <tchar.h>。 这是为了更轻松地编写可与 charwchar_t 配合使用的应用。 其工作方式是,在代码中改用 TCHAR 宏,如果在项目中定义了 UNICODE 符号,则该宏最终解析为 wchar_t,否则解析为 char。 如果总是在启用 UNICODE 的情况下生成,则不需要 TCHAR,可以直接使用 wchar_t。 有关详细信息,请参阅使用一般文本映射。 以下代码在文件顶部显示这两个 #include 语句。

    #include <windows.h>
    #include <tchar.h>
    
  3. 除了 WinMain 函数之外,每个 Windows 桌面应用程序还必须具有一个窗口过程函数。 该函数称为 WndProc,但可以在代码中为其指定任何名称。 WndProc 具有以下语法。

    LRESULT CALLBACK WndProc(
       _In_ HWND   hWnd,
       _In_ UINT   message,
       _In_ WPARAM wParam,
       _In_ LPARAM lParam
    );
    

    在此函数中编写代码,以处理发生事件时应用程序从 Windows 收到的消息。 例如,如果用户在应用程序中选择“确定”按钮,Windows 会向你发送一条消息。 在 WndProc 函数内编写代码来执行任何适当的工作。 此过程称为处理事件。 你只需处理与应用程序相关的事件。

    有关详细信息,请参阅 窗口过程

WinMain 函数添加功能

  1. WinMain 函数中,需要捕获有关主窗口的一些基本信息。 可以通过填充 WNDCLASSEX 类型的结构来完成此操作。 该结构包含有关窗口的信息,例如应用程序图标、窗口的背景色、标题栏中显示的名称等。 重要的是,它包含一个指向窗口过程的函数指针,该窗口过程处理 Windows 发送到应用的消息。 下面的示例演示一个典型 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(wcex.hInstance, 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, IDI_APPLICATION);
    

    有关上述结构的字段的信息,请参阅 WNDCLASSEX

  2. 填充 WNDCLASSEX 结构后,向 Windows 注册该结构,使其了解你的窗口以及如何向该窗口发送消息。 使用 RegisterClassEx 函数,并将窗口类结构作为参数传递。 使用 _T 宏是因为我们根据上面有关 Unicode 的讨论使用 TCHAR 类型。 下面的代码演示如何注册窗口类。

    if (!RegisterClassEx(&wcex))
    {
       MessageBox(NULL,
          _T("Call to RegisterClassEx failed!"),
          _T("Windows Desktop Guided Tour"),
          NULL);
    
       return 1;
    }
    
  3. 接下来,使用 CreateWindowEx 函数创建窗口。

    static TCHAR szWindowClass[] = _T("DesktopApp");
    static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application");
    
    // The parameters to CreateWindowEx explained:
    // WS_EX_OVERLAPPEDWINDOW : An optional extended window style.
    // 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 = CreateWindowEx(
    WS_EX_OVERLAPPEDWINDOW,
       szWindowClass,
       szTitle,
       WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT,
       500, 100,
       NULL,
       NULL,
       hInstance,
       NULL
    );
    if (!hWnd)
    {
       MessageBox(NULL,
          _T("Call to CreateWindowEx failed!"),
          _T("Windows Desktop Guided Tour"),
          NULL);
    
       return 1;
    }
    

    此函数返回一个 HWND,它是窗口句柄。 句柄有点像指针。 Windows 使用它来跟踪你创建的窗口。 有关详细信息,请参阅 Windows 数据类型

  4. 至此,窗口已创建完毕,但仍需要告知 Windows 使其可见。 这就是这段代码的作用:

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

    显示的窗口只是一个空白矩形,因为尚未实现 WndProc 函数。 应用程序尚未处理 Windows 正在向其发送的消息。

  5. 为了处理消息,我们首先添加所谓的“消息循环”来侦听 Windows 发送的消息。 当应用程序收到消息时,此循环将该消息调度到 WndProc 函数进行处理。 消息循环类似于以下代码:

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

    有关消息循环中的结构和函数的详细信息,请参阅 MSGGetMessageTranslateMessageDispatchMessage

    用于创建应用程序主窗口并侦听 Windows 发送给应用的消息的基本 WinMain 函数类似于以下代码:

    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(wcex.hInstance, 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, IDI_APPLICATION);
    
       if (!RegisterClassEx(&wcex))
       {
          MessageBox(NULL,
             _T("Call to RegisterClassEx failed!"),
             _T("Windows Desktop Guided Tour"),
             NULL);
    
          return 1;
       }
    
       // Store instance handle in our global variable
       hInst = hInstance;
    
       // The parameters to CreateWindowEx explained:
       // WS_EX_OVERLAPPEDWINDOW : An optional extended window style.
       // 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 = CreateWindowEx(
          WS_EX_OVERLAPPEDWINDOW,
          szWindowClass,
          szTitle,
          WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, CW_USEDEFAULT,
          500, 100,
          NULL,
          NULL,
          hInstance,
          NULL
       );
    
       if (!hWnd)
       {
          MessageBox(NULL,
             _T("Call to CreateWindow failed!"),
             _T("Windows Desktop 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;
    }
    

WndProc 函数中处理消息

  1. 要处理应用程序收到的消息,可以在 WndProc 函数中实现 switch 语句。

    要处理的一条重要消息是 WM_PAINT。 当必须更新其显示窗口的一部分时,应用程序会收到 WM_PAINT 消息。 当用户将窗口移到你的窗口前面,然后又将其移开时,可能会发生该事件。 当你的窗口第一次显示时,它会收到此消息,让你有机会显示你的应用程序 UI。 当 Windows 发送这些事件时,你的应用程序会发现它们。 第一次显示窗口时,必须更新整个窗口。

    要处理 WM_PAINT 消息,请首先调用 BeginPaint,然后处理所有的逻辑以在窗口中布局文本、按钮和其他控件。 然后调用 EndPaint。 对于此应用程序,BeginPaint()EndPaint() 之间的代码会在你在 WinMain() 中创建的窗口中显示 Hello, Windows desktop!。 在以下代码中,TextOut 函数在窗口中的指定位置显示文本。

    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, Windows desktop!");
    
    switch (message)
    {
    case WM_PAINT:
       hdc = BeginPaint(hWnd, &ps);
    
       // Here your application is laid out.
       // For this introduction, we just print out "Hello, Windows desktop!"
       // in the top left corner.
       TextOut(hdc,
          5, 5,
          greeting, _tcslen(greeting));
       // End application-specific layout section.
    
       EndPaint(hWnd, &ps);
       break;
    }
    

    在前面的代码中,HDC 是与窗口工作区关联的设备上下文的句柄。 在窗口中绘图时可以使用它来引用其工作区。 BeginPaintEndPaint 函数用于准备并完成工作区中的绘制。 BeginPaint 返回用于在工作区进行绘制的显示设备上下文的句柄;EndPaint 结束绘制请求并释放设备上下文。

  2. 应用程序通常还处理许多其他消息。 例如,首次创建窗口时发送 WM_CREATE,关闭窗口时发送 WM_DESTROY。 以下代码显示基本但完整的 WndProc 函数:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
       PAINTSTRUCT ps;
       HDC hdc;
       TCHAR greeting[] = _T("Hello, Windows desktop!");
    
       switch (message)
       {
       case WM_PAINT:
          hdc = BeginPaint(hWnd, &ps);
    
          // Here your application is laid out.
          // For this introduction, we just print out "Hello, Windows desktop!"
          // 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;
    }
    

生成代码

正如之前承诺的那样,下面是可正常运行的应用程序的完整代码。

生成此示例

  1. 在编辑器中删除 HelloWindowsDesktop.cpp 中的所有代码。 复制此示例代码并将其粘贴到 HelloWindowsDesktop.cpp 中

    // HelloWindowsDesktop.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("DesktopApp");
    
    // The string that appears in the application's title bar.
    static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application");
    
    // Stored instance handle for use in Win32 API calls such as FindResource
    HINSTANCE hInst;
    
    // Forward declarations of functions included in this code module:
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain(
       _In_ HINSTANCE hInstance,
       _In_opt_ HINSTANCE hPrevInstance,
       _In_ LPSTR     lpCmdLine,
       _In_ 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(wcex.hInstance, 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, IDI_APPLICATION);
    
       if (!RegisterClassEx(&wcex))
       {
          MessageBox(NULL,
             _T("Call to RegisterClassEx failed!"),
             _T("Windows Desktop Guided Tour"),
             NULL);
    
          return 1;
       }
    
       // Store instance handle in our global variable
       hInst = hInstance;
    
       // The parameters to CreateWindowEx explained:
       // WS_EX_OVERLAPPEDWINDOW : An optional extended window style.
       // 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 = CreateWindowEx(
          WS_EX_OVERLAPPEDWINDOW,
          szWindowClass,
          szTitle,
          WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, CW_USEDEFAULT,
          500, 100,
          NULL,
          NULL,
          hInstance,
          NULL
       );
    
       if (!hWnd)
       {
          MessageBox(NULL,
             _T("Call to CreateWindow failed!"),
             _T("Windows Desktop 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, Windows desktop!");
    
       switch (message)
       {
       case WM_PAINT:
          hdc = BeginPaint(hWnd, &ps);
    
          // Here your application is laid out.
          // For this introduction, we just print out "Hello, Windows desktop!"
          // 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;
    }
    
  2. “生成” 菜单上,选择 “生成解决方案” 。 编译结果显示在 Visual Studio 的“输出”窗口中。

    显示 DesktopApp 项目生成步骤的动画。

    动画显示单击“全部保存”按钮,然后从主菜单中选择“生成”>“生成解决方案”。

  3. 若要运行应用程序,请按 F5。 此时应会显示带有“Hello, Windows desktop!”文本的窗口。

    正在运行的项目的屏幕截图。它显示了标题为“Windows 桌面引导教程应用程序”的窗口。窗口的内容是“Hello,Windows 桌面版!”。

祝贺你! 你已生成了一个传统 Windows 桌面应用程序。

另请参阅

Windows C++ 桌面应用程序类型