C++开发截屏小程序,Win32程序,可以显示截屏区域并保存。
上次的流星雨屏幕程序就简单涉及到GDI绘图了,这次简单介绍几个API函数,涉及到GDI的。
GetDC,获取当前创建的窗口的设备环境。
CreateDC,获取当前屏幕的设备环境。
CreateCompatibleDC,创建一个兼容性的设备环境(相当于一个虚拟的设备环境)
BitBlt,这个函数,相当于拷贝,将一个环境的设备内容拷贝到另一个设备中。
CreateCompatibleBitmap,创建一块画布,将其放在兼容性的DC里面,这样就可以在里面画图了,当然还要放入画笔和画刷这些。
介绍完这些函数之后,那么设计思路就来了:
1.首先当然还是定义并创建窗口,还有消息循环。
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
82
83
84
|
ATOM MyRegisterClass( HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof (WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDC_CAPTURESCREEN));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = ( HBRUSH )(BLACK_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance( HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中
//创建自己的窗口
hWnd = CreateWindow(szWindowClass, szTitle, WS_POPUP,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
//显示和更新窗口
ShowWindow(hWnd, SW_MAXIMIZE);
UpdateWindow(hWnd);
return TRUE;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
//playsound只能播放wav格式,而mcisendstring可以播放任意格式的。
//PlaySound("yixi.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
mciSendString( "open ./abc.mp3 alias bk" ,
0, 0, 0);
mciSendString( "play bk repeat" , 0, 0, 0);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CAPTURESCREEN, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance); //注册类
// 执行应用程序初始化:
if (!InitInstance(hInstance, nCmdShow)) //初始化窗口
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CAPTURESCREEN));
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return ( int )msg.wParam;
}
|
2.之后获取当前屏幕的设备环境,
3.然后将它保存到兼容性的DC中,这就相当于将当前屏幕图片放到一个缓冲区中。在WM_CREATE
消息里面做这个动作。
1
2
3
4
5
6
7
8
9
10
|
void ScreenDisplay()
{
HDC disDc = ::CreateDC( "DISPLAY" , NULL, NULL, NULL);
g_memDC = ::CreateCompatibleDC(disDc);
g_ScreenW = GetDeviceCaps(disDc, HORZRES);
g_ScreenH = GetDeviceCaps(disDc, VERTRES);
HBITMAP hbitmap = CreateCompatibleBitmap(disDc, g_ScreenW, g_ScreenH);
SelectObject(g_memDC, hbitmap);
BitBlt(g_memDC, 0, 0, g_ScreenW, g_ScreenH, disDc, 0, 0, SRCCOPY);
}
|
4.接着再将它放到我们创建的窗口中,这时就会看到整个桌面就不动了,就呈现的是一张图片,
5.之后我们就可以在这张图片上绘制我们想截取的区域。
6.呈现的是静止的图片,如果绘制之后,需要更新,这就用到一个函数InvalidateRgn
,会无效选定的区域,这样会触发消息WM_PAINT,所以在这个消息里面将重新绘制图形,然后显示即可。
1
2
3
4
5
6
7
8
9
|
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
SelectObject(hdc, hpen);
SelectObject(hdc, hBrush);
BitBlt(hdc, 0, 0, g_ScreenW, g_ScreenH, g_memDC, 0, 0, SRCCOPY);
Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
EndPaint(hWnd, &ps);
break ;
|
接下来就是绘制想要区域的操作,需要用到的几个鼠标的消息函数,鼠标按下,鼠标弹起,鼠标移动,鼠标双击。
那么思路来了:
鼠标按下,确定左上角的点,然后鼠标移动绘制矩形区域,然后鼠标弹起,确定右下角的点,这样矩形区域绘制完成。
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
|
case WM_LBUTTONDOWN:
{
if (!Iselect)
{
POINT pt;
GetCursorPos(&pt);
rect.left = pt.x;
rect.top = pt.y;
rect.right = pt.x;
rect.bottom = pt.x;
InvalidateRgn(hWnd, 0, FALSE);
Isdowmn = TRUE;
}
}
break ;
case WM_LBUTTONUP:
{
if (Isdowmn == TRUE&&!Iselect)
{
POINT pt;
GetCursorPos(&pt);
rect.right = pt.x;
rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, FALSE);
Isdowmn = FALSE;
Iselect = TRUE;
}
}
break ;
case WM_MOUSEMOVE:
{
if (Isdowmn == TRUE&&!Iselect)
{
POINT pt;
GetCursorPos(&pt);
rect.right = pt.x;
rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, FALSE);
}
}
break ;
|
最后鼠标双击将截取到的图片保存剪切板,这样就完成了屏幕截取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
case WM_LBUTTONDBLCLK:
if (Iselect == TRUE)
{
int iNum = MessageBox(hWnd, "截图成功!" , "张一西" , MB_OKCANCEL | MB_ICONINFORMATION);
if (iNum == 1)
{
CopyToCliboard();
Iselect = FALSE;
PostQuitMessage(0);
}
else
{
Iselect = FALSE;
}
}
break ;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void CopyToCliboard()
{
HDC hScreenDC = ::CreateDC( "DISPLAY" , 0, 0, 0);
HDC memDC = ::CreateCompatibleDC(hScreenDC);
int Width = rect.right - rect.left-2;
int Height = rect.bottom - rect.top-2;
HBITMAP hBmap = CreateCompatibleBitmap(hScreenDC, Width, Height);
HBITMAP hOldBmap = ( HBITMAP )SelectObject(memDC, hBmap);
BitBlt(memDC, 0, 0, Width, Height, hScreenDC, rect.left+1, rect.top+1, SRCCOPY);
HBITMAP hNewBmap = ( HBITMAP )SelectObject(memDC, hOldBmap);
if (OpenClipboard(0)) //打开粘贴板
{
EmptyClipboard(); //清空粘贴板
SetClipboardData(CF_BITMAP, hNewBmap); //把图片放入粘贴板
CloseClipboard(); //关闭粘贴板
}
}
|
总结
到此这篇关于C++开发截屏小程序的文章就介绍到这了,更多相关C++开发截屏小程序内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/qq_34430371/article/details/105170709