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

整理 | 小耕家的喵大仙

出品 | 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

  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
回答: CAPL(Communication Access Programming Language)是一种用于编写通信测试脚本的语言,常用于CANoe中进行自动化测试。CAPL脚本的代码结构可以根据需求进行灵活编写,但通常包括以下几个部分:引用\[2\] 1. 前言:在脚本的开头部分,可以进行一些初始化设置和声明变量等操作。 2. 主要逻辑:在主要逻辑部分,可以编写测试用例的执行流程和相应的功能实现。可以使用条件语句、循环语句、函数调用等来实现不同的测试场景。 3. 函数定义:CAPL脚本中可以定义自己的函数,用于封装一些常用的操作或功能。这些函数可以在主要逻辑中被调用,提高代码的复用性和可读性。 4. 结束语:在脚本的结尾部分,可以进行一些清理操作或输出测试结果等。 对于UDS(Unified Diagnostic Services)的自动化测试,可以根据具体需求编写相应的CAPL脚本。在脚本中,可以使用UDS相关的函数和命令来实现对诊断功能的测试,包括发送诊断请求、接收诊断响应、解析响应数据等。同时,根据引用\[1\]中提到的半自动化脚本的需求,可以在脚本中添加手动确认功能的步骤,以确保功能配置的正确性。 总之,CAPL脚本可以根据具体的测试需求进行编写,通过调用相关函数和命令来实现对UDS功能的自动化测试。 #### 引用[.reference_title] - *1* *2* [UDS-基于CAPL的半自动化脚本编写流程](https://blog.csdn.net/wjz110201/article/details/124704882)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [搭配Panel界面及使用Capl识别配置文件TXT编写基于14229的UDS自动化测试流程)](https://blog.csdn.net/qq_36407982/article/details/109131802)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小耕家的喵大仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值