news 2026/9/7 6:20:39

MFC全局键鼠钩子实战:SetWindowsHookEx原理与完整实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MFC全局键鼠钩子实战:SetWindowsHookEx原理与完整实现

简介:这是一个面向 MFC/C++ 开发者的 Windows 全局钩子学习工程,完整演示了如何通过 HOOK.DLL 动态链接库挂接低级键盘钩子(WH_KEYBOARD_LL)与低级鼠标钩子(WH_MOUSE_LL),在回调函数中捕获按键码、鼠标屏幕坐标等输入信息,并用 CFile 或 fstream 写入日志文件,适合做输入监控演示、操作审计或辅助工具原型。压缩包共 80 个文件、66.54MB,包含可编译的 MFC 源码(.cpp/.h)、Visual Studio 工程文件(.sln/.vcxproj 以及 tlog、pch 等编译中间产物),同时提供 Release 和 Debug 构建,可以直接运行 HookApp.exe 和 HOOK.dll,也能对照 PDB 调试符号跟踪流程。工程中主程序 HOOKAPP 负责装载钩子并更新对话框显示,DLL 负责实际拦截与传递数据,目录结构保留了 .sdf/.opensdf 和 ipch 等 VS 索引缓存,便于打开工程后快速定位关键代码。目前已有 1397 人学习,ReadMe、targetver.h 等辅助文件齐全,较适合有 C++ 基础并想了解 SetWindowsHookEx、全局钩子与 MFC 界面联动原理的读者。还需注意,全局钩子会带来系统性能开销和隐私合规问题,应仅用于授权环境中的技术研究。 今年有个朋友问我,他想用 MFC 写个小工具,把全局的键盘和鼠标输入给拦下来,做自己的全局快捷键和键鼠记录功能。MFC 本身没有封装现成的钩子类,但 Windows 的SetWindowsHookEx这套 API 是现成的,用好了就能把整台电脑的键鼠事件接管过来。这篇文章我就把完整思路、核心代码和踩坑过程整理出来,尽量让一上来想照着做的朋友少走弯路。

1. 方案选型与整体设计思路

1.1 为什么用全局钩子而不是消息处理

MFC 处理键盘鼠标的常规方式,是在窗口的消息循环里响应WM_KEYDOWNWM_LBUTTONDOWN这类消息。但这种方式有一个致命限制:它只能收到当前进程、当前窗口的输入事件。只要你的程序不在前台,焦点在别的窗口上,消息就全跑到那边去了。

全局钩子要解决的就是这个“跨进程监听”问题。SetWindowsHookEx会把一个钩子过程挂到系统输入事件链上,无论当前焦点在哪个窗口、哪个程序,键盘和鼠标事件都会先经过这个钩子。常见的场景有这么几类:

  • 全局快捷键工具,在自己软件没焦点时也能响应组合键
  • 键鼠操作监控与回放,比如录制操作步骤做自动化
  • 游戏或工具类软件里拦截特定按键,屏蔽系统默认行为
  • 远程协助、演示工具中需要跟踪操作轨迹

对 MFC 项目来说,钩子过程不依赖某个具体窗口,适合放在一个独立管理类里,需要记录时把数据投递到 UI 线程即可。

1.2 关键选择:低层钩子(WH_KEYBOARD_LL / WH_MOUSE_LL)

Windows 提供的键盘钩子有WH_KEYBOARDWH_KEYBOARD_LL两种,鼠标钩子类似。低层钩子(LL 版本)是我的首选,原因非常实际:

  • 普通WH_KEYBOARD/WH_MOUSE钩子需要把钩子过程放在独立的 DLL 中,系统会把 DLL 映射到每个进程,编写、调试难度高,还容易引发各种兼容性问题。
  • 低层钩子在调用线程所在进程中执行回调,不需要 DLL,直接在 EXE 里写回调函数就能完成全局监听,这对大多数应用场景已经足够。

低层钩子的原理是系统把原始输入事件循环派发之前,先传递给注册了钩子的线程。回调执行完后再决定放行还是拦截——这一步对应CallNextHookEx是否被调用。需要说明的是,低层钩子对性能有隐性要求,回调里不能做耗时操作,后面我会细讲。

从设计角度看,我一般把钩子的安装、卸载、回调、消息转发封装成一个类,MFC 的 Dialog 或 CWinApp 里只负责调用,避免把业务逻辑和钩子机制混在一起。

2. 钩子核心机制与关键函数解析

2.1 安装与卸载:SetWindowsHookEx / UnhookWindowsHookEx

以安装键盘钩子为例:

g_hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, // 钩子类型:低层键盘钩子 KeyboardProc, // 回调函数地址 GetModuleHandle(nullptr), // 模块句柄,低层钩子传当前模块即可 0 // 线程ID为0,表示全局钩子 );

四个参数里最容易踩坑的是第三个。GetModuleHandle(nullptr)返回的是当前 EXE 模块句柄,传这个没问题;如果你把代码编译成 DLL 被别 EXE 加载,就得换成 DLL 自己的模块句柄,否则钩子安装会失败。第四个参数传0表示全局挂钩,传入线程 ID 则只对指定线程生效,控制台程序通常不需要这么用。

卸载函数很简单:

if (g_hKeyboardHook) { UnhookWindowsHookEx(g_hKeyboardHook); g_hKeyboardHook = nullptr; }

注意卸载和安装必须在同一个线程执行,跨线程卸载线程钩子会引发奇怪问题。习惯上我会在InitInstance里安装,在退出前的ExitInstance里卸载,保证线程一致。

2.2 回调函数:数据结构和返回约定

低层钩子的回调函数签名是统一的:

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0) // 只有nCode>=0才需要处理 { KBDLLHOOKSTRUCT* pKb = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); // 处理键盘数据 } return CallNextHookEx(g_hKeyboardHook, nCode, wParam, lParam); }

KBDLLHOOKSTRUCT最关键的两个字段是vkCode(虚拟键码)和flags(标志位)。flags里要特别检查LLKHF_INJECTED,因为用SendInput模拟的按键也会经过钩子,不检查这个字段会把“假按键”也当成真实输入处理。鼠标钩子的结构类似,换成MSLLHOOKSTRUCT,里面有鼠标坐标pt、滚轮数据mouseData和按键状态flags

回调返回值的约定是:如果放行该事件,必须调用CallNextHookEx并把返回值传下去。想拦截这个事件,直接返回1(非零)即可,事件就不会继续派发给目标窗口。实际项目中“拦截”要谨慎,拦错了按键会导致系统按键失灵,特别是Ctrl+Alt+Del这类安全组合键根本无法被低层钩子拦截。

2.3 消息循环的必要性:为什么回调不执行

低层钩子回调发生在安装钩子线程的消息循环中,所以 MFC 程序里必须在 UI 线程安装钩子并保证消息循环正常运行。控制台程序如果直接调SetWindowsHookEx却没有任何消息循环,回调可能永远不会被调用。MFC 的CWinApp::Run自带消息循环,这点天然满足。

如果你在非 UI 工作线程安装钩子,该线程也要有消息循环,比如CWinThreadRun函数。否则我实测过,钩子装成功了,回调却一次都不触发,排查半天才定位到是线程没有消息循环。

3. 实操:在 MFC 项目中实现全局键鼠捕获

3.1 环境准备与项目设置

我用的环境是 Visual Studio 2013 或更新版本,MFC 项目创建后默认就支持。不推荐用纯 Win32 空项目再手动引入 MFC 头文件,麻烦且容易漏。创建工程时选“基于对话框”“单文档”都行,核心逻辑放一个自己写的钩子管理类里。

需要包含的 Windows 头文件在 MFC 项目中一般已经被stdafx.h引用了,如果遇到重定义问题,检查是否手动重复包含了windows.h。另外,低层钩子相关的KBDLLHOOKSTRUCT在较老 SDK 中需要定义_WIN32_WINNT >= 0x0400,VS2013 默认值已经够用,不用额外处理。

3.2 定义钩子管理类

我的做法是把键盘、鼠标钩子封装成一个单例类,方便从对话框任意位置访问。核心结构如下:

class CGlobalKeyMouseHook { public: static CGlobalKeyMouseHook* Instance(); BOOL Install(); void Uninstall(); void SetTargetWindow(HWND hWnd) { m_hTargetWnd = hWnd; } void EnableKeyboardCapture(BOOL bEnable) { m_bKeyboardCapture = bEnable; } void EnableMouseCapture(BOOL bEnable) { m_bMouseCapture = bEnable; } static LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam); private: CGlobalKeyMouseHook() = default; ~CGlobalKeyMouseHook() = default; static HHOOK m_hKeyboardHook; static HHOOK m_hMouseHook; static HWND m_hTargetWnd; static BOOL m_bKeyboardCapture; static BOOL m_bMouseCapture; }; HHOOK CGlobalKeyMouseHook::m_hKeyboardHook = nullptr; HHOOK CGlobalKeyMouseHook::m_hMouseHook = nullptr; HWND CGlobalKeyMouseHook::m_hTargetWnd = nullptr; BOOL CGlobalKeyMouseHook::m_bKeyboardCapture = FALSE; BOOL CGlobalKeyMouseHook::m_bMouseCapture = FALSE;

静态成员变量必须在 cpp 文件里定义,这是 C++ 的基础要求,但 MFC 项目里很容易因为忘了这步导致链接错误“无法解析的外部符号”。回调函数必须设置成静态函数,因为普通成员函数有this指针,Windows 回调机制按 C 调用约定调用,函数指针类型不匹配连编译都过不去。

3.3 安装钩子的完整实现

安装钩子部分,我加了些防御性判断和错误码输出:

BOOL CGlobalKeyMouseHook::Install() { if (m_hKeyboardHook || m_hMouseHook) return TRUE; // 已经安装过 // 安装键盘钩子 m_hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(nullptr), 0); if (!m_hKeyboardHook) { DWORD dwError = GetLastError(); TRACE(_T("Install keyboard hook failed, error=%d\n"), dwError); return FALSE; } // 安装鼠标钩子 m_hMouseHook = SetWindowsHookEx( WH_MOUSE_LL, MouseProc, GetModuleHandle(nullptr), 0); if (!m_hMouseHook) { DWORD dwError = GetLastError(); TRACE(_T("Install mouse hook failed, error=%d\n"), dwError); UnhookWindowsHookEx(m_hKeyboardHook); m_hKeyboardHook = nullptr; return FALSE; } return TRUE; }

安装失败的常见原因有三个:模块句柄传错、目标进程权限不足、系统没有为低层钩子分配超时时间。后两者在普通本机开发环境中一般不会遇到,但如果你的软件是普通用户权限,目标是提权后的管理员窗口,低层钩子依然能收到事件,这点比普通钩子有优势,只是对受保护进程(如某些系统服务)的事件无能为力。

3.4 键盘钩子回调的数据提取

键盘钩子回调中,我实际开发时除了记录虚拟键码,还会把按键的扫描码和名称一起转换出来,方便 UI 显示:

LRESULT CALLBACK CGlobalKeyMouseHook::KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0 && m_bKeyboardCapture) { KBDLLHOOKSTRUCT* pKeyInfo = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); UINT vkCode = pKeyInfo->vkCode; // 过滤掉自动重复和弹起事件,只在按下时处理 if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) { // 如果需要拦截指定按键,在这里判断并返回1 if (vkCode == VK_F8) { // 例如屏蔽F8 return 1; } // 把按键信息发送到UI线程 if (m_hTargetWnd) { // 用自定义消息传递,或者开一个小结构体 ::PostMessage(m_hTargetWnd, WM_MY_GLOBAL_KEYDOWN, vkCode, pKeyInfo->flags); } } } return CallNextHookEx(m_hKeyboardHook, nCode, wParam, lParam); }

两个关键点:

第一,回调里的工作必须尽量轻量。低层钩子的回调是在系统输入线程的上下文中被调用的,如果回调耗时过长,系统会跳过你的钩子甚至直接卸载。注册表里有个HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout,默认值极短,实测回调里做字符串拼接、文件写入这类操作很可能导致钩子静默失效。因此我通常只做薄处理,需要记录数据就PostMessage给主窗口,再由 UI 线程处理。

第二,拦截要精确wParam区分按下、弹起、系统键等事件,拦截键盘逻辑要明确是想屏蔽“按下”还是同时屏蔽“弹起”。屏蔽按下通常就够了,残留的弹起消息不会对系统造成明显影响。

3.5 鼠标钩子回调的数据提取

鼠标钩子回调处理类似:

LRESULT CALLBACK CGlobalKeyMouseHook::MouseProc( int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0 && m_bMouseCapture) { MSLLHOOKSTRUCT* pMouseInfo = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam); BOOL bIsInjected = (pMouseInfo->flags & LLMHF_INJECTED) != 0; // 过滤模拟输入,结合自己的业务需求决定是否处理 if (!bIsInjected) { POINT pt = pMouseInfo->pt; UINT messageType = wParam; // WM_MOUSEMOVE, WM_LBUTTONDOWN 等 DWORD mouseData = pMouseInfo->mouseData; // 滚轮数据 if (m_hTargetWnd) { ::PostMessage(m_hTargetWnd, WM_MY_GLOBAL_MOUSE, messageType, MAKELPARAM(pt.x, pt.y)); } } } return CallNextHookEx(m_mouseHook, nCode, wParam, lParam); }

MSLLHOOKSTRUCT里的pt是屏幕坐标,与 MFC 窗口自己的GetMessagePos坐标体系一致,收到后可以直接换算成相对某个窗体的坐标,方便做屏幕区域的限定判断。鼠标消息量极大,尤其WM_MOUSEMOVE频繁触发,如果不加节流,PostMessage会把 UI 消息循环塞满。通常我在回调里只处理按下/弹起/滚轮事件,不处理WM_MOUSEMOVE,或者对移动事件做 50ms 窗口内的合并。

3.6 在 MFC 对话框中的集成用法

CMyGlobalHookDlg::OnInitDialog里初始化:

BOOL CMyGlobalHookDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 告诉钩子管理器目标窗口 CGlobalKeyMouseHook::Instance()->SetTargetWindow(m_hWnd); CGlobalKeyMouseHook::Instance()->EnableKeyboardCapture(TRUE); CGlobalKeyMouseHook::Instance()->EnableMouseCapture(TRUE); if (!CGlobalKeyMouseHook::Instance()->Install()) { AfxMessageBox(_T("全局钩子安装失败,请检查权限或冲突程序")); } return TRUE; }

退出时记得卸载:

void CMyGlobalHookDlg::OnDestroy() { CGlobalKeyMouseHook::Instance()->Uninstall(); CDialogEx::OnDestroy(); }

消息响应函数里接收数据:

ON_MESSAGE(WM_MY_GLOBAL_KEYDOWN, &CMyGlobalHookDlg::OnGlobalKeyDown) ON_MESSAGE(WM_MY_GLOBAL_MOUSE, &CMyGlobalHookDlg::OnGlobalMouse) LRESULT CMyGlobalHookDlg::OnGlobalKeyDown(WPARAM wParam, LPARAM lParam) { UINT vkCode = (UINT)wParam; CString strInfo; strInfo.Format(_T("全局按键按下: VK=0x%02X (%s)"), vkCode, GetKeyName(vkCode)); // 更新到列表控件或日志框 m_listLog.AddString(strInfo); return 0; }

注意自定义消息WM_MY_GLOBAL_KEYDOWNWM_MY_GLOBAL_MOUSE要在头文件里定义,建议从WM_APP(0x8000)开始:

#define WM_MY_GLOBAL_KEYDOWN (WM_APP + 1) #define WM_MY_GLOBAL_MOUSE (WM_APP + 2)

WM_APP开始可以有效避开系统保留消息段。

3.7 字符键的转换处理

很多需求要记录“用户按了哪个字符”,不能只用vkCodevkCode对应的是键盘物理键位置,比如按下 A 键时vkCode0x41,但如果你同时按下了Shift或切换到了中文输入法,实际的字符可能是大写字母、@符号或者汉字的输入法触发键。这种情况下建议调用ToUnicode函数转换:

int GetKeyChar(DWORD vkCode, DWORD scanCode, BOOL bShift, BOOL bCaps) { BYTE kbState[256] = {0}; kbState[VK_SHIFT] = bShift ? 0x80 : 0; kbState[VK_CAPITAL] = bCaps ? 0x01 : 0; WCHAR wcBuf[8] = {0}; // 第三个参数传扫描码,这里借用KBDLLHOOKSTRUCT中的scanCode int nLen = ToUnicode(vkCode, scanCode, kbState, wcBuf, 8, 0); return nLen > 0 ? wcBuf[0] : 0; }

ToUnicode在低层钩子回调里调用时有时会失败,尤其是输入法活动状态下。稳妥的做法是收到WM_KEYDOWN后,把vkCodescanCode传回 UI 线程,再在 UI 线程里调用ToUnicode,减少干扰。

4. 常见问题与排查技巧实录

4.1 钩子安装失败,GetLastError 返回 1428

错误码 1428 表示“无法在没有模块句柄的情况下安装全局钩子”。排查顺序:

  • 确认SetWindowsHookEx第三参数是否传了有效的模块句柄,低层钩子传GetModuleHandle(nullptr)一般没问题,但如果你在 DLL 里实现钩子,必须传 DLL 的模块句柄,不能偷懒用nullptr
  • 确认安装钩子的进程是 GUI 进程。纯控制台或服务程序不能安装全局钩子,系统要求该进程能够运行消息循环。
  • 检查是不是重复安装导致句柄泄漏,某些场景下钩子句柄在同一进程内多次安装、卸载,会触发系统限制。

4.2 回调执行了,但收不到某些按键或鼠标事件

比较常见的现象是“普通按键都能收到,但Ctrl+Alt+Del收不到”,这是系统保护的组合键,低层钩子无权处理,正常。另一种是收不到某些快捷键组合,比如 Win+L,这类组合键一部分在钩子之前就被系统拦截了,属于安全机制,不用强行处理。

鼠标方面,“左右键都能捕获,但鼠标中键滚动事件收不到”,需要检查wParam是否为WM_MOUSEWHEEL,滚动数据在MSLLHOOKSTRUCT::mouseData的高位字中,需要这样取:

short zDelta = HIWORD(pMouseInfo->mouseData); // 正数向上滚动,负数向下滚动

4.3 钩子装了一段时间后停止响应

这是低层钩子的经典问题。系统按照LowLevelHooksTimeout(默认几百毫秒)限制回调执行时间,如果回调里做了文件写入、数据库操作、大量OutputDebugString,就可能被系统判定为无响应,然后直接跳过回调。彻底的解决办法是让回调只做“记录 + PostMessage”,所有耗时逻辑移到 UI 线程。

如果实在无法避免在回调里做耗时处理,检查注册表是否被改过:

HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout

把它设得大一点可以缓解,但治标不治本,一旦扩大到 2000ms,用户会感觉系统卡顿。

4.4 调试断点导致钩子“假死”

开发阶段很多人喜欢在回调函数里下断点。低层钩子回调执行时如果断点命中,整个系统输入会短暂停滞,断点继续后看似没事,但钩子很可能已经被系统超时清理了。我的做法是回调里只做投递,关键逻辑的调试放到 UI 线程的消息响应函数里去断点,这样既不影响全局输入,也能定位到核心逻辑。

4.5 64 位进程与 32 位进程的差异

如果目标环境是 64 位 Windows,低层钩子有一个隐蔽坑:64 位程序安装的钩子无法拦截 32 位程序的低层输入,反过来 32 位程序安装的钩子也无法拦截 64 位程序。因为低层钩子回调发生在安装者自己的进程里,处理的是系统级输入事件,但它与目标进程的位数相关,系统只把“匹配位数”的事件派发给你。要覆盖全系统监听,需要同时编译 32 位和 64 位版本,分别运行两个钩子进程。

MFC 项目默认只有 32 位配置,如果目标是全平台,要在配置管理器里新建 x64 解决方案平台并编译一份,安装时根据系统位数选择运行对应版本的 exe。

4.6 回调里调用 MFC 窗口函数导致崩溃

低层钩子回调的调用线程完全不属于 MFC 窗口线程,Windows 消息接收方是某个窗口,但回调上下文不保证和窗口线程同步。一些 MFC 相关函数(比如AfxGetMainWndCWnd::FromHandle)在错误的线程中调用会返回空指针或断言失败。所以回调函数里我几乎不调用任何 MFC API,全部通过裸 APIPostMessage与 UI 通信。

5. 扩展与实用技巧

5.1 如何实现“仅拦截特定按键”

全局快捷键实现的核心逻辑,就是在回调里判断按键组合,然后返回 1 拦截,而不是返回 0 放行。比如实现一个“按 F9 静音麦克风”的功能:

if (wParam == WM_KEYDOWN && vkCode == VK_F9) { // 如果只是监听,这里直接PostMessage后返回0 // 如果要“吞掉”这个按键,就return 1 return 1; }

但要注意,拦截之后当前焦点程序收不到这个按键,可能影响用户预期,比如游戏的某个按键被拦截会导致游戏内操作失常。所以大多数正产场景是“监听 + 响应”而不是“拦截”。

5.2 用 SendInput 模拟键鼠输入与钩子的关系

热搜词里有人提到“VB模拟键盘输入 sendinput”,其实SendInput产生的输入事件也会经过低层钩子。在钩子回调里通过LLKHF_INJECTEDLLMHF_INJECTED可以区分真实硬件输入与模拟输入:

if (pKeyInfo->flags & LLKHF_INJECTED) { // 这是SendInput模拟出来的按键 }

这个标志有时候会被恶意软件伪造,但在普通应用开发中已经足够。把模拟输入和真实输入区分开很有用,例如录制宏回放软件不希望把回放过程也当成用户操作再次录制,判空了这个标志就能避免无限循环录制。

5.3 多实例冲突处理

如果你的工具有多个副本同时运行,所有副本都安装了全局钩子,输入事件会沿着钩子链依次传递,导致每个副本都收到一次键盘事件。需要在安装钩子前检查当前进程是否已经存在。简单办法是用命名互斥量:

HANDLE hMutex = CreateMutex(nullptr, TRUE, _T("Global\\MyKeyHookAppMutex")); if (GetLastError() == ERROR_ALREADY_EXISTS) { // 已有一个实例在运行 AfxMessageBox(_T("程序已在运行")); return FALSE; }

5.4 回调数据落地与日志

实际项目中,很多需求要把键鼠操作记录成日志文件。建议把PostMessage里发送的结构体设计成包含时间戳、按键/坐标、事件类型、注入标志等信息,统一由 UI 线程写成文本或持久化到数据库。这样即使回调因为超时被跳过,日志文件里也能看到最近的部分记录,方便定位问题。

在 MFC 列表控件或编辑框里实时滚动显示时,要注意 UI 刷新频率。鼠标移动事件每秒几十次,直接全部追加到控件会导致界面卡顿。通常做法是累积数据,每 200ms 刷新一次控件内容,日志仍按全量写入文件。

6. 写在最后的一点个人体会

钩子这套机制用了不少年头,低层钩子的方案在今天依然是“全局键鼠监听”最简单可靠的选择。真正有难度的往往不是钩子本身,而是后续的数据处理策略:回调必须轻量、线程模型必须清晰、消息派发必须及时。只要把这三条原则抓住,你就已经避开了大多数前人踩过的坑。

调试钩子类程序时,我习惯写一个小型测试面板,把GetLastErrorSetWindowsHookEx返回值、回调触发计数这几个关键指标都显示出来,钩子一失效立刻能看见。这个习惯帮我节省了大量定位时间,建议你也试试。希望大家都能写出健壮的全局键鼠工具,遇到问题了也欢迎回来交流各自的排查经验。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 6:20:21

网盘直链下载免费搞定:一个脚本取回八大网盘的真实链接

网盘直链下载免费搞定&#xff1a;一个脚本取回八大网盘的真实链接 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…

作者头像 李华
网站建设 2026/9/7 6:20:14

机器人轨迹规划实战:多段五次多项式平滑运动控制

简介&#xff1a;基于MATLAB的五次多项式轨迹规划仿真脚本&#xff0c;面向机器人路径规划、自动驾驶等动态控制系统开发者和相关专业初学者&#xff0c;也可用于课程实验或毕业设计的辅助参考。资源包共1个文件&#xff0c;为可直接运行的M脚本&#xff0c;压缩包仅1KB&#x…

作者头像 李华
网站建设 2026/9/7 6:18:55

企业级Agent记忆系统实战:Langgraph与DeepAgents构建短期与长期记忆

大模型做 Agent&#xff0c;聊到最后基本都会卡在同一个问题上&#xff1a;记忆。上下文一长就丢人设&#xff0c;用户隔几天再来就认不出&#xff0c;业务数据没法跨会话复用——这些问题不解决&#xff0c;Agent 就只能在 Demo 里待着。这次来看的方案来自码士集团分享的企业…

作者头像 李华
网站建设 2026/9/7 6:17:48

Python模拟键盘批量录入实战:原理、流程与避坑指南

简介&#xff1a;面向需要将条码或数据批量录入业务软件的办公与仓储人员&#xff0c;这份资源模拟条码扫描枪的输入方式&#xff0c;将条码数据和回车等命令预先编辑在文件中&#xff0c;再逐条发送到指定窗口&#xff0c;帮助摆脱手工重复敲键。资源包共77个文件、约443KB&am…

作者头像 李华
网站建设 2026/9/7 6:15:14

ASP.NET C#会员管理系统架构拆解与二次开发实战指南

简介&#xff1a;这是一套长期运行于多家商家的通用会员管理系统源码&#xff0c;面向餐饮娱乐、美容美发、休闲健身、洗浴中心、零售专卖等会员制服务行业&#xff0c;可供技术人员直接部署或二次开发。压缩包共2000个文件&#xff0c;大小约41.51MB&#xff0c;主体为206个C#…

作者头像 李华