C++程序调用SetWindowsHookEx全局拦截键盘按键消息和窗口消息的Hook实例分享

目录

1、Hook与Hook过程函数

2、SetWindowsHookEx函数说明

3、Hook实例1 - 使用SetWindowsHookEx在程序中拦截键盘消息

4、Hook实例2 - 使用SetWindowsHookEx在程序中拦截某个窗口的消息

5、最后


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(专栏文章已更新400多篇,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlC++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html       本文详细介绍一下可以给应用程序挂Hook钩子的系统API函数SetWindowsHookEx,并给出两个项目中使用的实例,以供大家借鉴和参考。

1、Hook与Hook过程函数

       Hook是应用程序截获消息、鼠标操作和击键等事件的机制。截获特定类型的事件的函数称为Hook过程函数。在Hook过程函数中,可以对其接收的每个事件执行操作,然后修改或放弃该事件。

       Windows系统支持许多不同类型的Hook,每种类型都提供对其消息处理机制的不同方面的访问,可以为一个类型的Hook指定一个Hook过程函数。比如,应用程序可以使用Hook类型WH_MOUSE来监视鼠标消息,在对应的Hook过程函数中处理拦截到的消息。

       可以通过调用 SetWindowsHookEx 函数并指定调用该过程的挂钩类型来安装挂钩过程,该过程是应与调用线程位于同一桌面中的所有线程相关联,还是与特定线程相关联,以及指向过程入口点的指针。

2、SetWindowsHookEx函数说明

       SetWindowsHookEx 是用于在Windows操作系统中设置全局或本地的钩子(hook)。钩子是一种用于监视并拦截特定事件或消息的机制,通常用于拦截和处理键盘输入、鼠标操作、窗口消息等。SetWindowsHookEx 允许你安装一个全局或本地的钩子过程,以便在事件发生时执行自定义的代码。

      SetWindowsHookEx的声明如下:

HOOK SetWindowsHookEx([in] int       idHook,[in] HOOKPROC  lpfn,[in] HINSTANCE hmod,[in] DWORD     dwThreadId
);

参数说明:

1)idHook:指定要安装的钩子类型。可以是以下之一:

含义

WH_CALLWNDPROC

4

安装一个挂钩过程,用于在系统将消息发送到目标窗口过程之前监视消息。 有关详细信息,请参阅 CallWndProc 挂钩过程。

WH_CALLWNDPROCRET

12

安装一个挂钩过程,该过程在目标窗口过程处理消息后监视消息。 有关详细信息,请参阅 [HOOKPROC 回调函数] (nc-winuser-hookproc.md) 挂钩过程。

WH_CBT

5

安装用于接收对 CBT 应用程序有用的通知的挂钩过程。 有关详细信息,请参阅 CBTProc 挂钩过程。

WH_DEBUG

9

安装可用于调试其他挂钩过程的挂钩过程。 有关详细信息,请参阅 DebugProc 挂钩过程。

WH_FOREGROUNDIDLE

11

安装将在应用程序的前台线程变为空闲状态时调用的挂钩过程。 此挂钩可用于在空闲时间执行低优先级任务。 有关详细信息,请参阅 ForegroundIdleProc 挂钩过程。

WH_GETMESSAGE

3

安装用于监视发布到消息队列的消息的挂钩过程。 有关详细信息,请参阅 GetMsgProc 挂钩过程。

WH_JOURNALPLAYBACK

1

 警告

Windows 11及更新版本:不支持日记挂钩 API。 建议改用 SendInput TextInput API。

安装一个挂钩过程,该过程发布以前由 WH_JOURNALRECORD 挂钩过程记录的消息。 有关详细信息,请参阅 JournalPlaybackProc 挂钩过程。

WH_JOURNALRECORD

0

 警告

Windows 11及更新版本:不支持日记挂钩 API。 建议改用 SendInput TextInput API。

安装一个挂钩过程,用于记录发布到系统消息队列的输入消息。 此挂钩可用于记录宏。 有关详细信息,请参阅 JournalRecordProc 挂钩过程。

WH_KEYBOARD

2

安装用于监视击键消息的挂钩过程。 有关详细信息,请参阅 KeyboardProc 挂钩过程。

WH_KEYBOARD_LL

13

安装用于监视低级别键盘输入事件的挂钩过程。 有关详细信息,请参阅 [LowLevelKeyboardProc] (/windows/win32/winmsg/lowlevelkeyboardproc) 挂钩过程。

WH_MOUSE

7

安装监视鼠标消息的挂钩过程。 有关详细信息,请参阅 MouseProc 挂钩过程。

WH_MOUSE_LL

14

安装用于监视低级别鼠标输入事件的挂钩过程。 有关详细信息,请参阅 LowLevelMouseProc 挂钩过程。

WH_MSGFILTER

-1

安装挂钩过程,用于监视由于对话框、消息框、菜单或滚动条中的输入事件而生成的消息。 有关详细信息,请参阅 MessageProc 挂钩过程。

WH_SHELL

10

安装一个挂钩过程,用于接收对 shell 应用程序有用的通知。 有关详细信息,请参阅 ShellProc 挂钩过程。

WH_SYSMSGFILTER

6

安装挂钩过程,用于监视由于对话框、消息框、菜单或滚动条中的输入事件而生成的消息。 挂钩过程监视与调用线程位于同一桌面中的所有应用程序的消息。 有关详细信息,请参阅 SysMsgProc 挂钩过程。

根据自己需要拦截的对象的类型,选择对应的钩子类型。 比如本文中要拦截键盘的按键消息,选择WH_KEYBOARD_LL;要拦截某个窗口的消息,选择WH_GETMESSAGE。

2)lpfn:指定一个回调函数的地址(挂钩过程函数),当特定事件发生时,该函数将被调用。每种类型的钩子,对应的回调函数的声明是不同的,可以参见上述表格中的说明,点击挂钩过程函数的说明链接去查看。

3)hMod:指定包含钩子函数的模块句柄。通常情况下,可以将其设置为 NULL,表示使用当前进程的模块句柄。

4)dwThreadId:指定要关联钩子的线程ID。如果是全局钩子,可以将其设置为 0,将钩子应用到所有线程。

返回值

       SetWindowsHookEx 返回一个非零值,表示成功安装钩子,或者返回 NULL 表示安装失败。安装成功后,钩子函数将开始监视并处理指定类型的事件。

3、Hook实例1 - 使用SetWindowsHookEx在程序中拦截键盘消息

       要在程序中拦截键盘按键消息,选择钩子类型,对应的钩子过程处理函数的声明为:

LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam)

相关代码如下:(在钩子过程处理函数中拦截ESC按键、CTrl+W按键消息等,按下这些按键时程序要做一些操作的)

//1、安装监控键盘消息的hook
HHOOK g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, 0);// 2、钩子过程函数,就是调用SetWindowsHookEx设置的回调函数
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{// 对于拦截键盘消息的过程函数,此处的code只有HC_ACTION一个值if (code == HC_ACTION){KBDLLHOOKSTRUCT *pLowLevelKBD = (KBDLLHOOKSTRUCT*)lParam;if (pLowLevelKBD->vkCode == VK_ESCAPE|| (pLowLevelKBD->vkCode == 0x57 && GetKeyState(VK_CONTROL) < 0) ) // 0x57 - 按键W{// 具体处理代码省略}}return CallNextHookEx(g_hHook, code, wParam, lParam);
}// 3、卸载hook(利用SetWindowsHookEx返回的钩子句柄去卸载)
if (g_hHook != NULL)
{::UnhookWindowsHookEx(g_hHook);g_hHook = NULL;
}

       在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:该精品技术专栏的订阅量已达到510多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2:  

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏3:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,专栏文章已经更新到400多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法、C++11及以上新特性(不仅看开源代码会用到,日常编码中也会用到部分新特性,面试时也会涉及到)、常用C++开源库的介绍与使用、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(排查软件异常的手段与方法、分析C++软件异常的基础知识、常用软件分析工具使用、实战问题分析案例等)、设计模式、网络基础知识与网络问题分析进阶内容等。

专栏4:   

VC++常用功能开发汇总(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5: 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


4、Hook实例2 - 使用SetWindowsHookEx在程序中拦截某个窗口的消息

       我们的软件在接收桌面共享图像时需要实现新的功能,需要做到以下几点细节:

1)要支持桌面共享图像的缩放;
2)当播放视频图像的窗口尺寸小于共享图像的分辨率尺寸时,要支持通过鼠标拖动,将不可见的区域拖出来显示;
3)要做到实时的拖动,用户一拖动鼠标就要立即响应,不能有明显的延迟。

       特别是第三点,不能有掩饰,但UI层到底层的音视频编解码层之间经过了好几层,函数调用是异步的,如果由UI层感知到用户鼠标拖动的坐标信息发给音视频编解码层,会有延时,体验会非常不好。并且拖动鼠标的过程中要频繁地调用接口给编解码层传递位置坐标信息,这样频繁的调用函数会有一定的开销,会拖慢程序的运行效率。

       首先,要拦截窗口的消息,可以选择使用WH_GETMESSAGE钩子类型。

       其次,这个显示远程发过来的桌面共享视频图像的窗口,在UI层,属于UI线程的,我们只需要拦截UI线程的窗口消息即可,所以通过UI层传过来的窗口句柄值,调用GetWindowThreadProcessId获取UI主线程的线程id,作为第四个参数传给SetWindowsHookEx。 

       给显示桌面共享视频图像的窗口所在的UI线程安装拦截消息的hook钩子

// 获得窗口所属进程ID和线程ID
DWORD dwProcessId = 0;
DWORD dwThreadId = GetWindowThreadProcessId(g_hDrawWnd, &dwProcessId);
DWORD dwThreadId2  = GetCurrentThreadId();
LogPrintf("window ProcessId: %d, window ThreadId: %d, current ThreadId: %d\n", dwProcessId, dwThreadId, dwThreadId2);// 这段代码只能写在dll工程中
// 安装一个钩子子程,在系统将消息发送到目标窗口过程之前监视消息;
// WH_GETMESSAGE:可过滤和修改post消息;
// CallWndProc:处理函数
// 输入的线程ID 必须是创建窗口的线程ID,就是程序UI主线程的ID
g_hHook = SetWindowsHookEx( WH_GETMESSAGE, CallWndProc, 0, dwThreadId );
if (g_hHook == NULL)
{DWORD dwErrId = GetLastError();LogError("[quit] SetWindowsHookEx() failed. err=%d:%s\n", dwErrId, strerror(dwErrId));return FALSE;
}

       经过一番对友商软件相同功能的研究后,确定我们只要在钩子过程处理函数中拦截WM_LBUTTONDOWN鼠标左键按下、WM_LBUTTONUP鼠标左键弹起、WM_MOUSEMOVE鼠标移动等消息。

一次完整的拖动操作,从鼠标按下开始拖动,一直按着鼠标左键拖动鼠标,鼠标左键松开就完成了此次拖动操作。所以要关注WM_LBUTTONDOWN、WM_LBUTTONUP和WM_MOUSEMOVE等消息。

       窗口处理过程函数中拦截绘制桌面共享视频图像窗口消息的代码如下:

LRESULT CALLBACK CallWndProc(int code, WPARAM wParam, LPARAM lParam)
{if (g_nDecLogon == 9){LogPrintf("------------CallWndProc\n");}//DWORD dwThreadId2  = GetCurrentThreadId(); //查看实际处理线程 是不是 UI主线程MSG* pWpsStruct =(MSG*)lParam; switch ( pWpsStruct->message ){case WM_LBUTTONDOWN:if ( pWpsStruct->hwnd == g_hDrawWnd )  // 判断响应事件的窗口句柄{if ( pWpsStruct->wParam ==  MK_LBUTTON) // 鼠标左键按下{g_bStartMove = true; g_tCursorPoint.x = LOWORD(pWpsStruct->lParam);g_tCursorPoint.y = HIWORD(pWpsStruct->lParam);if (g_nDecLogon == 9){LogPrintf("------------鼠标左键按下: client coordinate (%d,%d)\n", g_tCursorPoint.x, g_tCursorPoint.y);}}}break;case WM_LBUTTONUP: //鼠标左键松开{g_bStartMove = false;g_bTracking = false;g_tCursorPoint.x = LOWORD(pWpsStruct->lParam); g_tCursorPoint.y = HIWORD(pWpsStruct->lParam);if (g_nDecLogon == 9){LogPrintf("------------鼠标左键松开: client coordinate (%d,%d)\n", g_tCursorPoint.x, g_tCursorPoint.y);}}break;case WM_MOUSEMOVE: // 鼠标抓取移动if ( g_bStartMove ){if (!g_bTracking){TRACKMOUSEEVENT tme;tme.cbSize = sizeof(tme);tme.hwndTrack = g_hDrawWnd;tme.dwFlags = TME_LEAVE;tme.dwHoverTime = 1;g_bTracking = TrackMouseEvent(&tme);}g_tCursorPoint.x = LOWORD(pWpsStruct->lParam); g_tCursorPoint.y = HIWORD(pWpsStruct->lParam);if (g_nDecLogon == 9){LogPrintf("------------鼠标抓取移动: g_bTracking=%d, cursor client coordinate (%d,%d)\n", g_bTracking, g_tCursorPoint.x, g_tCursorPoint.y);}}break;case WM_MOUSELEAVE: {POINT point = {0};RECT rcDlg = {0};GetCursorPos(&point);GetClientRect(g_hDrawWnd, &rcDlg);ClientToScreen(g_hDrawWnd, (LPPOINT)&rcDlg);ClientToScreen(g_hDrawWnd, ((LPPOINT)&rcDlg) + 1);if ( !::PtInRect( &rcDlg, point ) ){// 拖动时,鼠标已离开双流画面,int a = 0;}g_bStartMove = false;g_bTracking = false;g_tCursorPoint.x = LOWORD(pWpsStruct->lParam); g_tCursorPoint.y = HIWORD(pWpsStruct->lParam);if (g_nDecLogon == 9){LogPrintf("------------鼠标离开窗口: g_bTracking=%d, cursor client coordinate (%d,%d)\n", g_bTracking, g_tCursorPoint.x, g_tCursorPoint.y);}}break;default:break;}return CallNextHookEx( g_hHook, code, wParam, lParam );
}

       关于这个实例的详细细节和说明,可以参见我之前写的文章:

通过SetWindowHookEx去实时拦截窗口消息,实现视频会议中桌面共享图像的实时拖动(附源码)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/139594004 

5、最后

        本文详细介绍了给程序安装钩子的SetWindowsHookEx,并给出了项目中使用SetWindowsHookEx的两个实例,有一定的参考价值,希望对大家能有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415732.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wsl下将Ubuntu从c盘移动到其他盘

一、概述 因为自己的C盘内存不足&#xff0c;加上之后需要在Ubuntu下面下载许多的内容和东西&#xff0c;需要将其移动到d盘上面&#xff0c;这样可以拥有更大的空间。这里记载了一下自己的操作过程。 二、具体步骤 &#xff08;一&#xff09;过程 1.查看当前系统中wsl分发版…

Hi3061M开发板初测——点亮小灯

目录 前言环境配置点亮led源码IDA集成了串口监视器最后下载到开发板中运行 前言 海思MCU体验官活动&#xff0c;Hi3061M开发板到手后&#xff0c;配置环境初步测试点亮小灯。 环境配置 环境配置按照gitee提供的redeme一步一步来配置起来很顺利。具体可自行查阅&#xff1a;环境…

Python机器学习——人脸性别识别

一、选题背景 人脸识别技术是模式识别和计算机视觉领域最富挑战性的研究课题之一&#xff0c;也是近年来的研究热点&#xff0c;人脸性别识别作为人脸识别技术的重要组成部分也受到了广泛地关注。人脸性别识别就是向计算机输入人脸图像&#xff0c;经过某种方法或运算&#xff…

springnboot +uniapp汽车租赁系统

springnboot uniapp汽车租赁系统 手机移动端&#xff1a;主页&#xff0c;租赁汽车展示&#xff0c;汽车租赁&#xff0c;我的租赁记录&#xff0c;还车记录&#xff0c;注册登录&#xff0c;修改个人资料 PC端管理后台&#xff1a;公告管理&#xff0c;用户管理&#xff0c;…

【链表】环形链表

环形链表 环形链表I题目思路讲解代码书写拓展问题 环形链表II题目题目解析思路讲解代码书写 环形链表I 题目 题目链接: 环形链表 思路讲解 对于探究一个线性结构是否有环, 最经典的做法就是快慢指针法. 我们定义两个指针, 一个一次走两步, 一个一次走一步, 走完后判断两个是…

虚幻引擎VR游戏开发01 | VR设备和术语

四款Unreal Engine默认配套按键映射的VR设备 IMC按键映射 Oculus Touch (R) Grip Axis: 代表Oculus Rift或Quest设备的右手控制器的抓握轴输入。Valve Index (R) Grip Axis: 代表Valve Index设备的右手控制器的抓握轴输入。Vive (R) Grip: 代表HTC Vive设备的右手控制器的抓握…

chrome 插件开发入门

1. 介绍 Chrome 插件可用于在谷歌浏览器上控制当前页面的一些操作&#xff0c;可自主控制网页&#xff0c;提升效率。 平常我们可在谷歌应用商店中下载谷歌插件来增强浏览器功能&#xff0c;作为开发者&#xff0c;我们也可以自己开发一个浏览器插件来配合我们的日常学习工作…

Vite - 兼容旧版浏览器 plugin-legacy(2)

目录 1&#xff0c;问题2&#xff0c;解决3&#xff0c;String 其他新增 API 的版本 接上文 Vite - 兼容旧版浏览器 plugin-legacy&#xff08;1&#xff09; 1&#xff0c;问题 客户浏览器报错&#xff0c;不支持 replaceAll 方法。 该方法在 query-string 依赖内部使用了。…

嵌入式Linux:常见信号的默认行为

信号是一种软件中断&#xff0c;用于通知进程发生了某种异步事件。信号可以由用户、其他进程或操作系统内核产生。进程可以选择捕获并处理这些信号&#xff0c;或者忽略它们&#xff0c;让系统执行默认操作。 不可靠信号&#xff08;非实时信号&#xff09;&#xff1a;编号为 …

反爬虫策略收录集

前言 反爬虫&#xff0c;是指对扫描器中的网络爬虫环节进行反制&#xff0c;通过一些反制策略来阻碍或干扰爬虫的正常爬行&#xff0c;从而间接地起到防御目的。下面是一些常见的反爬虫策略的收录。 入门版 封IP 由于服务器有防火墙&#xff08;如果防火墙在TCP/UDP层或者它…

渲染100高性能云渲染,性价比超高

在这个3D渲染行业迅速发展的时代&#xff0c;对于渲染速度和稳定性的渴望日益强烈。需要更快的渲染时间来缩短项目周期&#xff0c;同时希望渲染过程更加稳定&#xff0c;避免问题导致的损失。 如今市场上虽然不乏各种云渲染服务&#xff0c;但要找到既经济又能满足高要求的选…

Java内存区域

文章目录 运行时数据区域1. 程序计数器2. 虚拟机栈局部变量表 3. 本地方法栈4. 堆5. 方法区运行时常量池直接内存 运行时数据区域 Java虚拟机在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途&#xff0c;以及创建和销毁的时间&…

sqli-labs靶场通关攻略(61-65)

Less-61 步骤一&#xff1a;查看数据库 ?id1)) and updatexml(1,concat(1,(select database())),1)-- 步骤二&#xff1a;查看表名 ?id1)) and updatexml(1,concat(1,(select group_concat(table_name) from information_schema.tables where table_schemasecurity)),1)--…

uniapp写的一个年月日时分秒时间选择功能

代码: <template><view><picker mode"multiSelector" :value"multiIndex" :range"multiRange" change"onMultiChange"><view class"picker">当前选择&#xff1a;{{ formattedDateTime }}</vie…

中国各地级市的海拔标准差

海拔标准差是衡量地理测量准确性的重要指标&#xff0c;它通过计算特定地点的海拔测量值与平均海拔之间的偏差来评估数据的可靠性。较小的标准差意味着测量结果较为一致&#xff0c;而较大的标准差则可能指出数据的波动性或测量误差。 计算方法 海拔标准差的计算遵循以下公式…

C++学习/复习补充记录 --- 图论(深搜,广搜)

图的度 无向图&#xff1a; 连接某节点的边数&#xff0c;即为该节点的【度】。 &#xff08;无向图中&#xff0c;有5条边连接节点4&#xff0c;则节点4的度为5。&#xff09; 有向图&#xff1a; 出度&#xff1a;从该节点出发的边的个数。 入度&#xff1a;指向该节点边的个…

Idea_服务器自动化部署_傻瓜式教程

使用Alibaba Cloud Toolkit 在 IntelliJ IDEA 中一键部署项目到服务器 1. 安装 Alibaba Cloud Toolkit 插件 确保 IntelliJ IDEA 版本为 2018.3 或以上。打开 IntelliJ IDEA&#xff0c;进入 File -> Settings -> Plugins&#xff0c;搜索并安装 Alibaba Cloud Toolkit…

【Python基础】字典类型

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、Python 字典类型2.1 访问字典里的值2.2 修改字典2.3 删除字典元素2.4 字典键值的特性2.5 遍历字典…

Vision Transformer (ViT) + 代码【详解】

文章目录 1、Vision Transformer (ViT) 介绍2、patch embedding3、代码3.1 class embedding Positional Embedding3.2 Transformer Encoder3.3 classifier3.4 ViT总代码 1、Vision Transformer (ViT) 介绍 VIT论文的摘要如下&#xff0c;谷歌翻译如下&#xff1a; 虽然 Transf…

《JavaEE进阶》----10.<SpringMVC应用分层:【三层架构】>

本篇博客我们主要讲解 1.应用的分层&#xff1a;三层架构 2.Spring MVC和三层架构的区别和联系 3.软件设计原则&#xff1a;高内聚低耦合 4.应用分层的好处 5.通过应用分层后的代码示例 一、三层架构简介 阿里开发手册中,关于工程结构部分,定义了常见工程的应用分层结构: 上图…