前言

如果要创建一个窗口程序而不是命令行程序,在 Windows 平台上使用 Win32 API 是一个比较经典的方法,这样的窗口程序就是 Win32 程序。

而 Win32 程序只能在 Windows 上运行,所以选择 Microsoft 提供的官方 IDE (Visual Studio)是一个很好的选择。虽然这个 IDE 确实很厉害,但仍旧有很多人并不喜欢使用它。

本文就来介绍一下使用 CMake 创建一个 Win32 程序的方法。

一、工具链

虽然你可能不喜欢用 Visual Studio 这个 IDE,但是我们仍然需要安装它,或者是另一个更好的选择,即安装【Visual Studio 生成工具】,这个软件其实和 Visual Studio 是一样的,但它不会安装代码编辑器。具体的安装方法此处并不提供,总之和安装 Visual Studio 一样选择【使用 C++ 的桌面开发】负载即可。

这个负载中对我们来说最重要的是【Windows SDK】、【MSVC 生成工具】这两个部分。其中【Windows SDK】对于 Win32 程序来说是必要的。

但【MSVC 生成工具】则并非必要的,它只是个编译链接调试的工具,我们也可以使用 MinGW 这些工具链,但其相对于直接使用【MSVC 生成工具】会麻烦很多,所以推荐还是使用【MSVC 生成工具】,毕竟也是官方的工具,肯定支持性也更好。

二、Win32 程序

我们直接使用 Microsoft 在 Win32 编程指导中给出的程序作为我们的示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";

WNDCLASS wc = { };

wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);

// Create the window.

HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style

// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);

if (hwnd == NULL)
{
return 0;
}

ShowWindow(hwnd, nCmdShow);

// Run the message loop.

MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

// All painting occurs here, between BeginPaint and EndPaint.

FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));

EndPaint(hwnd, &ps);
}
return 0;

}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

三、CMake 配置

基本和生成命令行程序相同,但需要在具体的生成语句中添加WIN32这个标识:

1
2
3
4
5
6
cmake_minimum_required(VERSION 3.27)
project(Win32Test)

set(CMAKE_CXX_STANDARD 11)

add_executable(Win32Test WIN32 main.cpp) # 在中间添加 WIN32 标识

使用 CMake 进行构建的命令也依然和命令行程序基本相同,但前提是使用 MSVC 作为工具链。

四、正常输出

按照上面的配置进行之后,如果一切正常,那么将直接显示下面的窗口:

01