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

本演练介绍如何在 Visual Studio 中创建传统的 Windows 桌面应用程序。 你创建的应用程序使用 Windows API 在窗口中显示 Hello、Windows 桌面! 。 可以将在本演练中开发的代码作为模式来创建 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 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 中“新建项目”对话框的屏幕截图,其中突出显示了 Win32 Project 选项,并在“名称”文本框中键入了 DesktopApp。

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

    Visual Studio 2015 中显示“Win32 应用程序向导概述”页的对话框的屏幕截图。

  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 宏,如果在项目中定义了 wchar_t 符号,则该宏最终解析为 UNICODE,否则解析为 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. 要处理应用程序收到的消息,可以在 switch 函数中实现 WndProc 语句。

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

    要处理 WM_PAINT 消息,请首先调用 BeginPaint,然后处理所有的逻辑以在窗口中布局文本、按钮和其他控件。 然后调用 EndPaint。 对于此应用程序,BeginPaint()EndPaint() 之间的代码会在你在 Hello, Windows desktop! 中创建的窗口中显示 WinMain()。 在以下代码中,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 桌面引导教程应用程序的窗口的屏幕截图。窗口的内容是 你好,Windows 桌面!

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

另请参阅