c# - 尝试在 C# 中使 waveout 工作时 vhost.exe 崩溃

标签 c# crash waveout

我尝试在 C# 中使用 waveout 来同时播放更多的 wav 文件(至少是不同的文件)。 (SoundPlayer 对象一次只播放一个,我不想为这个简单的目标使用 DirectSound 和 MediaPlayer 对象或任何其他高级技术。)

我将一个工作的 C++ 代码移植到 C# 并且它可以工作(在研究了如何编码和如何调用 native win32 dll-s 以及如何分配和锁定非托管内存之后)但它以某种方式使 vhost.exe 崩溃,我不知道为什么这样做。 (它不会抛出任何异常,只会出现标准的 windows 错误对话框并且程序崩溃并退出。)

有没有人有任何想法?

这是该类的来源:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using XiVo.PlayThrough;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Timers;

namespace RTS
{
    class WaveObject
    {
        protected IntPtr wo;
        protected byte[] Adat=null;
        protected WaveNative.WaveHdr woh;
        protected int pgc;

        public class NotAWaveformFileException : Exception
        {
            public NotAWaveformFileException(string str) : base(str) { }
            public NotAWaveformFileException() { }
        }

        public class WaveFileIsCorruptedException : Exception
        {
            public WaveFileIsCorruptedException(string str) : base(str) { }
            public WaveFileIsCorruptedException() { }
        }

        public class WaveMapperCouldNotBeOpenedException : Exception
        {
            public WaveMapperCouldNotBeOpenedException(string str) : base(str) { }
            public WaveMapperCouldNotBeOpenedException() { }
        }

        public WaveObject() {}

        public WaveObject(string Fn) : this() { Load(Fn); }

        public void Load(string Fn)
        {
            IntPtr mmio;
            NativeMMIO.mmckInfo Main, Sub;

            WaveFormat wfx;
            StringBuilder str=new StringBuilder(Fn);
            int r;
            mmio = NativeMMIO.mmioOpen(str,IntPtr.Zero,NativeMMIO.MMIO_READ);
            if (mmio == IntPtr.Zero)
            {
                throw new FileNotFoundException(Fn + "not found!");
            }
            Main.fccType = NativeMMIO.mmioFOURCC('W', 'A', 'V', 'E');
            if (NativeMMIO.mmioDescend(mmio, out Main, IntPtr.Zero, NativeMMIO.MMIO_FINDRIFF) != 0)
            {
                throw new NotAWaveformFileException();
            }
            Sub.ckid = NativeMMIO.mmioFOURCC('f', 'm', 't', ' ');
            if (NativeMMIO.mmioDescend(mmio, out Sub, out Main, NativeMMIO.MMIO_FINDCHUNK) != 0)
            {
                throw new WaveFileIsCorruptedException("fmt chunk is not found!");
            }
            byte[] raw = new byte[Sub.cksize+2];
            NativeMMIO.mmioRead(mmio, raw, (int)Sub.cksize);
            GCHandle conv = GCHandle.Alloc(raw, GCHandleType.Pinned); // mapping a WaveFormat structure from the byte array
            wfx = (WaveFormat)Marshal.PtrToStructure(conv.AddrOfPinnedObject(), typeof(WaveFormat));
            conv.Free();
            Sub.ckid = NativeMMIO.mmioFOURCC('d', 'a', 't', 'a');
            if (NativeMMIO.mmioDescend(mmio, out Sub, out Main, NativeMMIO.MMIO_FINDCHUNK) != 0)
            {
                throw new WaveFileIsCorruptedException("data chunk is not found!");
            }
            Adat = new byte[Sub.cksize+2];
            NativeMMIO.mmioRead(mmio, Adat, (int)Sub.cksize);
            NativeMMIO.mmioClose(mmio, 0);
            wfx.cbSize = (short)Marshal.SizeOf(wfx);
            unchecked // WAVE_MAPPER is 0xFFFFFFFF and it does not let it convert to int otherwise
            {
                int res = WaveNative.waveOutOpen(out wo, (int)WaveNative.WAVE_MAPPER, wfx, null, 0, (int)WaveNative.CALLBACK_NULL);
                if (res != WaveNative.MMSYSERR_NOERROR)
                {
                    throw new WaveMapperCouldNotBeOpenedException();
                }
            }
            woh.lpData = Marshal.AllocHGlobal((int)Sub.cksize); // alloc memory for the buffer
            Marshal.Copy(Adat, 0, woh.lpData, (int)Sub.cksize);
            woh.dwBufferLength = (int)Sub.cksize;
            woh.dwBytesRecorded = 0;
            woh.dwUser = IntPtr.Zero;
            woh.dwFlags = 0;
            woh.dwLoops = 1000000;
            woh.reserved = 0;
            woh.lpNext = IntPtr.Zero;
            r = WaveNative.waveOutPrepareHeader(wo, ref woh, Marshal.SizeOf(woh));
            pgc = System.Environment.TickCount;
        }

        public void Play()
        {
            if (System.Environment.TickCount - pgc > 50)
            {
                if (wo == null) throw new Exception("wo somehow became null.");
                int res = WaveNative.waveOutReset(wo);
                if (res != WaveNative.MMSYSERR_NOERROR) throw new Exception(string.Format("waveOutReset {0}",res));
                res=WaveNative.waveOutWrite(wo, ref woh, Marshal.SizeOf(woh));
                if ((res != WaveNative.MMSYSERR_NOERROR) && (res!=33)) throw new Exception(string.Format("waveOutWrite {0}",res));
            }
        }

        ~WaveObject()
        {
            Marshal.FreeHGlobal(woh.lpData); // release memory
        }
    }
}

最佳答案

经过大量谷歌搜索后,我意识到该错误在 winmm.dll 本身中。在某些情况下,它的辅助线程也会崩溃并关闭主机应用程序。

citation

关于c# - 尝试在 C# 中使 waveout 工作时 vhost.exe 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/810405/

相关文章:

c# - 重现 "close over the variable of a foreach"陷阱

c# - 如何判断格式化字符串中的替换次数?

c# - DbTransaction 类和关于 C# 中的接口(interface)

iOS 在 App Store 审查自动布局方法中崩溃

multithreading - waveOut (Win32API) 和多线程

c# - WaveOut 将波形文件播放到设备的特定 channel

c# - 如何在 Silverlight 中定位标签页的内容?

android - AsyncTask 在 doInBackground 中崩溃,添加到 listview

安卓应用程序停止

c++ - 如何获取当前 Windows 音频播放的采样率?