(2)自动接收QQ文件-QQ自动化(.Net)

c整理 | 小耕家的喵大仙

出品 | CSDN(ID:lichao19897314)

Q Q | 978124155

关于项目背景和微信自动化学习介绍

   因为前面写了很多关于微信自动化的文章,网上有一位朋友联系我说他是做广告行业的,有时候除了微信对接客户还需要通过QQ来处理工作,因为广告行业中有大量客户还是使用QQ传送文件给他们做处理,所以需要手动下载并根据QQ用户按天归档,每天大概有上千份文件,所以他说人工接收和归档工作量特别的大,所以联系我想帮他做个自动接收QQ文件并按照联系人和发送文件的日期进行归档的功能。经过一晚上的模式和技术准备,发现是完全可行,所以在微信自动化的基础上进行了改造后实现了QQ文件自动接收的功能,并且经过生产环境的使用和验证,效果良好,大大减少了他们的工作。

如果有兴趣的朋友可以看下我微信自动化的文章!因为底层实现和微信自动化同根同源,感兴趣的点个赞关注支持下原创。

(1)C#开启探索微信自动化之路-微信UI自动化

(2)C#创建微信窗体自动化实例-微信UI自动化

(3)C#针对系统热键管理-微信UI自动化

(4)C#采集微信通讯录和联系人-微信UI自动化

(5)C#实现针对微信窗体鼠标静默点击-微信UI自动化

(6)C#搜索微信通讯录联系人-微信UI自动化

(7)C#实现微信消息群发-微信UI自动化

(8)C#监控微信进程运行状态-微信UI自动化

(9)C#监控微信网络连接状态-微信UI自动化

(11)C#实现微信窗体尺寸跟随调整-微信UI自动化

(12)C#采集微信聊天记录及历史消息-微信UI自动化

(13)C#实现自动回复微信消息-微信UI自动化

(14)C#针对微信界面元素截图操作-微信UI自动化

(15)C#实现对微信窗体的行为管控-微信UI自动化

(16)C#实现微信多开-微信UI自动化

(17)C#实现微信聊天文件接收及下载-微信UI自动化

(18)C#采集微信群成员信息-微信UI自动化(.Net)

(19)C#添加微信好友(可批量添加)--微信UI自动化(.Net)

  • QQ版本以及软件功能效果

环境要求采用的QQ版本为当前最新版本QQ👇

QQ自动接收文件的效果视频呈现

功能介绍

(1)自主监控QQ主面板的实时消息,分析实时消息中是否包含文件类型的消息,如果分析有新文件消息则自动打开与之对应的联系人聊天窗体。

(2)自动分析打开的聊天窗体中的文件传输面板UI信息,抓取待接收的文件列表信息反馈给自动化软件,并自动触发QQ接收文件按钮的事件。

(3)监控所有处于打开状态的QQ聊天窗口的文件传输面板的实时状态,将文件接收情况反馈给自动化软件。

(4)如果发现某个聊天窗口文件全部接收完毕,并且没有新文件过来则自动关闭聊天窗体,提高自动化响应速度和整体性能。

(5)按照日期和QQ用户进行文件归档操作。

注意事项

在软件执行前,请手动将【合并会话窗口】取消,防止窗口合并,本软件需要每个聊天窗口独立显示。

软件部分截图

  • 技术实现思路和示例代码 

         以上QQ自动接收文件所实现的功能都是基于UI自动化机制,安全可靠。

  1. 找到QQ主窗体句柄和QQ进程ID,通过QQ进程ID构建UIA3Automation的自动化测试实例。
  2. 构建针对QQ自动化测试实例成功后,我们创建一个后台监听任务,监听QQ主窗体的消息面板。监听任务判断消息面板中的UI对象中的内容是否有修改,如果有修改则判断为新消息,并分析新消息是否为文件消息。
  3. 如果发现该新消息为文件消息,则自动打开本新消息的聊天面板,手动触发QQ接收文件的机制。
  4. 打开对应的聊天窗口后,我们需要实时监测每个聊天窗口的文件传输面板中的UI信息,获取到所有待接收和正在接收的文件信息,通过接收状态执行对应的操作,并收集接收状态。
  5. 如果发现某个聊天面板中文件全部接收完毕则强制关闭QQ聊天面板提高整体性能。
  6. 将成功接收到的文件从QQ默认文件夹中复制到软件的归档目录中,并按照QQ用户名和日期规则进行归档,并上传至FTP服务器保持副本,提高文件可用性。

核心示例代码 

加载QQ主窗体并构建自动化测试实例

 public bool Load(){int weChatID = 0;IntPtr hwnd = FindWindow(null, "QQ");if (hwnd != IntPtr.Zero){GetWindowThreadProcessId(hwnd, out weChatID);}else{return false;}application = FlaUI.Core.Application.Attach(weChatID);automation = new UIA3Automation();Window = application.GetMainWindow(automation);var windowSource = application.GetAllTopLevelWindows(automation);if (Window == null)return false;startPanel = string.Format("/Pane[{0}]", Window.FindAllChildren().Length-1);return true;}

监控QQ主面板实时文件消息

using FlaUI.QQ.FileReceive;
using FlaUI.WinForm.UIAuto.Model;
using FlaUI.QQ.FileReceive;
using FlaUI.QQ.FileReceive.Log;
using FlaUI.QQ.FileReceive.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace FlaUI.WinForm.UIAuto.Business.WX.Task
{/// <summary>/// 新文件消息检测/// </summary>public class UI_New_Receive_File_Task : UI_QQ_Element_Base_Task{private List<QQFileMessageDTO> historyMessageSource { get; set; }public override void Stop(){base.Stop();}public override void Start(){if (State == TaskState.Stop){State = TaskState.Runing;}else{return;}Thread th = new Thread(new ThreadStart(() =>{while (State == TaskState.Runing){try{LoopQQMainMessagePanel();}catch (Exception ex){SetMessage("错误:" + ex.Message);}Thread.Sleep(100);}}));th.Start();base.Start();}private void LoopQQMainMessagePanel(){var currentChatList = UI_QQ_Window.Current.Find("/Pane/Pane[4]/Pane[2]/Pane[4]/Pane/Pane/Pane/Pane/Pane/Pane/Pane/Pane/Pane/Pane/Pane/Pane");if (currentChatList == null || currentChatList.ControlType != FlaUI.Core.Definitions.ControlType.Pane){Thread.Sleep(300);return;}var source = currentChatList.FindAllChildren();var tempMessageSource = new List<QQFileMessageDTO>();source.ToList().ForEach(QQMessageItem =>{if (QQMessageItem.ControlType == FlaUI.Core.Definitions.ControlType.ListItem){var buttonName = QQMessageItem.Name;var lastMessage = QQMessageItem.Patterns.Value.PatternOrDefault?.Value;var messageitem = new QQFileMessageDTO { UserName = buttonName, Message = lastMessage };tempMessageSource.Add(messageitem);if (historyMessageSource != null){var cnt = historyMessageSource.Count(s => s.UserName == messageitem.UserName && messageitem.Message == s.Message);if (cnt == 0){var newMessage = messageitem.Message;if (IsFileMessage(newMessage)){var fileName = GetFileName(newMessage);SetMessage("来自【" + messageitem.UserName + "】新文件【" + fileName + "】");messageitem.FileName = fileName;UI_QQ_Window.Current.Focus();QQMessageItem.DoubleClick();}}}}});historyMessageSource = tempMessageSource;}private bool IsFileMessage(string message) {if(string.IsNullOrEmpty(message))	return false;if (message.Contains("分享文件\"") && message.Substring(message.Length - 1, 1).Contains("\"")){return true;}return false;}private string GetFileName(string message) {int index = message .IndexOf("分享文件\"");message= message.Substring(index, message.Length -index );message = message.Replace("分享文件\"", "");message = message.Substring(0, message.Length - 1);return message;}}
}

 从打开的QQ聊天面板获取文件信息和接收情况

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using FlaUI.Core.AutomationElements;
using FlaUI.QQ.FileReceive.Log;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;namespace FlaUI.QQ.FileReceive
{/// <summary>/// 接收QQ单窗口面板里面的文件/// </summary>public class UI_Window_File_Read_Task : UI_QQ_Element_Base_Task{public override void Start(){if (State == TaskState.Stop){State = TaskState.Runing;}else{return;}Thread th = new Thread(new ThreadStart(() =>{while (State == TaskState.Runing){try{FindAllChatWindow();}catch (Exception ex){SetMessage("错误:" + ex.Message);}Thread.Sleep(100);}}));th.Start();base.Start();}private AutomationElement FindAllChatWindow(){var ss = WindowApi.GetAllDesktopWindows();foreach (var item in ss){if (item.szClassName != "TXGuiFoundation")continue;var window = UI_QQ_Window.Current.Automation.FromHandle(item.hWnd);if (window == null)continue;var current = QQUserFileManger.Current.Get(window.Name, GetChatWindowType(window));if (current.QQChatWindowType == QQChatType.User){ReceiveUserFile(window, current);}else{ReceiveGroupFile(window, current);}}return null;}/// <summary>/// 接收用户发送的文件/// </summary>/// <param name="window"></param>private void ReceiveUserFile(AutomationElement window, QQUserFileSourceDTO dto){var receiveFilePanel = window.FindFirstByXPath(@"/Pane[3]/Pane/Pane/Pane/Pane[2]/Pane/Pane[1]/Pane/Pane/Pane/Pane/Pane[1]/Pane/Pane");if (receiveFilePanel == null){//可以执行关闭dto.FileSource.Completed();//关闭CloseChatWindow(window);return;}List<string> executeingFileSource = new List<string>();foreach (var fileItem in receiveFilePanel.FindAllChildren()){if (fileItem.ControlType != Core.Definitions.ControlType.ListItem)continue;executeingFileSource.Add(fileItem.Name);ClickReceiveFile(fileItem, dto, window);}//判断是否接收完成foreach (var file in dto.FileSource){if (executeingFileSource.Count(s => file.FileName == s) <= 0){file.IsReceiveCompleted = true;}}}private void CloseChatWindow(AutomationElement window) {var closeButton = window.FindFirstByXPath("/Pane[4]/Button[3]");if (closeButton != null){closeButton.Click();}}private void ClickReceiveFile(AutomationElement fileItem, QQUserFileSourceDTO dto, AutomationElement window){//如果存在for (var i = 1; i <= 2; i++){var reviButton = fileItem.FindFirstByXPath("/Pane[2]/Pane/Pane[3]/Pane[2]/Button[" + i + "]");if (reviButton != null && reviButton.Name == "接收"){SystemLog.Info("开始接收新文件:" + fileItem.Name);window.Focus();reviButton.Click();dto.AddFile(fileItem.Name, true);break;}}}/// <summary>/// 群/// </summary>/// <param name="window"></param>/// <param name="dto"></param>private void ReceiveGroupFile(AutomationElement window, QQUserFileSourceDTO dto){CloseChatWindow(window);//if (dto.GroupExecute)//	return;//dto.GroupExecute = true;	//Task.Run(new Action(() =>//{//	//只能从文件是否完成//	//点击文件//	var fileTab = window.FindFirstByXPath("/Pane[3]/Pane/Pane/Pane/Pane[1]/Pane/Pane/Pane/ToolBar[1]/TabItem[4]");//             if (fileTab == null)//             {//                 dto.GroupExecute = false;//                 return;//             }//             window.Focus();//	fileTab.Click();//	//刷新//	var moreBtn = window.FindFirstByXPath("/Pane[3]/Pane/Pane/Pane/Pane[1]/Pane/Pane/Pane/ToolBar[1]/TabItem[4]");//             if (moreBtn == null)//             {//                 dto.GroupExecute = false;//                 return;//             }//             moreBtn.Click();//	var refBtn = window.FindFirstByXPath("/Pane[3]/Pane/Pane/Pane/Pane[1]/Pane/Pane/Pane/ToolBar[1]/TabItem[4]");//             if (refBtn == null)//             {//                 dto.GroupExecute = false;//                 return;//             }//             window.Focus();//	refBtn.Click();//             dto.GroupExecute = false;//         }));}private QQChatType GetChatWindowType(AutomationElement window){var list = window.FindFirstByXPath("/Pane[3]/Pane/Pane/Pane/Pane[2]/Pane/Pane[1]/Pane/Pane/Pane/Pane/Pane/Pane[3]/List");if (list != null && list.Name == "成员列表" && list.ControlType == Core.Definitions.ControlType.List){return QQChatType.Group;}return QQChatType.User;}public override void Stop(){base.Stop();}}public class QQUserFileManger : List<QQUserFileSourceDTO>{public event EventHandler<QQUserFileSourceDTO> DataChange;private QQUserFileManger() { }private static QQUserFileManger current = new QQUserFileManger { };public static QQUserFileManger Current { get { return current; } }/// <summary>/// 获取当前聊天对象窗体DTO/// </summary>/// <param name="name"></param>/// <param name="type"></param>/// <returns></returns>public QQUserFileSourceDTO Get(string name, QQChatType type){var current = this.FirstOrDefault(item => item.QQChatWindowName == name && item.QQChatWindowType == type);if (current == null){current = new QQUserFileSourceDTO { QQChatWindowName = name, QQChatWindowType = type };this.Add(current);DoDataChange();}return current;}public void DoDataChange(){if (DataChange != null){DataChange(this, null);}}public List<DisplayFileDTO> Show(){List<DisplayFileDTO> source = new List<DisplayFileDTO>();foreach (var item in this){foreach (var item1 in item.FileSource){var log = "等待接收";if (item1.IsReceive){log = "正在接收";if (item1.IsReceiveCompleted)log = "接收完成";}source.Add(new DisplayFileDTO{Id = item1.Id,QQChatName = item.QQChatWindowName,QQChatType = item.QQChatWindowType == QQChatType.User ? "用户文件" : "群文件",FileName = item1.FileName,RecevieLog = log});}}return source;}}public class DisplayFileDTO{public Guid Id { get; set; }public string QQChatName { get; set; }public string QQChatType { get; set; }public string FileName { get; set; }public string RecevieLog { get; set; }}/// <summary>/// 某个用户或者群下的文件集合/// </summary>public class QQUserFileSourceDTO{public QQUserFileSourceDTO(){FileSource = new QQFileSource();}/// <summary>/// QQ聊天窗口名称/// </summary>public string QQChatWindowName { get; set; }public QQChatType QQChatWindowType { get; set; }/// <summary>/// 是否在处理中/// </summary>public bool GroupExecute { get; set; } = false;public QQFileSource FileSource { get; set; }public QQFileDTO AddFile(string file, bool IsReceive = false){var item = new QQFileDTO { FileName = file, Id = Guid.NewGuid(), IsReceive = IsReceive };FileSource.Add(item);QQUserFileManger.Current.DoDataChange();return item;}}public enum QQChatType{/// <summary>/// 用户/// </summary>User,/// <summary>/// 群/// </summary>Group}public class QQFileSource : List<QQFileDTO>{public void Completed() {foreach (var item in this){item.IsReceiveCompleted = true;}}}/// <summary>/// QQ文件对象/// </summary>public class QQFileDTO{public Guid Id { get; set; }/// <summary>/// 文件名称/// </summary>public string FileName { get; set; }/// <summary>/// 是否开始接收/// </summary>public bool IsReceive { get; set; } = false;bool isReceiveCompleted = false;/// <summary>/// 是否接收完成/// </summary>public bool IsReceiveCompleted{get { return isReceiveCompleted; }set{isReceiveCompleted = value;QQUserFileManger.Current.DoDataChange();}}}
}

以上是核心组件及代码思路,因为代码关联类比较多,无法在本篇全部博客呈现!如果需要源码请加本人QQ 978124155

上一篇 C#监听QQ消息自动回复-QQ自动化icon-default.png?t=N7T8https://blog.csdn.net/lichao19897314/article/details/136038468

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

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

相关文章

使用 Java 原生或 Hutool 工具包编写非对称加解密的工具类

1、什么是非对称加密 使用一对&#xff08;2个&#xff09;密钥&#xff1a;一个用于加密信息&#xff0c;另一个则用于解密信息。有“公钥&#xff08;Public Key&#xff09;”和“私钥&#xff08;Private Key&#xff09;”之分。 非对称加密的“公钥”和“私钥”是成对出现…

c++24.4.13-const修饰指针

1、const修饰指针-常量指针 2、const修饰常量-指针常量 3、const既修饰指针又修饰常量 示例

maven之pom中的build标签

1、build标签分类 1.1、全局配置&#xff08;project build&#xff09; 针对整个项目的所有情况都有效。 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"htt…

什么?你设计接口什么都不考虑?

如果让你设计一个接口&#xff0c;你会考虑哪些问题&#xff1f; 1.接口参数校验 接口的入参和返回值都需要进行校验。 入参是否不能为空&#xff0c;入参的长度限制是多少&#xff0c;入参的格式限制&#xff0c;如邮箱格式限制 返回值是否为空&#xff0c;如果为空的时候是…

R语言数据可视化:基本绘图系统

目录 plot函数 par函数 hist函数 boxplot函数 plot函数应用实战 全局参数 R语言中有三大绘图系统包括基本绘图系统&#xff0c;Lattice绘图系统&#xff0c;ggplot2绘图系统 基本绘图系统 在R语言中&#xff0c;以下函数通常用于创建和定制图形&#xff1a; plot 函数…

僵尸进程和孤儿进程

目录 引言僵尸进程僵尸进程的状态僵尸进程周边知识 孤儿进程孤儿进程的状态 进程中的其他状态①.R---表示进程运行状态。②.S---表示进程的休眠状态。(进程什么都没做)③T 和 t 进程的运行、阻塞和挂起运行阻塞挂起状态&#xff1a; 引言 今天我们来将僵尸进程和孤儿进程以及其…

暴力枚举法

虽然暴力枚举法有时候效率低&#xff0c;时间复杂度高&#xff0c;但是在面对小规模数据集的时候&#xff0c;暴力枚举法往往是很好的思维利器。 B: 01 串的熵&#xff08;5分&#xff09; 问题描述 #include <iostream> #include <cmath> #include <algorithm…

【前端】es-drager 图片同比缩放 缩放比 只修改宽 只修改高

【前端】es-drager 图片同比缩放 缩放比 ES Drager 拖拽组件 (vangleer.github.io) 核心代码 //初始宽 let width ref(108)//初始高 let height ref(72)//以下两个变量 用来区分是单独的修改宽 还是高 或者是同比 //缩放开始时的宽 let oldWidth 0 //缩放开始时的高 let o…

【好用】推荐10套后端管理系统前端模板

后台管理系统前端模板是开发者在构建后台管理系统时使用的一种工具&#xff0c;它提供了预先设计好的界面和组件&#xff0c;以帮助开发者快速搭建出功能完善、用户体验良好的管理系统。以下是V哥整理的10款流行的后台管理系统前端模板&#xff0c;它们基于不同的技术栈和设计理…

【研发日记】CANoe自动化测试的配置方式(三)——SystemVariables数组方式

文章目录 前言 一、例程功能 二、仿真ECU 三、SystemVariables数组&#xff1a; 四、测试模块 五、测试运行效果 六、分析和应用 总结 前言 近期在做的一个自动化测试项目&#xff0c;尝试了一种以前没用过的测试配置方式&#xff0c;感觉效果还不错。然后又回顾了一下以…

Redis数据持久化 AOF RDB

Redis数据持久化 AOF RDB 1、单点 redis 的问题2、主从复制2.1 命令传播 3、Redis的持久化3.1 AOF写回策略重写机制后台重写 3.2 RDB&#xff08;默认方式&#xff09;RDB 方式&#xff1a;执行快照时&#xff0c;数据能被修改吗&#xff1f;RDB 方式总结 3.3 RDB 和 AOF 组合&…

场景:如何做数据清理

如果数据清理简单粗暴按时间进行清理&#xff0c;同时时间字段并没有增加索引就会出问题 如果没有增加索引&#xff0c;他就会进行全表扫描&#xff0c;并且会给全表的数据上一个x锁 会阻塞其他的线程 解决方案参考阿里云DMS数据清理方案 这个SQL查询的目的是从名为table_hol…