winform实现托盘语音提醒

news2024/11/25 3:46:59

测试环境:

visual studio 2022

window 10

.net framework 4.6

本文实现的功能有:

1   托盘最小化

2   语音定时播放

3   检测到操作系统被客户点静音后,需要程序控制开启音量(在运行过程中,由于语音重复播放,客户很烦,就会点静音,后面搞了一个在客户点静音后,如果客户一直没处理问题,就在10分钟后重新开启音量播放音频)

4  连接sql server数据库,如果不需要可以把代码注释掉

步骤如下:

1 新增名为DrawerAudio的winfrom程序,默认带出的窗体重新命名为:DrawerAudio

2 nuget安装NAudio,版本选择1.9.0,如下图:

3 网上找一张icon的图片,重新命名为ico_audio.ico,并放到debug目录,接着网上找一个要播放的mp3音频,并重新命名为"发生药槽错误,请盘点变红的药槽.mp3"

4  App.config配置文件编辑如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
    </startup>
	<connectionStrings>
		<add name="Sql" connectionString="server=127.0.0.1;uid=sa;pwd=密码;database=sql server数据库名称"/>
	</connectionStrings>
	<appSettings>
		<add key="IsTest" value="0" />
		<add key="SetAudioVolume" value="60" />
		<add key="MuteMinute" value="10" />
	</appSettings>
</configuration>

IsTest为1为测试模式,0为正式运行模式

SetAudioValume是设置音量

MuteMinute为最小音量,为了客户把音量调得过小,小于该音量后,程序自动把音量调大

5 新建名为SqlHelper的类并编辑如下(需要添加System.Configuration.dll引用):

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DrawerAudio
{
    // Token: 0x02000003 RID: 3
    internal class SqlHelper
    {
        // Token: 0x06000004 RID: 4 RVA: 0x00002124 File Offset: 0x00000324
        public static string GetSqlConnectionString()
        {
            return System.Configuration.ConfigurationManager.ConnectionStrings["Sql"].ConnectionString;
        }

        // Token: 0x06000005 RID: 5 RVA: 0x0000214C File Offset: 0x0000034C
        public static IList<T> ExecuteDataTable<T>(string sqlText, params SqlParameter[] parameters) where T : class, new()
        {
            IList<T> result;
            using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlText, SqlHelper.GetSqlConnectionString()))
            {
                DataTable dataTable = new DataTable();
                sqlDataAdapter.SelectCommand.Parameters.AddRange(parameters);
                sqlDataAdapter.Fill(dataTable);
                IList<T> list = new List<T>();
                PropertyInfo[] properties = typeof(T).GetProperties();
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    T t = Activator.CreateInstance<T>();
                    foreach (PropertyInfo propertyInfo in properties)
                    {
                        propertyInfo.SetValue(t, dataTable.Rows[i][propertyInfo.Name], null);
                    }
                    list.Add(t);
                }
                result = list;
            }
            return result;
        }
    }
}

6  新建名为AudioHelper的类并编辑如下:

using NAudio.CoreAudioApi;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DrawerAudio
{
    public class AudioHelper
    {
        private static bool IsPlaying = false;
        private static WaveOut waveOut;
        private static Mp3FileReader reader;
        private static string audioName;
        private static object lockobj = new object();

        public static bool Init(string audioName)
        {
            AudioHelper.audioName = audioName;
            AudioHelper.IsPlaying = true;
            return true;
        }

        public static bool GetIsPalying()
        {    
            return IsPlaying;
        }

        public static bool CheckCanStart()
        {
            if (waveOut!=null&&waveOut.PlaybackState == PlaybackState.Playing)
            {
                return false;
            }
            return true;
        }

        public static void PlayAudio()
        {
            try
            {
                lock (lockobj)
                {
                    using (var ms = File.OpenRead(audioName))
                    {
                        using (reader = new Mp3FileReader(ms))
                        using (var wavStream = WaveFormatConversionStream.CreatePcmStream(reader))
                        using (var baStream = new BlockAlignReductionStream(wavStream))
                        using (waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
                        {
                            waveOut.Init(baStream);
                            waveOut.Play();
                            while (waveOut.PlaybackState == PlaybackState.Playing&& AudioHelper.GetIsPalying())
                            {
                                Thread.Sleep(100);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("异常信息:"+ex.Message);
            }
        }

        public static bool StopPlay()
        {
            try
            {
                if (waveOut != null)
                {
                    IsPlaying = false;
                    waveOut.Stop();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("停止错误:"+ex.Message);
            }
            return true;
        }

        /// <summary>
        /// 获取当前音量
        /// </summary>
        /// <returns></returns>
        public  static int GetCurrentSpeakerVolume()
        {
            int volume = 0;
            var enumerator = new MMDeviceEnumerator();

            //获取音频输出设备
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            if (speakDevices.Count() > 0)
            {
                MMDevice mMDevice = speakDevices.ToList()[0];
                volume = Convert.ToInt16(mMDevice.AudioEndpointVolume.MasterVolumeLevelScalar * 100);
            }
            return volume;
        }

        public static void  SetCurrentSpeakerVolume(int volume)
        {
            var enumerator = new MMDeviceEnumerator();
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            if (speakDevices.Count() > 0)
            {
                MMDevice mMDevice = speakDevices.ToList()[0];
                mMDevice.AudioEndpointVolume.MasterVolumeLevelScalar = volume / 100.0f;
            }
        }

        /// <summary>
        /// 检测是否是静音
        /// </summary>
        /// <returns></returns>
        public static bool CheckIsNoNoise()
        {
            var enumerator = new MMDeviceEnumerator();
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            MMDevice mMDevice = speakDevices.ToList()[0];
            return mMDevice.AudioEndpointVolume.Mute;
        }
        /// <summary>
        /// 关闭静音
        /// </summary>
        public static void CloseNoNoise()
        {
            var enumerator = new MMDeviceEnumerator();
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            MMDevice mMDevice = speakDevices.ToList()[0];
            mMDevice.AudioEndpointVolume.Mute = false;
        }
    }
}

7  新建Model目录,并新建名为DrawerModel的类,并编辑如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DrawerAudio.Model
{
    // Token: 0x02000004 RID: 4
    public class DrawerModel
    {
        // Token: 0x17000001 RID: 1
        // (get) Token: 0x06000007 RID: 7 RVA: 0x00002245 File Offset: 0x00000445
        // (set) Token: 0x06000006 RID: 6 RVA: 0x0000223C File Offset: 0x0000043C
        public int IdDrawer { get; set; }

        // Token: 0x17000002 RID: 2
        // (get) Token: 0x06000009 RID: 9 RVA: 0x00002256 File Offset: 0x00000456
        // (set) Token: 0x06000008 RID: 8 RVA: 0x0000224D File Offset: 0x0000044D
        public int IdProduct { get; set; }
    }
}

8 编辑FrmMain如下:

using DrawerAudio.Model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DrawerAudio
{
    public partial class FrmMain : Form
    {
        bool isTest = ConfigurationManager.AppSettings["IsTest"].Equals("1");
        int audioVolume = Convert.ToInt32(ConfigurationManager.AppSettings["SetAudioVolume"]);
        //静音的分钟数
        int muteMinute= Convert.ToInt32(ConfigurationManager.AppSettings["MuteMinute"]);
        const int WM_SYSCOMMAND = 0x112;
        const int SC_MINIMIZE = 0xF020;
        Thread audioThread = null;
        int secondCount = 0;
        public FrmMain()
        {
            InitializeComponent();
            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            this.Load += FrmMain_Load;
            audioThread = new Thread(StartAudio);
            audioThread.IsBackground=true;
            AudioHelper.Init("发生药槽错误,请盘点变红的药槽.mp3");
            audioThread.Start();
            System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
            timer.Interval = 1000;
            timer.Tick += Timer_Tick;
            timer.Start();
        }
        private const int CP_NOCLOSE_BUTTON = 0x200;
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams myCp = base.CreateParams;
                myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON;
                return myCp;
            }
        }
        private void Timer_Tick(object sender, EventArgs e)
        {
            int currentVlume=AudioHelper.GetCurrentSpeakerVolume();
            if (currentVlume < 20)
            {
                AudioHelper.SetCurrentSpeakerVolume(audioVolume);
                
            }
            if (AudioHelper.CheckIsNoNoise())
            {
                secondCount++;
                if (secondCount > (60 * muteMinute))
                {
                    secondCount = 0;
                    AudioHelper.CloseNoNoise();
                }
            }
            else
            {
                secondCount = 0;
            }

        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_SYSCOMMAND)
            {
                if (m.WParam.ToInt32() == SC_MINIMIZE)
                {
                    this.ShowInTaskbar = false;
                    this.WindowState= FormWindowState.Minimized;
                }
            }
            base.WndProc(ref m);
        }
        private void FrmMain_Load(object sender, EventArgs e)
        {
            //实例化一个NotifyIcon对象

            NotifyIcon notifyIcon = new NotifyIcon();

            //设置图标
            notifyIcon.Icon = new Icon("ico_audio.ico");
            //设置提示文本
            notifyIcon.Text = "药槽错误语音提醒";
            //设置双击托盘图标后显示窗体
            notifyIcon.DoubleClick += NotifyIcon_DoubleClick;
            //显示托盘
            notifyIcon.Visible = true;
        }

        private void NotifyIcon_DoubleClick(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowInTaskbar = true;
            this.Activate();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            AudioHelper.Init("发生药槽错误,请盘点变红的药槽.mp3");
            if (audioThread.ThreadState == (ThreadState.Background|ThreadState.Suspended))
            {
                audioThread.Resume();
            }
            else if(audioThread.ThreadState==(ThreadState.Background|ThreadState.Unstarted))
            {
                audioThread.Start();
            }
            MessageBox.Show("开始成功");
        }


        private void StartAudio()
        {
            while (true)
            {
                Thread.Sleep(500);
                if (!isTest)
                {
                    if (GetDrawerError())
                    {
                        if (AudioHelper.GetIsPalying() && AudioHelper.CheckCanStart())
                        {
                            AudioHelper.PlayAudio();
                        }
                    }
                }
                else
                {
                    if (AudioHelper.GetIsPalying() && AudioHelper.CheckCanStart())
                    {
                        AudioHelper.PlayAudio();
                    }
                }

            }
        }
        private bool GetDrawerError()
        {
            string sqlText = "select IdDrawer,IdProduct from 表名 where 条件";
            try
            {
                IList<DrawerModel> list = SqlHelper.ExecuteDataTable<DrawerModel>(sqlText, Array.Empty<SqlParameter>());
                if (list.Count > 0)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("查询失败,错误信息:" + ex.Message);
            }
            return false;
        }
        /// <summary>
        /// 停止按钮的逻辑,根据需要进行加入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            audioThread.Suspend();
            AudioHelper.StopPlay();
        }
    }
}

要上班了,代码就不解释了

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Protobuf】基本使用总结+项目实践

概述 序列化与反序列化 网络传输中使用&#xff0c;可以实现将对象转换为二进制序列&#xff0c;然后将二进制序列转换为对象&#xff0c;这一个交互的过程就是序列化。生成的数据&#xff0c;持久化存储到磁盘上的过程&#xff0c;也需要经过序列化和反序列化才可以实现。 序…

SpringBoot实现的美发门店客户关系管理(CRM)系统

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

浅谈2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者

目录 1.概述 1.1. 跨学科的融合 1.2. 推动科学研究的工具 1.3. 对科学界的激励 1.4. 技术的社会影响 2.机器学习与神经网络的发展前景 2.1.具体应用与作用 2.1.1. 医疗健康 2.1.2. 金融 2.1.3. 制造业 2.1.4. 交通与物流 2.1.5. 零售 2.2.未来展望 2.3.科学研究与…

C# 实现调用函数,打印日志(通过反射代理、非IOC)

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C# &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff…

宝塔面板配置FTP服务结合内网穿透实现其他设备远程连接上传文件

文章目录 前言1. Linux安装Cpolar2. 创建FTP公网地址3. 宝塔FTP服务设置4. FTP服务远程连接小结 5. 固定FTP公网地址6. 固定FTP地址连接 前言 本文主要介绍宝塔FTP文件传输服务如何搭配内网穿透工具&#xff0c;实现随时随地远程连接局域网环境搭建的宝塔FTP文件服务并进行文件…

电商数据淘宝/京东/1688商品SKU数据采集||电商API接口

电商数据采集接口数据分析是一个涉及多个步骤的过程&#xff0c;以下是一个详细的指南&#xff1a; 一、数据采集接口的选择与接入 选择合适的电商数据采集接口&#xff1a; 根据需求选择提供所需数据的电商平台接口。考虑接口的稳定性、数据更新频率及准确性。 接口接入准备&…

《网络数据安全管理条例》正式公布,规范数据处理活动,保障网络数据安全

近日&#xff0c;《网络数据安全管理条例》&#xff08;以下简称《条例》&#xff09;正式公布&#xff0c;自2025年1月1日起施行。 《条例》旨在规范网络数据处理活动&#xff0c;保障网络数据安全&#xff0c;促进网络数据依法合理有效利用&#xff0c;保护个人、组织的合法权…

java时间复杂度与空间复杂度的排序

怎么理解时间复杂度和空间复杂度 时间复杂度和空间复杂度一般是针对算法而言&#xff0c;是衡量一个算法是否高效的重要标准。先纠正一个误区&#xff0c;时间复杂度并不是算法执行的时间&#xff0c;再纠正一个误区&#xff0c;算法不单单指冒泡排序之类的&#xff0c;一个循…

获取期货股票历史数据以及均线策略分析

【数据获取】银河金融数据库&#xff08;yinhedata.com&#xff09;能够获取国内外金融股票、期货历史行情数据&#xff0c;包含各分钟级别。 【搭建策略】均线策略作为一种广泛应用于股票、期货等市场的技术分析方法&#xff0c;凭借其简单易懂、操作性强等特点&#xff0c;深…

CV图像处理小工具——json文件转P格式mask

CV图像处理小工具——json文件转P格式mask import cv2 import json import numpy as np import osdef func(file_path: str) -> np.ndarray:try:with open(file_path, moder, encoding"utf-8") as f:configs json.load(f)# 检查JSON是否包含必要的字段if "…

【专题】2024年中国电商市场研究报告合集PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37835 在全球电商持续发展的背景下&#xff0c;中国电商市场面临新态势。 增长压力与机遇并存&#xff0c;从综合电商与直播电商发展的放缓&#xff0c;到企业 3C 数码商用品电商采购的趋势&#xff0c;以及零售业拥抱“性价比时代…

校园网站设计怎么做

校园网站设计是一项复杂而又具有挑战性的任务&#xff0c;因为它需要考虑到学校内各种不同的需求和利益。一个成功的校园网站应该能够满足学生、教职员工、家长和管理人员的需求&#xff0c;同时提供清晰、易用且富有吸引力的界面。以下是一些设计校园网站的关键方面&#xff0…

腾讯全文检索引擎 wwsearch 正式开源

背景 企业微信作为典型企业服务系统&#xff0c;其众多企业级应用都需要全文检索能力&#xff0c;包括员工通讯录、企业邮箱、审批、汇报、企业CRM、企业素材、互联圈子等。下图是一个典型的邮件检索场景。 由于过去几年业务发展迅速&#xff0c;后台检索架构面临挑战&#xf…

学霸都在用的秘密武器!盘点3款语音识别转文字软件,学习力MAX!

现在科技这么发达&#xff0c;手写笔记好像越来越不流行了。在这个什么都讲究快的时代&#xff0c;怎么又快又好地记下重要信息&#xff0c;是大家都想要的。正好&#xff0c;现在市面上有很多能把语音转换成文字的工具&#xff0c;它们特别有用&#xff0c;正在慢慢改变我们学…

pipe和pipefd

Linux 中 pipe 的详细介绍 在 Linux 中&#xff0c;pipe 是一个系统调用&#xff0c;用于创建一个管道&#xff0c;这是一种用于进程间通信&#xff08;IPC&#xff09;的机制。管道允许两个进程之间进行单向数据传输&#xff0c;通常是一个进程向管道写入数据&#xff0c;而另…

【机器学习】金融预测 —— 风险管理与股市预测

我的主页&#xff1a;2的n次方_ 在金融领域&#xff0c;机器学习&#xff08;ML&#xff09;已经成为了不可或缺的工具。金融预测&#xff0c;尤其是风险管理和股市预测&#xff0c;涉及海量数据和复杂模式的分析&#xff0c;而这些正是机器学习擅长处理的领域。通过分析历…

什么是矩阵系统,怎么选择矩阵系统,怎么oem贴牌,怎么源码搭建

一、架构设计方面 采用微服务架构 将矩阵系统拆分为多个小型的、独立的服务模块。每个微服务专注于特定的业务功能&#xff0c;如用户管理、内容发布、数据分析等。这样可以独立地开发、部署和扩展每个服务&#xff0c;而不会影响整个系统。例如&#xff0c;当用户量增加导致用…

机器学习与神经网络荣膺诺贝尔物理学奖:跨学科融合的时代来临

近日&#xff0c;2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者&#xff0c;这一消息犹如一颗重磅炸弹&#xff0c;迅速在全球学术界和科技界引起了轰动和热议。这是诺贝尔物理学奖首次将桂冠授予计算机科学领域的研究者&#xff0c;标志着物理学与计算机科学的…

dvwa:文件包含、文件上传

文件包含 本地文件包含&#xff08;敏感信息泄露&#xff09;和远程文件包含&#xff08;命令执行&#xff09; 本地文件包含一般包含一些本地的敏感文件&#xff0c;如&#xff1a;/etc/passwd或/etc/shadow等 远程文件包含能使得服务器代码执行&#xff0c;如包含黑客vps的…

【纯前端实现xlsx的解析并处理成table需要的格式】

概要 xlsx纯前端导入并解析成json 整体架构流程 xlsx导入并解析成json&#xff0c;并与table中的数据进行对比&#xff0c;根据唯一标识更新对应数据项 技术名词解释 vue2xlsx 技术细节 首先下载xlsx依赖 npm install xlsx --save然后在需要导入xlsx的地方 这里主要用in…