独钓寒江雪

用C++的优雅,驯服Windows的狂野

Wireshark 中有两种过滤器:

  • 捕获过滤器:用于在数据包捕获阶段过滤数据包,只捕获符合条件的数据包,这样可以减少捕获不必要的数据包,从而提高性能。
  • 显示过滤器:用于在已经捕获的数据包中过滤出符合条件的数据包进行显示,它使用的是 Wireshark 自己的语法。

捕获过滤器

在 Wireshark 的开始页面或者在捕获选型页面中选择需要捕获的网络适配器,然后输入捕获过滤器规则,设置完成之后,点击“开始”按钮即可使用该规则在对应适配器上进行网络流量抓取。

阅读全文 »

CMake 是一个开源、跨平台的构建系统生成器(Build-system Generator)。

本文是 Modern CMake 简明教程系列的下篇,上篇请移步至 《Modern CMake 简明教程(上)》,中篇请移步至 《Modern CMake 简明教程(中)》

本教程默认 CMake 最低版本为 3.16,即 cmake_minimum_required(VERSION 3.16)

集成第三方库

在项目中集成第三方库是一种非常常见的需求,CMake 提供了两种方式来集成第三方库。

第一种:直接集成第三方库的源码。

说到集成第三方库的源码,我们第一时间想到的可能就是将其源码直接拷贝到项目目录中,然后提交到 git 仓库,更加高级一点可能会使用 git submodule 的方式。但我以为这两种方式都不够优雅,无法很好的管理、更新依赖库,特别是在项目的依赖库的比较多时。

CMake 提供了两个模块(两种方式)来集成第三方库的源码:

  • FetchContent
    该模块支持在 CMake 生成项目时就下载第三方库,还会自动将第三方库添加到项目中,不需要手动调用 add_subdirectory。
  • ExternalProject
    该模板支持在构建(编译)项目时下载第三方库。显然 ExternalProject 的下载时机要晚于 FetchContent 。

第二种:使用预编译好的第三方库。

这种方式需要先单独编译安装第三方库,然后使用 find_package 查找该库,最后设置目标的相关属性,如包含目录、依赖库等。

阅读全文 »

CMake 是一个开源、跨平台的构建系统生成器(Build-system Generator)。

本文是 Modern CMake 简明教程系列的中篇,上篇请移步 《Modern CMake 简明教程(上)》

本教程默认 CMake 最低版本为 3.16,即 cmake_minimum_required(VERSION 3.16)

生成器表达式

不知你是否思考过这样一个问题:我们在编译项目时,通常有不同的配置,如 Debug 和 Release,如何在不同的配置中定义不同的预编译宏、包含不同的目录、依赖不同的库呢?

其实要解决这个问题,并不困难,只需要使用到 CMake 中的 生成器表达式。我们在开源项目的 CMake 脚本中经常看到的 $<...> 这样的表达式就是生成器表达式,但通常都会嵌套使用,如 $<$<...>:...>

生成器表达式通常有下面几种形式:

  • $<condition:true_string>
  • $<IF:condition,true_string,false_string>
  • $<BOOL:string>
  • 特定的语法形式,如 $<CONFIG:cfgs> 表示当前配置存在于 cfgs 列表中时,表达式结果为 1,否则为 0。

前三种形式比较简单,最后一种形式虽然有多种类型,但我们通常只需要记忆几种常用的,有需要时查阅官方文档

阅读全文 »

CMake 是一个开源、跨平台的构建系统生成器(Build-system Generator)。

CMake 是构建系统生成器,而不是构建系统,CMake 支持生成不同构建系统所支持的工程文件,如 Visual Studio,XCode,Makefile 等。

本教程作为 CMake 的简明教程,不会事无巨细的讲述 CMake 的每一个语法,而是以实用为目的,介绍 CMake 的基础语法和常用指令。

虽然只是简明教程,但通过本教程,你仍然可以掌握 CMake 的脉络,熟练应用 CMake 于项目中。

Modern CMake

CMake 距今已有 20 多年的历史,CMake 从 3.0 开始引入 Target 概念,有了 Target 和 Property 的定义,CMake 也就更加地现代化。

我们将引入 Target 概念之前(也就是 3.0 之前)的 CMake 称之为老式 CMake,之后的称之为现代 CMake(Modern CMake)。

现代 CMake 是围绕 Target 和 Property 来定义的,在现代 CMake 中不应该出现诸如下面的指令:

  • add_compile_options
  • include_directories
  • link_directories
  • link_libraries

因为这些指令都是目录级别的,在该目录(含子目录)上定义的所有目标都会继承这些属性,这样会导致出现很多隐藏依赖和多余属性的情况。

我们最好直接针对 Target 进行操作,如:

1
2
3
4
5
6
7
add_executable(hello main.cpp)

# 老式写法
include_directories(./include)

# 现代写法
target_include_directories(hello PRIVATE ./include)

本文讲述的知识点只适用于现代 CMake,让我们脱掉沉重的历史包袱,轻装上阵吧!

阅读全文 »

当你点击桌面图标,一个窗口缓缓展开;滚动网页时,文字与图片在屏幕上丝滑游走;打开绘图软件,笔触落下的瞬间,色彩便在虚拟画布上晕染开来——这些习以为常的界面交互,构成了我们与数字世界对话的桥梁。但你是否想过:这些“理所当然”的视觉体验,究竟是如何从代码的海洋里“生长”出来的?窗口的轮廓如何被精准勾勒?色彩与线条怎样穿越硬件与系统的边界,最终跃入人眼?

Windows图形编程的核心骨架

在深入探索Windows图形编程之前,让我们先了解一个最基本的Windows窗口程序骨架。这个骨架程序包含了创建窗口、处理消息和基本绘图的全部要素:

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
#include <Windows.h>

// 声明窗口过程函数
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

// 程序入口点
int WINAPI WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow) {
// 1. 注册窗口类
const wchar_t CLASS_NAME[] = L"SampleWindowClass";

WNDCLASSEX wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX); // 结构体大小
wcex.lpfnWndProc = WindowProc; // 窗口过程函数
wcex.hInstance = hInstance; // 程序实例句柄
wcex.lpszClassName = CLASS_NAME; // 窗口类名
wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // 光标样式
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 窗口背景

RegisterClassEx(&wcex);

// 2. 创建窗口
HWND hwnd = CreateWindowEx(
0, // 扩展样式
CLASS_NAME, // 窗口类名
L"Windows图形编程示例", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口样式

// 位置和大小
CW_USEDEFAULT, CW_USEDEFAULT,
800, 600,

NULL, // 父窗口
NULL, // 菜单
hInstance, // 实例句柄
NULL // 附加数据
);

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

// 3. 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// 4. 消息循环
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return (int)msg.wParam;
}

// 窗口过程函数
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);

// 在这里添加绘图代码
// 例如: TextOut(hdc, 50, 50, L"Hello, Windows!", 15);

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

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

这个基础程序包含了Windows图形编程的核心要素:

  1. ​WinMain入口点​ - Windows GUI应用程序的起点
    ​2. 窗口类注册​ - 定义窗口的基本特性
    ​3. 窗口创建​ - 根据注册的类创建窗口实例
  2. ​消息循环​ - Windows程序的心脏,负责接收和分发系统发送给窗口的各种消息
    ​5. 窗口过程函数​ - 可以在此处理发送到窗口的所有消息

接下来,我们将深入探讨Windows窗口创建和图形绘制的各个方面。

阅读全文 »

以前嵌入脚本首选Lua,但有些年头没有用Lua了,语法也快忘记光了,这些年倒是对 JavaScript 语法愈发熟悉了,于是想看看有没有小巧的 JavaScript 引擎,可以嵌入到 C++程序中使用。嘿,还真有。花时间研究了下 JerryScript 库,也顺手给 JerryScript 提交了几个 PR 被采纳了,有幸成为顶级项目的 Contributor(就是玩儿 ^_^)。

JerryScript 是一个轻量级的 JavaScript 引擎,资源占用极少,它可以运行在资源受限制的设备上,如:

  • 只有几 KB RAM 能运行引擎的设备(<64 KB RAM)
  • 只能为代码引擎提供有限 ROM 空间的设备(<200 KB ROM)

JerryScript 使用 C 语言开发,跨平台。

阅读全文 »

在Windows系统中,F12永远为调试器所预留,不能被用来注册为快捷键,如我们通常使用F12打开浏览器的调试工具。即便当前未调试应用程序,如果内核模式调试器或实时调试器有驻留,F12也会被预留。

详见:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646309.aspx

可以通过修改注册表来指定其他的按键作为调试器预留快捷键:

1
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug] UserDebuggerHotKey=dword:00000000

比如0x13 (Pause键)。

在讲述柔性数组(Flexible Array)之前,首先要介绍一下不完整类型 (Incomplete Type)。不完全类型是暂时没有完全定义好的类型,缺乏足够的信息(例如长度、类型)去描述一个完整的类型。在C/C++中不完全类型有三种不同形式:void、未指定长度的数组以及具有非指定内容的结构和类。

阅读全文 »

打开任何一个数字证书售卖网站都可以看到它们通常将数字证书分为两个大类:SSL证书和数字签名证书。

SSL证书的主要作用是对网站进行身份验证和传输数据加密;

数字签名主要用于验证信息的真实性和完整性,根据使用场景的不同大致分为如下几类:

  • 对客户端程序(.exe、.dll、.sys等文件)签名的代码签名证书。
  • 对PDF等文档签名的文档签名证书。
  • 对电子邮件及其附件签名和加密的邮件安全证书。
阅读全文 »
0%