using System; using System.IO; using System.Runtime.InteropServices; using Avalonia.Platform; namespace Notify.Interop; /// /// 播放打包的提示音 wav /// /// 用 winmm 的 PlaySound 从内存异步播放;为配合 SND_ASYNC,wav 拷到不会被 GC /// 移动的非托管内存里常驻 /// internal static partial class Sound { private const uint SND_ASYNC = 0x0001; private const uint SND_NODEFAULT = 0x0002; private const uint SND_MEMORY = 0x0004; private static IntPtr _wavPtr; private static DateTime _lastPlay = DateTime.MinValue; [LibraryImport("winmm.dll", EntryPoint = "PlaySoundW")] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool PlaySound(IntPtr pszSound, IntPtr hmod, uint fdwSound); public static void Play() { // 防连环音:300ms 内只响一次 var now = DateTime.UtcNow; if ((now - _lastPlay).TotalMilliseconds < 300) { return; } _lastPlay = now; try { EnsureLoaded(); if (_wavPtr != IntPtr.Zero) { PlaySound(_wavPtr, IntPtr.Zero, SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } } catch { // 播放失败无所谓 } } private static void EnsureLoaded() { if (_wavPtr != IntPtr.Zero) { return; } using var s = AssetLoader.Open(new Uri("avares://notify/Assets/notification.wav")); using var ms = new MemoryStream(); s.CopyTo(ms); var bytes = ms.ToArray(); _wavPtr = Marshal.AllocHGlobal(bytes.Length); Marshal.Copy(bytes, 0, _wavPtr, bytes.Length); } }