最近更新于 2024-05-05 14:18
环境
Windows 11 专业工作站版 22H2
Visual Studio 2022 专业版
使用 Unicode 字符集,C17 标准编译,64 位编译
代码
/**
* @file screenshot.c
* @author IYATT-yx
* @brief Windows 截图
* @version 0.1
* @data 2023.2.1
* @details
* 使用:
* 运行后,鼠标左键按下然后拖动选择截图范围,放开鼠标截图到剪切板
* 按 Esc 退出截图界面
*
* 开发环境: Windows 11 专业工作站版 22H2
* Visual Studio 2022 专业版
* 使用 Unicode 字符集
* C17 标准,64 位编译
*/
#include <Windows.h>
int g_screen_width, g_screen_height; // 保存屏幕分辨率
HDC g_memory_DC; // 用于存放图像
RECT g_rect; // 矩形区域,用于存放选择框的位置信息
/**
* @brief 捕捉整个桌面的图像
*/
void capture_desktop()
{
HDC display_DC = CreateDC(L"DISPLAY", NULL, NULL, NULL); // 为主显示设备创建设备描述表
g_screen_width = GetDeviceCaps(display_DC, HORZRES); // 获取屏幕宽度
g_screen_height = GetDeviceCaps(display_DC, VERTRES); // 获取屏幕高度
g_memory_DC = CreateCompatibleDC(display_DC); // 创建显示设备的内存 DC
HBITMAP hCanvas = CreateCompatibleBitmap(display_DC, g_screen_width, g_screen_height); // 创建与显示设备关联的位图用作画布
SelectObject(g_memory_DC, hCanvas); // 将放入内存 DC 的内存中
BitBlt(g_memory_DC, 0, 0, g_screen_width, g_screen_height, display_DC, 0, 0, SRCCOPY); // 将屏幕显示的内容拷贝到内存 DC 中
}
/**
* @brief 将数据拷贝到剪切板
*/
void copy_bitmap_to_clipboard()
{
HDC display_DC = CreateDC(L"DISPLAY", NULL, NULL, NULL);
int width = g_rect.right - g_rect.left;
int height = g_rect.bottom - g_rect.top;
HDC memory_DC = CreateCompatibleDC(display_DC);
HBITMAP hCanvas = CreateCompatibleBitmap(display_DC, width, height);
HBITMAP hOldMap = SelectObject(memory_DC, hCanvas);
BitBlt(memory_DC, 0, 0, width, height, display_DC, g_rect.left, g_rect.top, SRCCOPY);
HBITMAP hNewMap = SelectObject(memory_DC, hOldMap);
OpenClipboard(NULL); // 打开剪切板
EmptyClipboard(); // 清空剪切板
SetClipboardData(CF_BITMAP, hNewMap); // 将位图数据拷贝到剪切板
CloseClipboard(); // 关闭剪切板
}
LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE: // 窗口创建前
{
capture_desktop();
break;
}
case WM_LBUTTONDOWN: // 鼠标左键按下
{
POINT pt;
GetCursorPos(&pt); // 获取鼠标光标的位置
g_rect.left = pt.x;
g_rect.top = pt.y;
g_rect.right = pt.x;
g_rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, TRUE); // 有更新内容就发送绘图消息
break;
}
case WM_LBUTTONUP: // 鼠标左键放开
{
POINT pt;
GetCursorPos(&pt);
g_rect.right = pt.x;
g_rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, TRUE);
copy_bitmap_to_clipboard();
break;
}
case WM_PAINT: // 绘图
{
LOGPEN pen;
pen.lopnColor = RGB(255, 0, 0); // 截图选择框的颜色 - 红
pen.lopnStyle = PS_SOLID; // 截图选择框的线型 - 实线
pen.lopnWidth = (POINT){2, 2}; // 截图框的线宽
HPEN hPen = CreatePenIndirect(&pen); // 画笔,用于绘制图
LOGBRUSH brush;
brush.lbStyle = BS_NULL;
HBRUSH hBrush = CreateBrushIndirect(&brush); // 画刷,同于填充图形内部
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps); // 开始绘图
HGDIOBJ hOldBrush = SelectObject(hdc, hBrush); // 切换画刷
HGDIOBJ hOldPen = SelectObject(hdc, hPen); // 切换画笔
BitBlt(hdc, 0, 0, g_screen_width, g_screen_height, g_memory_DC, 0, 0, SRCCOPY); // 从内存 DC 中复制捕捉的图像数据到窗口中
Rectangle(hdc, g_rect.left, g_rect.top, g_rect.right, g_rect.bottom); // 绘制图像选择框
SelectObject(hdc, hOldBrush); // 换回默认画刷
SelectObject(hdc, hOldPen); // 换回默认画笔
EndPaint(hWnd, &ps); // 结束绘图
break;
}
case WM_CLOSE: // 点击关闭按钮
{
DestroyWindow(hWnd);
break;
}
case WM_KEYDOWN: // 按 Esc 退出
{
if (wParam == 27)
{
PostMessage(hWnd, WM_CLOSE, 0, 0); // 发送退出信号
}
break;
}
case WM_DESTROY: // 窗口销毁后
{
PostQuitMessage(0); // 退出消息循环
break;
}
default:
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
return 0;
}
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPreHinstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
// 注册窗口类
PCWSTR szClassName = L"Desktop";
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
wc.lpszClassName = szClassName;
wc.hCursor = LoadCursor(NULL, IDC_CROSS); // 鼠标光标设置为十字键头
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"注册窗口失败!", L"错误", MB_OK);
return 1;
}
// 创建窗口 - WS_POPUP 弹出窗口,没有标题栏
HWND hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, szClassName, L"截图", WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL, L"创建窗口失败", L"错误", MB_OK);
return 1;
}
// 显示窗口
ShowWindow(hWnd, SW_MAXIMIZE); // 设置最大化显示
UpdateWindow(hWnd);
// 消息循环
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
按下左键拉动选择截图范围,放开左键拷贝到剪切板
Windows 截图简单实现 – Windows API