2009-09-03 21:01:11 +02:00
|
|
|
|
#region License
|
|
|
|
|
//
|
|
|
|
|
// The Open Toolkit Library License
|
|
|
|
|
//
|
|
|
|
|
// Copyright (c) 2006 - 2009 the Open Toolkit library.
|
|
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
// in the Software without restriction, including without limitation the rights to
|
|
|
|
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
|
// the Software, and to permit persons to whom the Software is furnished to do
|
|
|
|
|
// so, subject to the following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
|
|
|
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
|
|
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
|
|
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
|
// OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
//
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
2009-10-07 12:44:45 +02:00
|
|
|
|
namespace OpenTK
|
2009-09-03 21:01:11 +02:00
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2009-10-07 12:44:45 +02:00
|
|
|
|
/// Provides a common foundation for all flat API bindings and implements the extension loading interface.
|
2009-09-03 21:01:11 +02:00
|
|
|
|
/// </summary>
|
|
|
|
|
public abstract class BindingsBase
|
|
|
|
|
{
|
|
|
|
|
#region Fields
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A reflection handle to the nested type that contains the function delegates.
|
|
|
|
|
/// </summary>
|
2014-04-26 18:28:51 +02:00
|
|
|
|
[Obsolete("Not used")]
|
2009-09-03 21:01:11 +02:00
|
|
|
|
readonly protected Type DelegatesClass;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A refection handle to the nested type that contains core functions (i.e. not extensions).
|
|
|
|
|
/// </summary>
|
2014-04-26 18:28:51 +02:00
|
|
|
|
[Obsolete("Not used")]
|
2009-09-03 21:01:11 +02:00
|
|
|
|
readonly protected Type CoreClass;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A mapping of core function names to MethodInfo handles.
|
|
|
|
|
/// </summary>
|
2014-04-26 18:28:51 +02:00
|
|
|
|
[Obsolete("Not used")]
|
|
|
|
|
readonly protected SortedList<string, MethodInfo> CoreFunctionMap;
|
2009-09-03 21:01:11 +02:00
|
|
|
|
|
|
|
|
|
bool rebuildExtensionList = true;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructs a new BindingsBase instance.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public BindingsBase()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Protected Members
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets a <see cref="System.Boolean"/> that indicates whether the list of supported extensions may have changed.
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected bool RebuildExtensionList
|
|
|
|
|
{
|
|
|
|
|
get { return rebuildExtensionList; }
|
|
|
|
|
set { rebuildExtensionList = value; }
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-07 12:52:48 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Retrieves an unmanaged function pointer to the specified function.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="funcname">
|
|
|
|
|
/// A <see cref="System.String"/> that defines the name of the function.
|
|
|
|
|
/// </param>
|
|
|
|
|
/// <returns>
|
|
|
|
|
/// A <see cref="IntPtr"/> that contains the address of funcname or IntPtr.Zero,
|
|
|
|
|
/// if the function is not supported by the drivers.
|
|
|
|
|
/// </returns>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Note: some drivers are known to return non-zero values for unsupported functions.
|
|
|
|
|
/// Typical values include 1 and 2 - inheritors are advised to check for and ignore these
|
|
|
|
|
/// values.
|
|
|
|
|
/// </remarks>
|
2009-10-07 12:44:45 +02:00
|
|
|
|
protected abstract IntPtr GetAddress(string funcname);
|
|
|
|
|
|
2009-11-04 00:26:57 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets an object that can be used to synchronize access to the bindings implementation.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>This object should be unique across bindings but consistent between bindings
|
|
|
|
|
/// of the same type. For example, ES10.GL, OpenGL.GL and CL10.CL should all return
|
|
|
|
|
/// unique objects, but all instances of ES10.GL should return the same object.</remarks>
|
|
|
|
|
protected abstract object SyncRoot { get; }
|
|
|
|
|
|
2013-12-04 20:33:19 +01:00
|
|
|
|
/// <summary>
|
2013-12-02 11:58:41 +01:00
|
|
|
|
/// Marshals a pointer to a null-terminated byte array to the specified <c>StringBuilder</c>.
|
|
|
|
|
/// This method supports OpenTK and is not intended to be called by user code.
|
2014-04-26 18:28:51 +02:00
|
|
|
|
/// </summary>
|
2013-12-02 11:58:41 +01:00
|
|
|
|
/// <param name="ptr">A pointer to a null-terminated byte array.</param>
|
|
|
|
|
/// <param name="sb">The StringBuilder to receive the contents of the pointer.</param>
|
2013-12-04 20:33:19 +01:00
|
|
|
|
protected static void MarshalPtrToStringBuilder(IntPtr ptr, StringBuilder sb)
|
2013-12-02 11:58:41 +01:00
|
|
|
|
{
|
|
|
|
|
if (ptr == IntPtr.Zero)
|
|
|
|
|
throw new ArgumentException("ptr");
|
|
|
|
|
if (sb == null)
|
|
|
|
|
throw new ArgumentNullException("sb");
|
|
|
|
|
|
|
|
|
|
sb.Length = 0;
|
2014-02-07 15:57:36 +01:00
|
|
|
|
for (int i = 0; ; i++)
|
2013-12-02 11:58:41 +01:00
|
|
|
|
{
|
|
|
|
|
byte b = Marshal.ReadByte(ptr, i);
|
|
|
|
|
if (b == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sb.Append((char)b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-04 20:33:19 +01:00
|
|
|
|
/// <summary>
|
2013-12-17 11:39:47 +01:00
|
|
|
|
/// Marshal a <c>System.String</c> to unmanaged memory.
|
2014-01-16 14:32:11 +01:00
|
|
|
|
/// The resulting string is encoded in ASCII and must be freed
|
2013-12-17 11:39:47 +01:00
|
|
|
|
/// with <c>FreeStringPtr</c>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="str">The <c>System.String</c> to marshal.</param>
|
|
|
|
|
/// <returns>
|
|
|
|
|
/// An unmanaged pointer containing the marshalled string.
|
|
|
|
|
/// This pointer must be freed with <c>FreeStringPtr</c>
|
|
|
|
|
/// </returns>
|
|
|
|
|
protected static IntPtr MarshalStringToPtr(string str)
|
|
|
|
|
{
|
|
|
|
|
if (String.IsNullOrEmpty(str))
|
|
|
|
|
{
|
|
|
|
|
return IntPtr.Zero;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allocate a buffer big enough to hold the marshalled string.
|
2014-01-16 14:32:11 +01:00
|
|
|
|
// GetMaxByteCount() appears to allocate space for the final NUL
|
|
|
|
|
// character, but allocate an extra one just in case (who knows
|
|
|
|
|
// what old Mono version would do here.)
|
|
|
|
|
int max_count = Encoding.ASCII.GetMaxByteCount(str.Length) + 1;
|
2013-12-17 11:39:47 +01:00
|
|
|
|
IntPtr ptr = Marshal.AllocHGlobal(max_count);
|
|
|
|
|
if (ptr == IntPtr.Zero)
|
|
|
|
|
{
|
|
|
|
|
throw new OutOfMemoryException();
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-16 14:32:11 +01:00
|
|
|
|
// Pin the managed string and convert it to ASCII using
|
|
|
|
|
// the pointer overload of System.Encoding.ASCII.GetBytes().
|
2013-12-17 11:39:47 +01:00
|
|
|
|
unsafe
|
|
|
|
|
{
|
|
|
|
|
fixed (char* pstr = str)
|
|
|
|
|
{
|
2014-01-16 14:32:11 +01:00
|
|
|
|
int actual_count = Encoding.ASCII.GetBytes(pstr, str.Length, (byte*)ptr, max_count);
|
2013-12-17 11:39:47 +01:00
|
|
|
|
Marshal.WriteByte(ptr, actual_count, 0); // Append '\0' at the end of the string
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Frees a marshalled string that allocated by <c>MarshalStringToPtr</c>.
|
|
|
|
|
/// </summary>
|
2014-02-22 21:55:48 +01:00
|
|
|
|
/// <param name="ptr">An unmanaged pointer allocated with <c>MarshalStringToPtr</c></param>
|
2013-12-17 11:39:47 +01:00
|
|
|
|
protected static void FreeStringPtr(IntPtr ptr)
|
|
|
|
|
{
|
|
|
|
|
Marshal.FreeHGlobal(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Marshals a <c>System.String</c> array to unmanaged memory by calling
|
2013-12-04 20:33:19 +01:00
|
|
|
|
/// Marshal.AllocHGlobal for each element.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>An unmanaged pointer to an array of null-terminated strings</returns>
|
|
|
|
|
/// <param name="str_array">The string array to marshal.</param>
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-19 23:51:47 +02:00
|
|
|
|
int i = 0;
|
|
|
|
|
try
|
2013-12-04 20:33:19 +01:00
|
|
|
|
{
|
2014-06-19 23:51:47 +02:00
|
|
|
|
for (i = 0; i < str_array.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
IntPtr str = MarshalStringToPtr(str_array[i]);
|
|
|
|
|
Marshal.WriteIntPtr(ptr, i * IntPtr.Size, str);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-22 21:38:10 +02:00
|
|
|
|
catch (OutOfMemoryException)
|
2014-06-19 23:51:47 +02:00
|
|
|
|
{
|
|
|
|
|
for (i = i - 1; i >= 0; --i)
|
|
|
|
|
{
|
|
|
|
|
Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, i * IntPtr.Size));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(ptr);
|
|
|
|
|
|
2014-06-22 21:38:10 +02:00
|
|
|
|
throw;
|
2013-12-04 20:33:19 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2013-12-17 11:39:47 +01:00
|
|
|
|
/// Frees a marshalled string that allocated by <c>MarshalStringArrayToPtr</c>.
|
2013-12-04 20:33:19 +01:00
|
|
|
|
/// </summary>
|
2013-12-17 11:39:47 +01:00
|
|
|
|
/// <param name="ptr">An unmanaged pointer allocated with <c>MarshalStringArrayToPtr</c></param>
|
2013-12-04 20:33:19 +01:00
|
|
|
|
/// <param name="length">The length of the string array.</param>
|
|
|
|
|
protected static void FreeStringArrayPtr(IntPtr ptr, int length)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < length; i++)
|
|
|
|
|
{
|
2014-06-19 23:51:47 +02:00
|
|
|
|
Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, i * IntPtr.Size));
|
2013-12-04 20:33:19 +01:00
|
|
|
|
}
|
|
|
|
|
Marshal.FreeHGlobal(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-03 21:01:11 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Internal Members
|
|
|
|
|
|
2014-04-26 18:28:51 +02:00
|
|
|
|
internal abstract void LoadEntryPoints();
|
2009-09-03 21:01:11 +02:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|