- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C++开发截屏小程序功能由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
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 。
最后此篇关于C++开发截屏小程序功能的文章就讲到这里了,如果你想了解更多关于C++开发截屏小程序功能的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在构建一个 RCP 应用程序,其中每个季度都会更新功能/插件。因此,如果用户选择自动更新功能/插件,则会下载更新插件的新 jar,但旧插件仍在使用我不再使用的磁盘空间。 我厌倦了删除包含旧 jar
我如何从外部 Controller 功能中调用 Controller 内部的功能,例如电话间隙回调功能 这是 Controller 外部定义的功能 function onDeviceReady()
如果某个功能(例如 MediaSource)可用,我如何使用 Google Dart 检查。 new MediaSource() 抛出一个错误。如何以编程方式检查此类或功能是否存在?有任何想法吗?是否
我正在尝试运行 Azure Orchestrations,突然我开始从 statusQueryGetUri 收到错误: 协调器函数“UploadDocumentOrchestrator”失败:函数“U
我见过 iPhone 上的应用程序,如果在 3.0 上运行,将使用 3.0 功能/API,例如应用内电子邮件编辑器,如果在 2.x 上运行,则不使用这些功能,并退出应用程序以启动邮件相反。 这是怎么做
这是 DB 规范化理论中的一个概念: Third normal form is violated when a non-key field is a fact about another non-ke
如果我定义 #if SOMETHING #endif 而且我还没有在任何地方定义 SOMETHING。 #if 中的代码会编译吗? 最佳答案 当#if的参数表达式中使用的名称未定义为宏时(在所有其他宏
我刚刚澄清了 A* 路径查找应该如何在两条路径具有相等值的 [情况] 下运行,无论是在计算期间还是在结束时,如果有两条相等的短路径。 例如,我在我的起始节点,我可以扩展到两个可能的节点,但它们都具有相
Java有没有类似下面的东西 宏 一种遍历所有私有(private)字段的方法 类似于 smalltalk symbols 的东西——即用于快速比较静态字符串的东西? 请注意,我正在尝试为 black
这个程序应该将华氏度转换为摄氏度: #include int main() { float fahrenheit, celsius; int max, min, step;
当打开PC缓存功能后, 软件将采用先进先出的原则排队对示波器采集的每一帧数据, 进行帧缓存。 当发现屏幕中有感兴趣的波形掠过时, 鼠标点击软件的(暂停)按钮, 可以选择回看某一帧的波形
我有一个特殊的(虚拟)函数,我想在沙盒环境中使用它: disable.system.call eval(parse(text = 'model.frame("1 ~ 1")'), envir = e
使用新的 Service 实现,我是否必须为我的所有服务提供一个 Options 方法? 使用我的所有服务当前使用的旧 ServiceBase 方法,OPTIONS 返回 OK,但没有 Access-
我正在阅读 Fogus 的关于 Clojure 的喜悦的书,在并行编程章节中,我看到了一个函数定义,它肯定想说明一些重要的事情,但我不知道是什么。此外,我看不到这个函数有什么用 - 当我执行时,它什么
我有大量的 C 代码,大部分代码被注释掉和/或 #if 0。当我使用 % 键匹配 if-else 的左括号和右括号时,它也匹配注释掉的代码。 有没有办法或vim插件在匹配括号时不考虑注释掉或#if 0
我有这个功能: map(map(fn x =>[x])) [[],[1],[2,3,4]]; 产生: val it = [[],[[1]],[[2],[3],[4]]] 我不明白这个功能是如何工作的。
我使用 Visual Studio 代码创建了一个函数应用程序,然后发布了它。功能应用程序运行良好。我现在在功能门户中使用代码部署功能(KUDU)并跳过构建。下面是日志 9:55:46 AM
我有一个数据框df: userID Score Task_Alpha Task_Beta Task_Charlie Task_Delta 3108 -8.00 Easy Easy
我真的无法解决这个问题: 我有一个返回数据框的函数。但是,数据框仅打印在我的控制台中,尽管我希望将其存储在工作空间中。我怎样才能做到这一点? 样本数据: n <- 32640 t <- seq(3*p
有没有办法找出所有可能的激活器命令行选项? activator -help仅提供最低限度的可用选项/功能列表,但所有好的东西都隐藏起来,即使在 typesafe 网站在线文档中也不可用。 到目前为止,
我是一名优秀的程序员,十分优秀!