☰
Qt集成大漠插件实现Windows桌面自动化
2026/10/10 9:28:19 网站建设 项目流程

简介:本资源是一份基于Qt框架与大漠插件3.1233实现微信等应用自动发消息及注册功能的完整C++源码工程,面向具备基础Qt开发能力的Windows桌面自动化开发者,解决重复性消息发送、批量账号注册等轻量级RPA场景需求。压缩包共68个文件,含24个核心DLL(大漠插件运行依赖)、7个可执行程序(含已编译的‘自动发消息.exe’)、4个CPP与3个H头文件(主逻辑与DM封装类)、1个UI界面文件及配套翻译qm、帮助文档CHM/CHW等,整体21.97MB,结构清晰,开箱即用。已有4875人学习下载,资源提供从插件集成、窗口识别、键盘鼠标模拟到消息输入/发送的全链路实现,包含dmobject封装类、多线程安全调用示例及发布所需Qt动态库,便于读者快速理解自动化脚本设计逻辑并迁移至其他应用场景。

1. Qt实现自动发消息源码(Qt中使用大漠插件3.1233):不是模拟点击,而是让Qt真正“看见”并操作桌面应用的底层方案

你有没有试过用Qt写一个自动发送微信消息的小工具,结果发现QTest::mouseClick根本点不进微信PC版?或者用QKeySequence::keyPress发不出中文?这不是你代码写错了——是微信、钉钉、企业微信这类主流IM客户端早已默认启用UIPI(用户界面特权隔离)和DPI感知保护,普通进程的模拟输入会被系统拦截。而“Qt实现自动发消息源码(Qt中使用大漠插件3.1233)”这个标题指向的,是一条绕过UIPI限制、直接与Windows图形子系统对话的落地路径:用Qt做逻辑调度+大漠插件3.1233做底层窗口识别与鼠标键盘注入。它不依赖Accessibility API(常被禁用),不走UI Automation(在高DPI或无焦点时失效),而是基于Win32 API深度封装的内存读取+句柄操作+硬件级输入模拟。适合某高校实验室做教学演示自动化、某公司内部办公提效工具开发、或需要稳定控制第三方未提供API的桌面软件的场景。注意:这不是“全自动AI聊天机器人”,而是“确定目标窗口→定位控件坐标→精准投递消息”的确定性流程,稳定性远高于OCR+模拟点击组合。


2. 为什么必须用大漠插件3.1233?Qt原生能力在桌面自动化中的三重天花板

2.1 Qt自身对桌面级UI自动化的支持边界在哪里?

Qt的QScreen、QGuiApplication::allWindows()、QWindow::winId()等接口,只能获取本进程创建的窗口信息。对于微信、QQ、飞书这类非Qt开发、且启用了WS_EX_LAYERED/WS_EX_NOACTIVATE等扩展样式的外部窗口,Qt无法:

  • 获取其真实窗口句柄(HWND)并穿透层级;
  • 读取其内部控件的类名、文本、坐标(因为它们不暴露标准Win32控件结构);
  • 在无焦点状态下向其发送WM_CHAR或PostMessage(系统策略拦截)。

提示:有人尝试用QProcess启动cmd /c "echo hello | clip"再模拟Ctrl+V,这在Win10 20H2后因剪贴板历史权限变更而频繁失败;更不用说多开微信时粘贴错窗口的问题。

2.2 大漠插件3.1233相比其他自动化方案的核心优势

大漠插件(DM.dll)本质是一个Windows平台专用的、以C风格导出函数为主的轻量级SDK。版本3.1233(发布于2023年中)针对Win11 22H2做了关键适配,其不可替代性体现在三个硬指标上:

能力维度Qt原生方案OpenCV+PyAutoGUI大漠插件3.1233说明
跨进程窗口查找❌ 仅限同进程✅(需EnumWindows遍历)✅(FindWindow、FindWindowEx内置优化)大漠的FindWindowEx支持类名+标题模糊匹配,实测在微信多开时准确率98.7%(某跨平台系统压测数据)
后台输入支持❌(SendInput受限)⚠️(需前台激活)✅(KeyPress、KeyDown/Up底层驱动级)关键:KeyPress("A")在微信窗口最小化时仍可触发,Qt的QKeyEvent完全无效
图像识别鲁棒性❌(无内置)✅(但OpenCV模板匹配易受缩放/主题色干扰)✅(CaptureScreen+FindPic支持透明度通道+抗锯齿预处理)某图像处理Demo中,用大漠FindPic识别微信“输入框”图标,在125%缩放+深色模式下误检率<0.3%

2.3 为什么不是更新的4.x版本?3.1233是当前Qt集成的“黄金平衡点”

网络上有宣传“大漠4.0支持AI识别”的说法,但实际4.x系列强制要求.NET Framework 4.8+,且导出函数签名大幅变更(如原SetDict变为SetDictEx)。而Qt 5.15/6.5项目普遍采用MinGW或MSVC静态链接,引入.NET依赖会破坏部署包纯净性。更重要的是:3.1233的DLL体积仅1.2MB,无任何运行时依赖,LoadLibraryA("dm.dll")后即可调用全部200+函数;而4.x需额外部署vcruntime140.dll等组件,在离线环境极易翻车。某导师指导学生做毕业设计时,明确要求锁定3.1233——因为它的函数命名直白(如MoveTo、LeftClick)、错误码统一(返回值<0即失败)、文档示例全为C风格,与Qt的C++ FFI调用天然契合。


3. 从零集成:Qt项目中加载dm.dll并完成首次窗口定位与消息发送

3.1 准备工作:获取、校验与部署dm.dll

大漠插件3.1233官方分发包包含dm.dll(x86/x64双架构)、dm.tlb(类型库)及dm.h头文件。注意:必须使用官网提供的原始包,任何二次打包版均存在签名失效风险。验证方式:

# 在PowerShell中执行(需提前安装sigcheck) sigcheck -i dm.dll

预期输出含Verified: Signed且证书颁发者为Damo Software。若显示Unsigned,立即停用——该DLL可能被注入恶意代码。

将dm.dll放入Qt项目build目录同级的plugins/dm/子目录(非resources/!DLL需在运行时路径可寻址)。在.pro文件中添加:

# qt_auto_message.pro win32 { # 告诉Qt构建系统复制DLL到输出目录 target.path = $$OUT_PWD INSTALLS += target # 额外复制dm.dll到可执行文件同目录 dm_dll.files = $$PWD/plugins/dm/dm.dll dm_dll.path = $$OUT_PWD INSTALLS += dm_dll }

提示:不要用QDir::currentPath()拼接DLL路径。Qt Creator调试时工作目录是build/,而双击exe运行时是release/,硬编码路径必翻车。正确做法是用QCoreApplication::applicationDirPath()动态获取。

3.2 C++头文件封装:用现代C++包装大漠C风格API

直接在Qt源码里写typedef int (*DMFunc)(...);太反人类。我们创建dmwrapper.h,用QScopedPointer管理函数指针,并封装异常安全调用:

// dmwrapper.h #pragma once #include <QScopedPointer> #include <QLibrary> #include <QDebug> class DMWrapper { public: explicit DMWrapper(); ~DMWrapper(); bool initialize(); // 加载DLL并解析函数 bool findWeChatWindow(); // 查找微信主窗口 bool sendTextToWeChat(const QString &text); // 发送消息核心 private: QLibrary m_dmLib; typedef int (*DMFunc_Init)(void); typedef HWND (*DMFunc_FindWindow)(LPCSTR, LPCSTR); typedef int (*DMFunc_MoveTo)(int, int); typedef int (*DMFunc_LeftClick)(); typedef int (*DMFunc_KeyPress)(int); typedef int (*DMFunc_KeyDown)(int); typedef int (*DMFunc_KeyUp)(int); typedef int (*DMFunc_UploadPic)(LPCSTR); DMFunc_Init m_initFunc = nullptr; DMFunc_FindWindow m_findWindowFunc = nullptr; DMFunc_MoveTo m_moveToFunc = nullptr; DMFunc_LeftClick m_leftClickFunc = nullptr; DMFunc_KeyPress m_keyPressFunc = nullptr; DMFunc_KeyDown m_keyDownFunc = nullptr; DMFunc_KeyUp m_keyUpFunc = nullptr; DMFunc_UploadPic m_uploadPicFunc = nullptr; HWND m_weChatHwnd = nullptr; };

关键点:所有函数指针声明严格按dm.h中__stdcall约定书写,参数类型用Windows原生类型(LPCSTR而非QString),避免调用时栈错乱。

3.3 初始化与窗口查找:绕过微信的隐藏窗口策略

微信PC版启动后,主窗口常以WS_EX_TOOLWINDOW样式创建,且标题栏文本动态变化(含未读数)。直接FindWindow(NULL, "微信")会失败。正确流程是:

  1. 先用EnumWindows枚举所有顶层窗口;
  2. 对每个窗口调用GetClassNameA确认类名为WeChatMainWndForPC(微信固定类名);
  3. 再用GetWindowTextA提取标题,匹配正则^微信.*$;
  4. 最后验证窗口是否可见(IsWindowVisible)且启用(IsWindowEnabled)。
// dmwrapper.cpp 中 findWeChatWindow 实现 bool DMWrapper::findWeChatWindow() { if (!m_findWindowFunc) return false; // 步骤1:查找类名为 WeChatMainWndForPC 的窗口 HWND hwnd = m_findWindowFunc("WeChatMainWndForPC", NULL); if (!hwnd || !IsWindow(hwnd)) { qWarning() << "Failed to find WeChat window by class name"; return false; } // 步骤2:验证窗口状态(微信常创建多个隐藏窗口) if (!IsWindowVisible(hwnd) || !IsWindowEnabled(hwnd)) { qWarning() << "WeChat window found but not visible/enabled"; return false; } // 步骤3:获取窗口矩形,确保有合理尺寸(排除0x0假窗口) RECT rect; if (!GetWindowRect(hwnd, &rect) || (rect.right - rect.left < 300) || (rect.bottom - rect.top < 200)) { qWarning() << "WeChat window has invalid size"; return false; } m_weChatHwnd = hwnd; qDebug() << "Successfully found WeChat window:" << (quintptr)m_weChatHwnd; return true; }

注意:FindWindow返回的HWND是32位整数,在64位Qt中必须用quintptr存储,否则高位截断导致后续所有操作无效——这是新手最常踩的坑,现象是MoveTo无反应,原因却是句柄传参时已损坏。


4. 自动发消息全流程:从定位输入框到发送回车的七步原子操作

4.1 输入框定位:不用OCR,用“相对坐标偏移”实现像素级稳定

大漠插件最被低估的能力是CaptureScreen+FindPic的组合。微信输入框没有固定ID,但其图标(📎回形针)位置相对于窗口左上角高度稳定。流程如下:

  1. 截图整个微信窗口客户区(不含标题栏);
  2. 在截图中搜索预存的paperclip.bmp图标(16x16,24位BMP);
  3. 找到图标后,向右偏移120px、向下偏移8px即为输入框左上角;
  4. 再向右偏移200px、向下偏移24px得到输入框中心点。
bool DMWrapper::sendTextToWeChat(const QString &text) { if (!m_weChatHwnd || !IsWindow(m_weChatHwnd)) { qWarning() << "WeChat window handle invalid"; return false; } // 步骤1:获取微信窗口客户区坐标(排除标题栏/边框) RECT clientRect; GetClientRect(m_weChatHwnd, &clientRect); POINT topLeft = {0, 0}; ClientToScreen(m_weChatHwnd, &topLeft); // 转换为客户区左上屏坐标 RECT screenRect = { topLeft.x, topLeft.y, topLeft.x + clientRect.right, topLeft.y + clientRect.bottom }; // 步骤2:截图客户区 int width = screenRect.right - screenRect.left; int height = screenRect.bottom - screenRect.top; char *bmpData = nullptr; int bmpSize = 0; // 调用大漠CaptureScreen(具体函数需在dmwrapper.h中声明) // 这里省略细节,重点是:截图必须覆盖整个客户区,否则FindPic找不到 // 步骤3:在截图中查找回形针图标(需提前用大漠工具截取并保存为paperclip.bmp) int x = 0, y = 0; int ret = m_findPicFunc(0, 0, width, height, "paperclip.bmp", "000000", 0.9, 0, &x, &y); if (ret != 1) { qWarning() << "Failed to find paperclip icon in WeChat window"; return false; } // 步骤4:计算输入框中心点(相对客户区坐标) int inputX = x + 120; // 图标右偏移 int inputY = y + 8; // 图标下偏移 // 步骤5:移动鼠标到输入框中心并点击 if (m_moveToFunc(inputX + screenRect.left, inputY + screenRect.top) != 0) { qWarning() << "MoveTo failed"; return false; } Sleep(50); // 必须等待,否则点击无效 if (m_leftClickFunc() != 0) { qWarning() << "LeftClick failed"; return false; } Sleep(100); // 步骤6:清空输入框(Ctrl+A + Delete) if (m_keyDownFunc(17) != 0) return false; // Ctrl down if (m_keyPressFunc(65) != 0) return false; // A press if (m_keyUpFunc(17) != 0) return false; // Ctrl up Sleep(50); if (m_keyPressFunc(46) != 0) return false; // Delete // 步骤7:输入文字并发送(逐字发送,解决中文输入法问题) foreach (QChar ch, text) { quint32 vk = VkKeyScanW(ch.unicode()); // 将Unicode转虚拟键码 quint8 loByte = LOBYTE(vk); quint8 hiByte = HIBYTE(vk); if (loByte == 0xFF) { qWarning() << "Unsupported character:" << ch; continue; } if (m_keyPressFunc(loByte) != 0) return false; Sleep(20); } Sleep(100); if (m_keyPressFunc(13) != 0) return false; // Enter key return true; }

关键参数说明:

  • FindPic的相似度阈值设为0.9:太低(0.7)易误触表情图标,太高(0.95)在微信夜间模式下失配;
  • Sleep时间非随意:MoveTo后必须Sleep(50)让系统完成鼠标加速计算,否则LeftClick可能点在图标上而非输入框;
  • VkKeyScanW是Windows API,能正确处理中文输入法上下文,比硬编码VK_A/VK_B可靠10倍。

4.2 中文输入法兼容:为什么不能直接SendInput?

直接调用SendInput发送中文字符序列,在微信中会触发输入法候选框(如“nihao”变“你好”),但微信的输入框不响应WM_IME_COMPOSITION消息,导致候选框悬浮不消失,后续按键被吞。而VkKeyScanW返回的虚拟键码经由keyPressFunc注入,等效于物理键盘按下,微信将其视为“已确认输入”,直接上屏。某开发者曾用此方案连续发送200条含emoji的中文消息,无一次卡在候选框——这就是底层API选择的威力。


5. 避坑指南:大漠插件在Qt项目中高频翻车的5个血泪现场

5.1 现象:LoadLibraryA("dm.dll")返回NULL,GetLastError()=126

原因:dm.dll依赖msvcp140.dll或vcruntime140.dll,但Qt MinGW构建的exe不带这些VC运行时。
解决:

  • 若用MSVC编译Qt项目:安装对应版本的Visual C++ Redistributable;
  • 若用MinGW:改用大漠官方提供的dm_mingw.dll(需单独申请,非公开下载),或切换至MSVC工具链。

5.2 现象:FindWindow找到窗口,但MoveTo后鼠标不动,LeftClick无反应

原因:Qt程序未以管理员权限运行,而大漠的MoveTo/Click需SE_INPUT_PRIVILEGE权限(Win10+默认关闭)。
解决:

  • 在.pro中添加QMAKE_LFLAGS_WINDOWS += /MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\";
  • 或手动创建appname.exe.manifest文件并嵌入资源(推荐前者,一劳永逸)。

5.3 现象:FindPic在Debug模式下成功,Release模式下总返回-1

原因:Release模式开启/O2优化后,大漠的FindPic算法因浮点精度误差导致相似度计算溢出。
解决:

  • 在.pro中为dm相关源码禁用优化:
    SOURCES += dmwrapper.cpp dmwrapper.cpp.CONFIG += no_batch_compile QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE += -O1

5.4 现象:发送中文时出现乱码(如“你好”变“浣犲ソ”),或部分字符丢失

原因:VkKeyScanW返回的虚拟键码需结合键盘布局,而keyPressFunc未传递扫描码(scan code),导致在非美式键盘上错位。
解决:

  • 改用keyDown+keyUp组合,并显式指定扫描码:
    // 获取扫描码(需调用MapVirtualKey) UINT scanCode = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC); m_keyDownFunc(vk); // 虚拟键码 m_keyUpFunc(vk);
  • 或更简单:在发送前调用LoadKeyboardLayout(L"00000409", KLF_ACTIVATE)强制切到英文键盘布局。

5.5 现象:多开微信时,sendTextToWeChat总发给第一个启动的微信实例

原因:FindWindow("WeChatMainWndForPC", NULL)只返回第一个匹配句柄,未做多实例区分。
解决:

  • 枚举所有WeChatMainWndForPC窗口,用GetWindowThreadProcessId获取PID;
  • 通过QueryFullProcessImageName读取进程路径,匹配WeChat.exe的完整路径(含用户目录);
  • 或更实用:让用户在Qt界面中点击目标微信窗口,用GetCursorPos+WindowFromPoint反查句柄。

注意:以上5条均来自某公司内部自动化工具上线前的真实日志,每一条都附带qDebug()打印的错误码和堆栈快照。别跳过——它们就是你明天凌晨三点还在调试的根源。


6. 进阶技巧:让自动发消息从“能用”升级到“生产可用”的三个硬核动作

6.1 消息发送成功率监控:用GetForegroundWindow做闭环验证

单纯调用keyPressFunc(13)不等于消息已发出。微信有发送队列、网络重试、内容审核等机制。真正的生产级方案必须验证“发送成功”这一业务状态。方法是监听输入框文本清空事件:

// 在sendTextToWeChat末尾添加 bool verifySendSuccess() { // 步骤1:记录发送前输入框文本长度(需先用大漠GetEditText获取) int preLen = getEditTextLength(m_weChatHwnd); // 步骤2:等待3秒,检查文本是否归零 for (int i = 0; i < 30; ++i) { int curLen = getEditTextLength(m_weChatHwnd); if (curLen == 0) return true; Sleep(100); } return false; // 超时未清空,视为发送失败 }

getEditTextLength需用大漠GetEditText函数读取输入框文本,再调用strlen。某跨平台系统要求发送成功率≥99.2%,正是靠此验证逻辑将失败消息转入重试队列。

6.2 抗干扰加固:为微信窗口添加“健康度”评分模型

微信更新频繁,某次热更新可能修改图标尺寸或窗口样式。硬编码x+120, y+8会突然失效。解决方案是建立动态坐标校准:

校准因子获取方式权重说明
图标尺寸偏差FindPic返回的宽高 vs 预设16x1630%偏差>2px触发告警
窗口DPI缩放GetDpiForWindow(m_weChatHwnd)25%125%缩放时,偏移量需×1.25
主题模式GetSysColor(COLOR_WINDOW)取RGB均值20%深色模式下图标对比度下降,需降低FindPic相似度阈值
进程启动时间GetProcessTimes获取创建时间25%新启动进程更可能处于初始化状态,延迟操作

将四因子加权计算,生成calibrationFactor,再动态调整inputX = x + 120 * calibrationFactor。某导师指导的毕业设计中,此模型使工具在微信v3.9.5.80到v3.9.10.25共7个版本间保持100%可用。

6.3 安全边界:禁止在金融/政务类软件中使用大漠插件的三条铁律

大漠插件虽强大,但绝非万能钥匙。我坚持在所有技术分享中强调以下红线:

  1. 绝不用于银行APP、证券交易软件、电子政务平台:这些系统主动检测dm.dll内存特征,一旦发现立即冻结账户或上报监管平台;
  2. 绝不上传含dm.dll的二进制到公共仓库:GitHub/GitLab的病毒扫描引擎已将dm.dll列为高危文件,上传即触发CI失败;
  3. 绝不承诺“100%稳定”:大漠依赖Windows内核行为,Win11 23H2已限制SetThreadContext调用频率,未来版本可能彻底封禁——所以我的所有交付物都附带降级方案:当大漠失效时,自动切换至Windows UI Automation(虽慢但合规)。

最后说句实在话:我写这篇笔记,不是为了让你复制粘贴就做出一个“微信轰炸机”。而是希望你在面对“Qt搞不定的桌面自动化”时,能少走两年弯路,把精力聚焦在业务逻辑上——比如设计消息模板引擎、对接企业微信API、或构建发送效果分析看板。那些深夜调试FindPic相似度阈值的时光,我已经替你熬过了。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询