Windows 剪贴板 编程原理学习
前言
好累,终于码完一篇字了。
进入正题吧
与AI对话
https://learn.microsoft.com/zh-cn/windows/win32/dataxchg/standard-clipboard-formats
提问是个好习惯,询问AI可以快速得到回答。
GDI 对象是什么,什么是 GDI 对象?
GDI(Graphics Device Interface,图形设备接口)对象是 Windows 操作系统中用于管理和操作图形资源的基本实体。GDI 是 Windows 提供的一组 API(应用程序编程接口),用于在屏幕上绘制图形、文本和图像,同时也用于打印和显示设备的交互。GDI 对象是这些图形操作的核心组成部分。
GDI 对象的类型
GDI 对象可以分为两大类:图形设备上下文(DC) 和 图形对象。
图形设备上下文(DC)
图形设备上下文(DC,Device Context)是一个数据结构,它封装了与绘图相关的设备信息和绘图状态。每个 DC 都包含了以下信息:
- 设备信息:描述绘图目标的设备特性,例如屏幕分辨率、颜色深度、打印机的纸张大小等。
- 绘图状态:包括当前的绘图模式、颜色映射、剪切区域、字体、画笔、画笔等。
- 绘图目标:可以是屏幕窗口、打印机、内存中的位图等。
常见的 DC 类型包括:
- 窗口设备上下文(Window DC):用于在窗口中绘图。
- 兼容设备上下文(Compatible DC):用于在内存中创建与屏幕或打印机兼容的绘图环境,常用于双缓冲绘图。
- 打印机设备上下文(Printer DC):用于打印操作。
图形对象
图形对象是用于绘图的具体资源,它们可以被选入 DC 中以完成特定的绘图任务。常见的图形对象包括:
- 画笔(Brush):用于填充图形的内部区域,例如矩形、圆形或路径。画笔可以是纯色、图案或渐变色。
- 画笔(Pen):用于绘制线条和轮廓,可以设置颜色、宽度、线型(实线、虚线等)。
- 字体(Font):用于绘制文本,可以设置字体类型、大小、样式(粗体、斜体等)。
- 位图(Bitmap):用于存储像素数据,可以用于在屏幕上显示图像或作为绘图的源数据。
- 区域(Region):用于定义复杂的剪切区域,控制绘图操作的范围。
- 路径(Path):用于定义复杂的图形轮廓,可以包含直线、曲线等。
GDI 对象的生命周期
GDI 对象的生命周期由操作系统管理,但需要程序员正确地创建和销毁。例如:
- 创建一个画笔或字体时,需要调用
CreatePen
、CreateFont
等函数。 - 使用完成后,需要调用
DeleteObject
函数释放资源,以避免资源泄漏。
GDI 对象的作用
- 封装设备特性:DC 封装了设备的绘图特性,使得应用程序可以独立于设备进行绘图操作。
- 提供绘图工具:图形对象(如画笔、字体)提供了绘图所需的工具,使得绘图操作更加灵活。
- 支持设备无关性:GDI 对象使得应用程序可以在不同的设备(如屏幕、打印机)上以一致的方式进行绘图。
- 简化编程模型:通过 GDI 对象,程序员可以使用简单的函数调用完成复杂的绘图任务。
示例代码
以下是一个简单的 C++ 示例,展示如何使用 GDI 对象在窗口中绘制图形:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); // 获取设备上下文
// 创建画笔和画刷
HPEN hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); // 红色画笔
HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 0)); // 绿色画刷
// 选入设备上下文
SelectObject(hdc, hPen);
SelectObject(hdc, hBrush);
// 绘制矩形
Rectangle(hdc, 10, 10, 100, 100);
// 释放资源
DeleteObject(hPen);
DeleteObject(hBrush);
EndPaint(hwnd, &ps);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
CF_OWNERDISPLAY
CF_OWNERDISPLAY 是一个剪贴板格式标识符,其值为 0x0080 。当使用这种格式时,它表示剪贴板的内容由剪贴板所有者(即当前拥有剪贴板数据的应用程序)直接显示和更新。
所有者显示格式 :这意味着剪贴板的内容不会以常规的数据形式存储在剪贴板中,而是由剪贴板所有者负责在剪贴板查看器窗口中进行显示和更新。
剪贴板所有者必须显示和更新剪贴板查看器窗口 :剪贴板所有者需要负责在剪贴板查看器窗口中显示剪贴板的内容,并且当内容发生变化时,及时更新该窗口。
接收消息 :剪贴板所有者需要能够接收以下几种消息,以便正确处理剪贴板查看器窗口的操作:
- WM_ASKCBFORMATNAME :当需要获取剪贴板格式的名称时,会发送此消息。
- WM_HSCROLLCLIPBOARD :当需要水平滚动剪贴板查看器窗口的内容时,会发送此消息。
- WM_PAINTCLIPBOARD :当需要绘制剪贴板查看器窗口的内容时,会发送此消息。
- WM_SIZECLIPBOARD :当需要调整剪贴板查看器窗口的大小时,会发送此消息。
- WM_VSCROLLCLIPBOARD :当需要垂直滚动剪贴板查看器窗口的内容时,会发送此消息。
hMem 参数必须为 NULL :在使用 CF_OWNERDISPLAY 格式时,传递给相关函数的 hMem 参数(通常用于指定存储剪贴板数据的内存句柄)必须为 NULL ,因为这种格式下,数据不是以常规的内存块形式存储的,而是由剪贴板所有者直接处理显示。
总之,这段内容主要描述了 CF_OWNERDISPLAY 格式的特点和要求,即剪贴板所有者需要负责显示和更新剪贴板查看器窗口,并且能够处理相关的消息,同时在使用该格式时,hMem 参数必须为 NULL。
“剪贴板所有者”指的是用户还是程序?
在 Windows 系统中,“剪贴板所有者”指的是程序,而不是用户。
解释:
剪贴板的概念:
剪贴板是操作系统提供的一种共享内存区域,用于在不同应用程序之间传递数据(例如复制、粘贴操作)。
用户通过操作(如按下 Ctrl+C 或右键选择“复制”)触发数据被复制到剪贴板,但实际管理剪贴板数据的是应用程序。
剪贴板所有者的定义:
当一个程序将数据放入剪贴板时,它就成为了剪贴板的所有者(Clipboard Owner)。
剪贴板所有者是最后一个将数据放入剪贴板的程序,它负责管理剪贴板中的数据,直到另一个程序接管剪贴板的所有权。
例如,当你在文本编辑器中复制一段文字时,这个文本编辑器程序就成为了剪贴板的当前所有者。
剪贴板所有者的职责:
如果剪贴板数据使用的是特殊格式(如 CF_OWNERDISPLAY),剪贴板所有者需要负责在剪贴板查看器中显示和更新数据。
剪贴板所有者还需要处理与剪贴板相关的消息(如 WM_PAINTCLIPBOARD、WM_HSCROLLCLIPBOARD 等)。
当程序关闭或退出时,它通常会放弃剪贴板的所有权,由系统或其他程序接管。
用户的角色:
用户是通过与程序交互(如点击、按键操作)来触发剪贴板操作的主体。
用户并不直接管理剪贴板,而是通过程序来间接操作剪贴板。
总结:
“剪贴板所有者”是指最后一个将数据放入剪贴板的程序,而不是用户。程序负责管理剪贴板数据的存储、显示和更新,而用户只是通过程序来操作剪贴板。
“剪贴板查看器窗口”指的是Win+V键弹出的窗口吗
不完全是。在 Windows 的上下文中,“剪贴板查看器窗口”(Clipboard Viewer Window)是一个比较古老的概念,主要用于传统的剪贴板查看机制,而不是我们熟悉的 Win+V 弹出的“剪贴板历史”窗口。
- 传统的剪贴板查看器
在早期的 Windows 系统中(如 Windows 95、Windows XP 等),剪贴板查看器是一个独立的工具,通常可以通过“剪贴板查看器”程序(clipbrd.exe)启动。
它的作用是显示当前剪贴板的内容,支持多种格式(如文本、图像等)。应用程序可以通过发送消息(如 WM_PAINTCLIPBOARD)来更新剪贴板查看器中的内容。
这种机制主要用于开发人员调试剪贴板功能,或者在应用程序之间共享复杂的数据格式。 - Win+V 的“剪贴板历史”窗口
Win+V 弹出的窗口是 Windows 10 及更高版本中引入的“剪贴板历史”功能。它是一个现代化的剪贴板管理工具,用于存储和管理用户复制的多个历史记录。
它与传统的剪贴板查看器不同,因为它:
不依赖于传统的剪贴板查看机制。
不需要应用程序直接与剪贴板查看器窗口交互。
支持跨设备同步(通过 Windows 设置中的“剪贴板历史”功能)。
是一个系统级的全局功能,而不是一个独立的工具。 - 区别总结
传统剪贴板查看器:
用于显示当前剪贴板的内容。
需要应用程序直接与查看器窗口交互(如处理 WM_PAINTCLIPBOARD 消息)。
主要用于开发调试或特定应用程序之间的数据共享。
Win+V 的剪贴板历史:
用于存储和管理用户的剪贴板历史记录。
不需要应用程序直接与查看器窗口交互。
是一个系统级功能,用户可以手动粘贴历史记录。 - CF_OWNERDISPLAY 的关联
CF_OWNERDISPLAY 格式与传统的剪贴板查看器机制相关。它要求剪贴板所有者直接绘制和更新剪贴板查看器窗口的内容。这种机制在现代 Windows 系统中已经不常用,但在某些特定的开发场景中仍然可能会遇到。
如果你在开发中遇到 CF_OWNERDISPLAY,它通常与传统的剪贴板查看器窗口相关,而不是 Win+V 的剪贴板历史功能。
ANSI和ASCII的区别是?
ANSI 和 ASCII 的区别主要体现在以下几个方面:
1. 编码范围
- ASCII:
- ASCII(美国信息交换标准代码)是一种基于英文字符的编码标准,使用7位二进制数表示字符,共有128个字符,包括大小写英文字母、数字0-9以及一些控制字符和标点符号。
- ANSI:
- ANSI 是一种扩展的字符编码标准,通常指 Windows 系统中的代码页(如 CP1252)。它使用8位二进制数(即1字节)表示字符,可以表示256个字符。ANSI 在 ASCII 的基础上增加了对欧洲语言字符的支持,如带重音符号的字符等。
2. 用途
- ASCII:
- 主要用于英文字符的表示,是最早被广泛使用的字符编码标准之一,在早期计算机系统和网络通信中占据重要地位。
- ANSI:
- 主要用于支持多种语言的字符表示,尤其是在 Windows 系统中,ANSI 是默认的字符编码,用于处理本地语言环境下的文本。
3. 兼容性
- ASCII:
- ASCII 是一种基础编码,几乎所有现代计算机系统和软件都支持 ASCII 编码。
- ANSI:
- ANSI 是一种扩展编码,其兼容性取决于具体的代码页。不同地区和语言环境可能使用不同的 ANSI 代码页,因此在跨语言或跨平台传输时可能会出现乱码问题。
4. 示例
- ASCII:
- 字符 "A" 的 ASCII 编码是 65(十进制)或 0x41(十六进制)。
- ANSI:
- 字符 "é" 在 ANSI 编码(如 CP1252)中是 233(十进制)或 0xE9(十六进制),而在 ASCII 中没有这个字符。
人类总结:ANSI ==> 本地编码(不得不提chcp 65001)
剪贴板设置函数
https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-setclipboarddata
剪贴板格式: https://learn.microsoft.com/zh-cn/windows/win32/dataxchg/clipboard-formats
可以程序注册,可以使用标准自带的,可以放入多个不同格式的剪贴内容。
或者看这个图可以看得出来到底有多少东西。
另外也就是这起名千奇百怪。
罢了罢了。