Windows环境+C#实现显示接口测试

发布于:2024-07-11 ⋅ 阅读:(22) ⋅ 点赞:(0)

代码如下:

using Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Tools;
using DisplayMode = Models.DisplayMode;

namespace TestItem
{
    public partial class VideoTestManager : Form
    {
        private string originalDirectory = System.Environment.CurrentDirectory; // 保存当前目录
        private string programName = string.Empty;//程式名称
        public event Action<bool> CallExit = null;//回调函数
        private bool isPass = false;
        private string readValues = null; // 测试参数
        private string testArgs = null;//测试参数
        private List<string> testItem=null;//测试项目
        private string playFileName = string.Empty;//播放文件名称
        private List<DisplayEntity> displayEntity;//显示实体
        private int random_number = 0;//随机数
        private int input_number = 0;//输入数

        #region 构造函数
        //显示模式
        public VideoTestManager()
        {
            InitializeComponent();
            this.CallExit += (isPass) => { }; // 初始化事件
            this.Load += VideoTestManager_Load;
            this.FormClosing += VideoTestManager_FormClosing;
            this.KeyDown += VideoTestManager_KeyDown;
            this.KeyPreview = true; // Enable the form to receive key events
        }
        #endregion

        #region 窗体加载
        private const byte VK_LEFT = 0x25;
        private const byte VK_RIGHT = 0x27;
        private async void VideoTestManager_Load(object sender, EventArgs e)
        {
            if (await this.GetTestArgs())
            {
                this.SetHeaderStyle(); // 设置表头信息样式
                this.displayEntity = new List<DisplayEntity>();//初始化显示实体
                timer_Test.Enabled = true;
            }
        }
        #endregion

        #region 切屏显示
        /// <summary>
        /// 切屏显示
        /// </summary>
        /// <param name="mode"></param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        private void SwitchDisplayMode(DisplayMode mode)
        {
            string argument;
            switch (mode)
            {
                case DisplayMode.Internal:
                    argument = "/internal";
                    break;
                case DisplayMode.Clone:
                    argument = "/clone";
                    break;
                case DisplayMode.Extend:
                    argument = "/extend";
                    break;
                case DisplayMode.External:
                    argument = "/external";
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            Process.Start("DisplaySwitch.exe", argument);
        }
        #endregion

        #region 获取测试参数
        private async Task<bool> GetTestArgs()
        {
            try
            {
                //获取程式名称
                this.programName = AuxiliaryItemArray.GetProgramName(this.lbl_ShowResult) != null ? AuxiliaryItemArray.GetProgramName(this.lbl_ShowResult) + @".exe" : null;
                if (this.programName == null)
                    return false;

                // 获取测试参数
                this.testArgs = AuxiliaryItemArray.GetTestParameter(this.originalDirectory, this.programName, this.lbl_ShowResult);
                if (this.testArgs == null)
                    return false;

                //解析参数
                string[] args = this.testArgs.Split('|');

                this.playFileName = args[1].Split('=')[1];

                this.testItem = new List<string>();
                this.testItem = args[0].Split(',').ToList();
                this.lbl_TestArgs.BeginInvoke(new Action(() => { 
                    this.lbl_TestArgs.Text= args[0];
                }));

                return this.testItem.Count>0;
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    AuxiliaryItemArray.Loginfo($@"获取测试参数:{ex.Message}", false, lbl_ShowResult);
                }));
                return false;
            }
        }
        #endregion

        #region 播放视频
        /// <summary>
        /// 播放视频
        /// </summary>
        /// <param name="playFileName">播放文件</param>
        /// <returns></returns>
        private async Task<bool>Mp4Play(string playFileName)
        {
            try
            {
                //设置播放器URL
                // 获取当前目录
                string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
                // 拼接视频文件路径
                string videoPath = Path.Combine(currentDirectory, "Video", playFileName);

                if (File.Exists(videoPath))
                {
                    // 设置播放器URL
                    wmpPlayer.URL = videoPath;
                    // 设置循环播放模式
                    wmpPlayer.settings.setMode("loop", true);
                    return true;
                }
                else
                {
                    this.Invoke(new Action(() =>
                    {
                        AuxiliaryItemArray.Loginfo("视频文件未找到: " + videoPath, false, lbl_ShowResult);
                    }));
                    return false;
                }
            }
            catch(Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    AuxiliaryItemArray.Loginfo($@"播放MP4错误:{ex.Message}", false, lbl_ShowResult);
                }));
                return false;
            }
        }
        #endregion

        #region 设置表头信息样式
        private void SetHeaderStyle()
        {
            // 设置参数列宽度,使用百分比
            this.tabPanel_Args.ColumnStyles[0].SizeType = SizeType.Percent;
            this.tabPanel_Args.ColumnStyles[0].Width = 25;
            this.tabPanel_Args.ColumnStyles[1].SizeType = SizeType.Percent;
            this.tabPanel_Args.ColumnStyles[1].Width = 25;
            this.tabPanel_Args.ColumnStyles[2].SizeType = SizeType.Percent;
            this.tabPanel_Args.ColumnStyles[2].Width = 25;
            this.tabPanel_Args.ColumnStyles[3].SizeType = SizeType.Percent;
            this.tabPanel_Args.ColumnStyles[3].Width = 25;
        }
        #endregion

        #region 关闭窗体
        private void VideoTestManager_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.readValues = JsonConvert.SerializeObject(this.displayEntity, Formatting.Indented);//将实体类转换成json文件
            AuxiliaryItemArray.UpdateJsonInfo(this.programName, this.readValues, this.isPass, this.originalDirectory, this.lbl_ShowResult);
            this.ProcessExit(this.isPass);
        }
        #endregion

        #region 关闭进程
        private void ProcessExit(bool isPass)
        {
            CallExit?.Invoke(isPass);
        }
        #endregion

        #region 定时触发器
        private async void timer_Test_Tick(object sender, EventArgs e)
        {
            timer_Test.Enabled = false;
            bool testResult = true;
            string[] testArgsValues = this.testArgs.Split(',');

            foreach (var a in testArgsValues)
            {
                if (!this.displayEntity.Any(d => d.ProtName == a))
                {
                    testResult = false;
                    break;
                }
            }

            if (testResult)
            {
                this.readValues = JsonConvert.SerializeObject(this.displayEntity, Formatting.Indented);//将实体类转换成json文件
                AuxiliaryItemArray.UpdateJsonInfo(this.programName, this.readValues, true, this.originalDirectory, this.lbl_ShowResult);
                this.ProcessExit(this.isPass);
            }
            else
            {
                DisplayManager displayManager = new DisplayManager();
                DisplayEntity tempdata = new DisplayEntity();
                displayManager.DetectDisplays();
                if (displayManager.displayEntity.Count > 0)
                {
                    foreach (DisplayEntity ds in displayManager.displayEntity)
                    {
                        this.currentTestPort = new DisplayEntity();
                        if (!displayEntity.Any(d => d.ProtName == ds.ProtName) || displayEntity.Count == 0)
                        {
                            this.currentTestPort = ds;
                            tempdata = ds;
                            TestDisplayPort();//测试显示接口
                            if (ds.DeviceName.ToUpper().Contains("DISPLAY1"))
                            {
                                this.SwitchDisplayMode(DisplayMode.Internal);//仅第一个屏显示
                                this.currentTestPort.SwDisplayMode = DisplayMode.Internal;
                                break;
                            }
                            else
                            {
                                this.SwitchDisplayMode(DisplayMode.External);//仅第二个屏显示
                                this.currentTestPort.SwDisplayMode = DisplayMode.External;
                                break;
                            }
                        }
                    }
                }
            }
        }

        #endregion

        #region 显示接口测试
        /// <summary>
        /// 测试显示接口
        /// </summary>
        /// <param name="protName">接口名称</param>
        private async void TestDisplayPort()
        {
            this.input_number = 0;
            Random random = new Random();
            this.random_number = random.Next(1,9);

            this.lbl_ShowResult.BeginInvoke(new Action(() => {
                this.lbl_ShowResult.ForeColor = Color.SteelBlue;
                this.lbl_ShowResult.Text = $@"{this.currentTestPort.ProtName}接口测试中..";
            }));

            this.lbl_Random.BeginInvoke(new Action(() => {
                this.lbl_Random.Text = this.random_number.ToString();
            }));

            await this.Mp4Play(this.playFileName);//Mp4播放

            waitTime = 20;
            timer_random.Enabled = true;
            
        }
        #endregion

        #region 随机数检测
        private int waitTime = 0;//等待时间
        private DisplayEntity currentTestPort;//当前测试接口
        private async void timer_random_Tick(object sender, EventArgs e)
        {
            if(waitTime==0)
            {
                if(currentTestPort.ProtName=="VGA")
                {
                    this.lbl_VGA_result.Text = "FAIL";
                    this.lbl_VGA_result.ForeColor = Color.Red;
                }
                else if(currentTestPort.ProtName == "DVI")
                {
                    this.lbl_DVI_result.Text = "FAIL";
                    this.lbl_DVI_result.ForeColor = Color.Red;
                }
                else if (currentTestPort.ProtName == "DP")
                {
                    this.lbl_DP_result.Text = "FAIL";
                    this.lbl_DP_result.ForeColor = Color.Red;
                }
                else if (currentTestPort.ProtName == "HDMI")
                {
                    this.lbl_HDMI_result.Text = "FAIL";
                    this.lbl_HDMI_result.ForeColor = Color.Red;
                }

                this.lbl_ShowResult.BeginInvoke(new Action(() => {
                    this.lbl_ShowResult.Text = $@"{this.currentTestPort.ProtName}接口测试Fail";
                    this.lbl_ShowResult.ForeColor = Color.Red;
                }));

                this.SwitchDisplayMode(DisplayMode.Extend);//扩展屏显示
                await this.Mp4Play(this.playFileName);//Mp4播放
                timer_random.Enabled = false;
                this.timer_Test.Enabled = true;
            }
            else
            {
                if(this.input_number==0)
                    waitTime--;
                else
                {
                    if (currentTestPort.ProtName == "VGA")
                    {
                        this.lbl_VGA_result.Text = this.input_number == this.random_number ? "PASS" : "FAIL";
                        this.lbl_VGA_result.ForeColor = this.input_number == this.random_number ? Color.Green : Color.Red;
                    }
                    else if (currentTestPort.ProtName == "DVI")
                    {
                        this.lbl_DVI_result.Text = this.input_number == this.random_number ? "PASS" : "FAIL";
                        this.lbl_DVI_result.ForeColor = this.input_number == this.random_number ? Color.Green : Color.Red;
                    }
                    else if (currentTestPort.ProtName == "DP")
                    {
                        this.lbl_DP_result.Text = this.input_number == this.random_number ? "PASS" : "FAIL";
                        this.lbl_DP_result.ForeColor = this.input_number == this.random_number ? Color.Green : Color.Red;
                    }
                    else if (currentTestPort.ProtName == "HDMI")
                    {
                        this.lbl_HDMI_result.Text = this.input_number == this.random_number ? "PASS" : "FAIL";
                        this.lbl_HDMI_result.ForeColor = this.input_number == this.random_number ? Color.Green : Color.Red;
                    }

                    this.timer_random.Enabled = false;

                    if (this.input_number == this.random_number)
                    {
                        this.currentTestPort.TestResult = "PASS";
                        this.displayEntity.Add(this.currentTestPort);
                    }

                    this.lbl_ShowResult.BeginInvoke(new Action(() => {
                        this.lbl_ShowResult.Text = $@"{this.currentTestPort.ProtName}接口测试PASS";
                        this.lbl_ShowResult.ForeColor = Color.Green;
                    }));

                    this.waitTime = 0;
                    this.SwitchDisplayMode(DisplayMode.Extend);//扩展屏显示
                    await this.Mp4Play(this.playFileName);//Mp4播放
                    this.timer_Test.Enabled = true;
                }
            }
        }
        #endregion

        #region 键盘入事件
        /// <summary>
        /// 键盘键入事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VideoTestManager_KeyDown(object sender, KeyEventArgs e)
        {
            // Check if the pressed key is a number key (both top row and numpad)
            if ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) || (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9))
            {
                // Get the digit from the key code
                int digit = (e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) ? e.KeyCode - Keys.D0 : e.KeyCode - Keys.NumPad0;

                // Handle the digit input, for example:
                this.input_number = digit;
            }
        }
        #endregion
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using Models;

namespace Tools
{
    public class DisplayManager
    {
        public List<DisplayEntity> displayEntity; // 显示实体

        [DllImport("user32.dll")]
        private static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);

        [StructLayout(LayoutKind.Sequential)]
        private struct DISPLAY_DEVICE
        {
            public int cb;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string DeviceName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceString;
            public int StateFlags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceID;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceKey;
        }

        /// <summary>
        /// 检测接入的显示接口
        /// </summary>
        public void DetectDisplays()
        {

            displayEntity = new List<DisplayEntity>();

            // 使用WMI查询显示器连接类型
            ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\wmi", "SELECT * FROM WmiMonitorConnectionParams");
            foreach (ManagementObject queryObj in searcher.Get())
            {
                uint videoOutputTechnology = (uint)queryObj["VideoOutputTechnology"];
                string connectionType = GetConnectionType(videoOutputTechnology);

                displayEntity.Add(new DisplayEntity
                {
                    DeviceIndex = displayEntity.Count,
                    DeviceName = queryObj["InstanceName"]?.ToString(),
                    //DeviceString = DeviceString = d.DeviceString,
                    ProtName = connectionType
                });
            }

            DeviceString();
        }

        /// <summary>
        /// 检测接入的显示接口
        /// </summary>
        public void DeviceString()
        {
            DISPLAY_DEVICE d = new DISPLAY_DEVICE();
            d.cb = Marshal.SizeOf(d);

            int deviceIndex = 0;
            //this.displayEntity = new List<DisplayEntity>();

            while (EnumDisplayDevices(null, (uint)deviceIndex, ref d, 0))
            {

                if (deviceIndex < displayEntity.Count)
                {
                    displayEntity[deviceIndex].DeviceString = d.DeviceString;
                    displayEntity[deviceIndex].DeviceName = d.DeviceName;
                }
                //Console.WriteLine($"Device {deviceIndex}: {d.DeviceName} - {d.DeviceString}");
                //this.displayEntity.Add(new DisplayEntity()
                //{
                //    DeviceIndex = deviceIndex,
                //    DeviceName = d.DeviceName,
                //    DeviceString = d.DeviceString
                //});
                deviceIndex++;
            }
        }

        /// <summary>
        /// 获取连接的显示类型
        /// </summary>
        /// <param name="videoOutputTechnology"></param>
        /// <returns></returns>
        private string GetConnectionType(uint videoOutputTechnology)
        {
            // 根据WMI查询结果中的VideoOutputTechnology值返回连接类型
            switch (videoOutputTechnology)
            {
                case 0x00000000: return "HD15 (VGA)";
                case 0x00000001: return "S-Video";
                case 0x00000002: return "Composite video";
                case 0x00000003: return "Component video (YPbPr)";
                case 0x00000004: return "DVI";
                case 0x00000005: return "HDMI";
                case 0x00000006: return "LVDS";
                case 0x00000007: return "DJPN";
                case 0x00000008: return "SDI";
                case 0x00000009: return "DP";
                //case 0x00000009: return "DisplayPort external";
                //case 0x0000000A: return "DisplayPort embedded";
                case 0x0000000A: return "VGA";
                case 0x0000000B: return "UDI external";
                case 0x0000000C: return "UDI embedded";
                case 0x0000000D: return "SDTVDongle";
                case 0x80000000: return "Miracast";
                case 0x80000001: return "Indirect Display";
                default: return "Unknown";
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;

namespace Models
{
    public class DisplayEntity
    {
        /// <summary>
        /// 硬件指针
        /// </summary>
        public int DeviceIndex { get; set; }

        /// <summary>
        /// 硬件名称
        /// </summary>
        public string DeviceName { get; set; }

        /// <summary>
        /// 硬件字符串
        /// </summary>
        public string DeviceString { get; set; }

        /// <summary>
        /// 接口名称
        /// </summary>
        public string ProtName { get; set; }


        /// <summary>
        /// 切换的显示模式
        /// </summary>
        public DisplayMode SwDisplayMode { get; set; } = DisplayMode.Internal;


        /// <summary>
        /// 测试结果
        /// </summary>
        public string TestResult { get; set; } = "Wait";
    }

    public enum DisplayMode
    {
        Internal,//仅电脑屏幕
        Clone,//复制
        Extend,//扩展
        External//仅第二屏幕
    }
}