2011-02-24 45 views
4

我正在使用Visual C#Express为xna中的windows创建游戏。在游戏中,有六个SoundEffect对象定期调用他们的Play()方法。问题在于,有时游戏关闭时会崩溃。 这似乎发生在播放soundeffect时关闭窗口时。这是在Visual C#弹出消息:如何阻止SoundEffect在XNA Windows游戏关闭时崩溃?

AccessViolationException了未处理

试图读取或写入受保护的存储器中。这通常表明其他内存已损坏。

没有在Visual Studio调试和当“得到这个异常一般帮助”被点击时,一个空白页弹出任何可用的源..

中使用的代码看起来很像MSDN示例。这看起来像是存在于底层框架某处的问题,而不是我的代码。但我当然不知道。这已经发生了很多次。

http://msdn.microsoft.com/en-us/library/bb195053.aspx

下面是完整的异常详细信息:

System.AccessViolationException was unhandled 
    Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 
    Source=Microsoft.Xna.Framework 
    StackTrace: 
     at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.IsEventRegistered(EventType type) 
     at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.UnregisterEvent(EventType type) 
     at Microsoft.Xna.Framework.Audio.KernelMicrophone.ShutdownCaptureEngine() 
     at Microsoft.Xna.Framework.Audio.MicrophoneUnsafeNativeMethods.ShutdownCaptureEngine() 
     at Microsoft.Xna.Framework.Audio.AudioRendererShutdownHandler.AppExitingEventHandler(Object sender, EventArgs args) 
    InnerException: 

(我也有音乐通过的MediaPlayer播放,但我不认为这是相关的)

编辑:我似乎找到有用的东西,但它有点骇人听闻,真的不应该有必要。我仍然乐意接受更优雅的解决方案。

在Game1.UnloadContent()中调用此行。它会确保(如果你的声音效果都短于3秒)程序实际关闭时没有声音播放。

System.Threading.Thread.Sleep(3000); 
+0

您的UnloadContent代码的外观如何? (而且,你是否能够在从模板项目开始时重现此问题?) – 2011-02-25 07:49:41

回答

2

充分利用SoundEffect中对象的类成员并调用SoundEffect中的Dispose阶级解构()方法:

class MyClass 
{ 
    ~MyClass() 
    { 
     effect.Dispose(); 
    } 

    SoundEffect effect; 

} 

这应该让SoundEffect中物体自身的清洁,当你关闭游戏。您可以阅读有关一次性使用的对象:http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

+0

我完成了这个,崩溃仍然发生。 – Stefan 2011-02-24 21:41:06

+1

您是否尝试从SoundEffect对象获取SoundEffectInstance并从SoundEffectInstance调用Play? – BrMcMullin 2011-02-24 22:19:55

+2

这里析构函数和'Dispose'的用法是非常不正确的!**。您不应该在终结器中的另一个对象上调用Dispose,因为该对象可能在您的终结器运行时已经完成。终结器不应该引用另一个对象。 (正确的术语是破坏,而不是de * con *结构)。 – 2011-02-25 07:45:56

1

您可以让MyClass实现IDisposable并在该方法中处理SoundEffect?

+1

由ContentManager.Load加载的资源由ContentManager本身“拥有”,并且应该使用ContentManager.Unload卸载。不要对他们调用'Dispose'。 – 2011-02-25 07:56:05

1

我认为这是一个相当安全的说这是一个在框架中的错误。因为它在音频代码中,所以框架可能没有正确处理从驱动程序获得的东西。很难肯定地说。

只要说出一个AccessViolationException出来的框架是不“正常的”。这几乎肯定是不是你的错

函数IsEventRegistered发生异常的是unsafe函数。所以很可能这个函数正在做正确的例外:它正在访问一个无效的内存地址。

来自音频捕捉(麦克风)的关闭代码的异常,你是否在代码中对麦克风做了什么?你可以尝试使用/不使用麦克风,看看会发生什么。

另外:当没有附加调试器运行时会发生这种情况吗? (Ctrl + F5)

至于解决问题:你的解决方案并不是一个坏的解决办法。

如果你不能等待了三秒钟,你想获得你的手脏,写一些非常可疑(半不可移植,未necessaraly向前兼容)代码:你可以使用反射来访问音频系统的私有属性。查找在您调用SoundEffect.Play时内部创建的SoundEffectInstance对象的列表,然后在关闭之前停止这些实例。

或者您可以通过从不打电话Play有效地做同样的事情,而是调用CreateInstance和管理自己的火灾和遗忘的声音效果。缺点是这需要编写大量的代码!

0

我有同样的问题,我没有为我的声音集合类终结器(析构函数)中的空值。适用于我。

public class Audio 
{ 
    private ContentManager content; 
    public List<SoundEffectInstance> SoundInstance { get; private set; } 
    public AudioEmitter Emitter { get; set; } 
    public AudioListener Listener { get; set; } 
    public List<SoundEffect> Sound { get; set; } 
    public Audio(ContentManager content) 
    { 
     this.content = content; 
     Emitter = new AudioEmitter(); 
     Listener = new AudioListener(); 
     Sound = new List<SoundEffect>(); 
     SoundInstance = new List<SoundEffectInstance>(); 
    } 
    //set to null your sound instances and effects :D 
    ~Audio() 
    { 
     Sound = null; 
     SoundInstance = null; 
    } 
...