diff --git a/Source/OpenTK.Rewrite/Program.cs b/Source/OpenTK.Rewrite/Program.cs
index bae00913..c5e9e06a 100644
--- a/Source/OpenTK.Rewrite/Program.cs
+++ b/Source/OpenTK.Rewrite/Program.cs
@@ -47,6 +47,7 @@ namespace OpenTK.Rewrite
// mscorlib types
static AssemblyDefinition mscorlib;
static TypeDefinition TypeMarshal;
+ static TypeDefinition TypeStringArray;
static TypeDefinition TypeStringBuilder;
static TypeDefinition TypeVoid;
static TypeDefinition TypeIntPtr;
@@ -111,6 +112,7 @@ namespace OpenTK.Rewrite
return;
}
TypeMarshal = mscorlib.MainModule.GetType("System.Runtime.InteropServices.Marshal");
+ TypeStringArray = mscorlib.MainModule.GetType("System.String").MakeArrayType().Resolve();
TypeStringBuilder = mscorlib.MainModule.GetType("System.Text.StringBuilder");
TypeVoid = mscorlib.MainModule.GetType("System.Void");
TypeIntPtr = mscorlib.MainModule.GetType("System.IntPtr");
@@ -328,7 +330,7 @@ namespace OpenTK.Rewrite
// try {
// foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1); -- already emitted
// glGetShaderInfoLog(..., foo_sb_ptr); -- already emitted
- // MarshalStringBuilder(foo_sb_ptr, foo);
+ // MarshalPtrToStringBuilder(foo_sb_ptr, foo);
// }
// finally {
// Marshal.FreeHGlobal(foo_sb_ptr);
@@ -358,6 +360,52 @@ namespace OpenTK.Rewrite
}
}
+ static void EmitStringArrayParameter(MethodDefinition wrapper, TypeReference p, MethodBody body, ILProcessor il)
+ {
+ // string[] masrhaling:
+ // IntPtr ptr = MarshalStringArrayToPtr(strings);
+ // try {
+ // calli
+ // }
+ // finally {
+ // UnmarshalStringArray(ptr);
+ // }
+ var marshal_str_array_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringArrayToPtr"));
+
+ // IntPtr ptr;
+ var variable_name = p.Name + " _string_array_ptr";
+ body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
+ int index = body.Variables.Count - 1;
+
+ // ptr = MarshalStringArrayToPtr(strings);
+ il.Emit(OpCodes.Call, marshal_str_array_to_ptr);
+ il.Emit(OpCodes.Stloc, index);
+ il.Emit(OpCodes.Ldloc, index);
+
+ // The finally block will be emitted in the function epilogue
+ }
+
+ static void EmitStringArrayEpilogue(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il)
+ {
+ for (int i = 0; i < wrapper.Parameters.Count; i++)
+ {
+ var p = wrapper.Parameters[i].ParameterType;
+ if (p.Name == "String" && p.IsArray)
+ {
+ var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringArrayPtr"));
+ var get_length = wrapper.Module.Import(TypeStringArray.Methods.First(m => m.Name == "get_Length"));
+
+ // FreeStringArrayPtr(string_array_ptr, string_array.Length)
+ var variable_name = p.Name + "_string_array_ptr";
+ var v = body.Variables.First(m => m.Name == variable_name);
+ il.Emit(OpCodes.Ldloc, v.Index);
+ il.Emit(OpCodes.Ldarg, i);
+ il.Emit(OpCodes.Callvirt, get_length);
+ il.Emit(OpCodes.Call, free);
+ }
+ }
+ }
+
private static void EmitConvenienceWrapper(MethodDefinition wrapper,
MethodDefinition native, int difference, MethodBody body, ILProcessor il)
{
@@ -491,8 +539,7 @@ namespace OpenTK.Rewrite
}
else
{
- // String[] requires special marshalling.
- // Let the runtime handle this for now.
+ EmitStringArrayParameter(method, p, body, il);
}
}
}
diff --git a/Source/OpenTK/BindingsBase.cs b/Source/OpenTK/BindingsBase.cs
index 1f2372e1..36d421fe 100644
--- a/Source/OpenTK/BindingsBase.cs
+++ b/Source/OpenTK/BindingsBase.cs
@@ -119,13 +119,13 @@ namespace OpenTK
/// unique objects, but all instances of ES10.GL should return the same object.
protected abstract object SyncRoot { get; }
- ///
+ ///
/// Marshals a pointer to a null-terminated byte array to the specified StringBuilder.
/// This method supports OpenTK and is not intended to be called by user code.
- ///
+ ///
/// A pointer to a null-terminated byte array.
/// The StringBuilder to receive the contents of the pointer.
- protected static void MarshalPtrToStringBuilder(IntPtr ptr, StringBuilder sb)
+ protected static void MarshalPtrToStringBuilder(IntPtr ptr, StringBuilder sb)
{
if (ptr == IntPtr.Zero)
throw new ArgumentException("ptr");
@@ -144,6 +144,52 @@ namespace OpenTK
}
}
+ ///
+ /// Marshals a string array to unmanaged memory by calling
+ /// Marshal.AllocHGlobal for each element.
+ ///
+ /// An unmanaged pointer to an array of null-terminated strings
+ /// The string array to marshal.
+ protected static IntPtr MarshalStringArrayToPtr(string[] str_array)
+ {
+ IntPtr ptr = IntPtr.Zero;
+ if (str_array != null && str_array.Length != 0)
+ {
+ ptr = Marshal.AllocHGlobal(str_array.Length * IntPtr.Size);
+ if (ptr == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+
+ for (int i = 0; i < str_array.Length; i++)
+ {
+ IntPtr str = Marshal.StringToHGlobalAnsi(str_array[i]);
+ if (str == IntPtr.Zero)
+ {
+ throw new OutOfMemoryException();
+ }
+
+ Marshal.WriteIntPtr(ptr, i * IntPtr.Size, str);
+ }
+ }
+ return ptr;
+ }
+
+ ///
+ /// Frees a string array that has previously been
+ /// marshalled by MarshalStringArrayToPtr.
+ ///
+ /// An unmanaged pointer allocated by MarshalStringArrayToPtr
+ /// The length of the string array.
+ protected static void FreeStringArrayPtr(IntPtr ptr, int length)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, length * IntPtr.Size));
+ }
+ Marshal.FreeHGlobal(ptr);
+ }
+
#endregion
#region Internal Members