回调代表被收集?

一直在忙着用FMOD进行C#游戏开发,我早就遇到了麻烦,我似乎无法绕过。 我想做一些分支音频的东西并将一些游戏动作同步到节拍等等,所以我尝试将同步点添加到我的音乐曲目中。 这是代码:

public class Music { private Sound music; private Channel channel; private IntPtr syncPtr; public string File { get; private set; } public Music(string file) { File = file; } public void Load() { music = new Sound(); Audio.System.createSound(File, MODE.HARDWARE, ref music); } public void Unload() { music.release(); } public virtual void Play() { Audio.System.playSound(channel == null ? CHANNELINDEX.FREE : CHANNELINDEX.REUSE, music, false, ref channel); music.addSyncPoint(500, TIMEUNIT.MS, "wooo", ref syncPtr); channel.setCallback(channelCallback); } private RESULT channelCallback(IntPtr channelraw, CHANNEL_CALLBACKTYPE type, IntPtr commanddata1, IntPtr commanddata2) { if (type == CHANNEL_CALLBACKTYPE.SYNCPOINT) Console.WriteLine("sync!"); return RESULT.OK; } } 

然后…

 m = new Music(MUS_TUTORIAL); //m is static m.Load(); m.Play(); 

这首歌加载并播放正常…直到它达到我添加的500毫秒同步点。 此时,VC#从FMOD.EventSystem.update()中吐出以下错误:

在“Game!FMOD.CHANNEL_CALLBACK :: Invoke”类型的垃圾收集委托上进行了回调。 这可能会导致应用程序崩溃,损坏和数据丢失。 将委托传递给非托管代码时,托管应用程序必须保持它们的活动状态,直到确保它们永远不会被调用。

所以不知何故FMOD正在失去我通过它的代表的踪迹。 持有委托的Music实例并没有被垃圾收集 – 我现在将它存储在一个静态变量中 – 但我尝试使用静态方法也无济于事。 如果我禁用CallbackOnCollectedDelegate MDA,则错误将成为空引用exception,因此MDA不会出错。 我想我必须完全不了解FMOD在这里做了什么。

有没有C#+ FMOD大师能够看到我的错误?

  channel.setCallback(channelCallback); 

这是问题陈述。 FMod是非托管代码。 您正在此处创建委托对象并将其传递给非托管代码。 问题是,垃圾收集器无法跟踪本机代码所持有的引用。 下一个垃圾收集将找不到对象的引用并收集它。 Kaboom当本机代码进行回调时。

您需要自己保留一个引用,这样就不会发生:

 public class Music { private SomeDelegateType callback //... public Music(string file) { File = file; callback = new SomeDelegateType(channelCallback); } public virtual void Play() { Audio.System.playSound(channel == null ? CHANNELINDEX.FREE : CHANNELINDEX.REUSE, music, false, ref channel); music.addSyncPoint(500, TIMEUNIT.MS, "wooo", ref syncPtr); channel.setCallback(callback); } 

你需要从FMod包装器代码中找到实际的委托类型,我只是猜到了“SomeDelegateType”。

我在VB.NET和自定义C ++ DLL之间遇到了类似的问题。 感谢@Hans。 我欠这个网站很多次,因为它让我度过了所有的问题。 添加我的问题+解决方案希望它能帮助其他人在不同的环境中看到相同的解决方案。

宣布这个(在模块中)

 Public Delegate Sub CB_FUNC(ByVal x As Integer, ByVal y As Integer) Public Declare Sub vidProc_cb_MouseClick Lib "C:\Users\.....\vidProc\product\vidProc.dll" (ByVal addr_update As CB_FUNC) 

本来:

在button_click子中进行了简单的调用:

 vidProc_cb_MouseClick(AddressOf updateXY) 

我会得到’CallbackOnCollectedDelegate’错误。 不是立即,但在与表单上的其他对象交互后,然后尝试调用回调(在我的情况下是在OpenCV窗口中单击鼠标)。

修正:

1)声明(在表格类中,声明)

 Private addr_update As CB_FUNC 

2)在Form Load上定义addr_update

 addr_update = New CB_FUNC(AddressOf updateXY) 

3)使用新指针调用我的’set callback’函数(在button_click sub中)

 vidProc_cb_MouseClick(addr_update) 

我想我理解@Hans并正确实现它(我无法重现错误)。 希望这有助于某人。