diff --git a/Source/OpenTK/Audio/OpenAL/Alc/Alc.cs b/Source/OpenTK/Audio/OpenAL/Alc/Alc.cs index 38767a15..371bd81f 100644 --- a/Source/OpenTK/Audio/OpenAL/Alc/Alc.cs +++ b/Source/OpenTK/Audio/OpenAL/Alc/Alc.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Security; @@ -262,7 +263,13 @@ namespace OpenTK.Audio.OpenAL /// A string containing the name of the Device. public static string GetString(IntPtr device, AlcGetString param) { - return Marshal.PtrToStringAnsi(GetStringPrivate(device, param)); + IntPtr pstr = GetStringPrivate(device, param); + string str = String.Empty; + if (pstr != IntPtr.Zero) + { + str = Marshal.PtrToStringAnsi(pstr); + } + return str; } /// This function returns a List of strings related to the context. @@ -277,26 +284,54 @@ namespace OpenTK.Audio.OpenAL public static IList GetString(IntPtr device, AlcGetStringList param) { List result = new List(); - IntPtr t = GetStringPrivate(IntPtr.Zero, (AlcGetString)param); - System.Text.StringBuilder sb = new System.Text.StringBuilder(); - byte b; - int offset = 0; - do - { - b = Marshal.ReadByte(t, offset++); - if (b != 0) - sb.Append((char)b); - if (b == 0) - { - result.Add(sb.ToString()); - if (Marshal.ReadByte(t, offset) == 0) // offset already properly increased through ++ - break; // 2x null - else - sb.Remove(0, sb.Length); // 1x null - } - } while (true); - return (IList)result; + // We cannot use Marshal.PtrToStringAnsi(), + // because alcGetString is defined to return either a nul-terminated string, + // or an array of nul-terminated strings terminated by an extra nul. + // Marshal.PtrToStringAnsi() will fail in the latter case (it will only + // return the very first string in the array.) + // We'll have to marshal this ourselves. + IntPtr t = GetStringPrivate(device, (AlcGetString)param); + if (t != IntPtr.Zero) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + byte b; + int offset = 0; + do + { + b = Marshal.ReadByte(t, offset++); + if (b != 0) + { + sb.Append((char)b); + } + else + { + // One string from the array is complete + result.Add(sb.ToString()); + + // Check whether the array has finished + // Note: offset already been increased through offset++ above + if (Marshal.ReadByte(t, offset) == 0) + { + // 2x consecutive nuls, we've read the whole array + break; + } + else + { + // Another string is starting, clear the StringBuilder + sb.Remove(0, sb.Length); + } + } + } + while (true); + } + else + { + Debug.Print("[Audio] Alc.GetString({0}, {1}) returned null.", + device, param); + } + + return result; } [DllImport(Alc.Lib, EntryPoint = "alcGetIntegerv", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()]