/// <summary> /// Initializes a new instance of the <see cref="OpenTK.Graphics.GraphicsContext"/> class using /// an external context handle that was created by a third-party library. /// </summary> /// <param name="handle"> /// A valid, unique handle for an external OpenGL context, or <c>ContextHandle.Zero</c> to use the current context. /// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before. /// </param> /// <param name="getAddress"> /// A <c>GetAddressDelegate</c> instance that accepts the name of an OpenGL function and returns /// a valid function pointer, or <c>IntPtr.Zero</c> if that function is not supported. This delegate should be /// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function /// pointers.) /// </param> /// <param name="getCurrent"> /// A <c>GetCurrentContextDelegate</c> instance that returns the handle of the current OpenGL context, /// or <c>IntPtr.Zero</c> if no context is current on the calling thread. This delegate should be implemented /// using the same toolkit that created the OpenGL context (i.e. if the context was created with /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve /// the current context.) /// </param> public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent) { if (getAddress == null || getCurrent == null) { throw new ArgumentNullException(); } lock (SyncRoot) { // Replace a zero-handle by the current context, if any if (handle == ContextHandle.Zero) { handle = getCurrent(); } // Make sure this handle corresponds to a valid, unique OpenGL context if (handle == ContextHandle.Zero) { throw new GraphicsContextMissingException(); } else if (available_contexts.ContainsKey(handle)) { throw new InvalidOperationException("Context handle has already been added"); } // We have a valid handle for an external OpenGL context, wrap it into a // DummyGLContext instance. implementation = new Platform.Dummy.DummyGLContext(handle, getAddress); GetCurrentContext = getCurrent ?? GetCurrentContext; AddContext(this); } implementation.LoadAll(); }
public void GetAddressAsync(string name) { GetAddressDelegate dc = new GetAddressDelegate(this.GetAddress); AsyncCallback cb = new AsyncCallback(this.GetResultsOnCallback); IAsyncResult ar = dc.BeginInvoke(name, cb, null); }
/// <summary> /// Link delegates field using import declaration, using platform specific method for determining procedures address. /// </summary> internal static void BindAPIFunction <T>(string path, string functionName, GetAddressDelegate getProcAddress, KhronosVersion version, ExtensionsCollection extensions) { FunctionContext functionContext = GetFunctionContext(typeof(T)); Debug.Assert(functionContext != null); BindAPIFunction(path, getProcAddress, functionContext.GetFunction(functionName), version, extensions); }
/// <summary> /// Link delegates field using import declaration, using platform specific method for determining procedures address. /// </summary> internal static void BindAPIFunction <T>(string path, string functionName, GetAddressDelegate getProcAddress, KhronosVersion version, ExtensionsCollection extensions) { if (path == null) { throw new ArgumentNullException("path"); } if (functionName == null) { throw new ArgumentNullException("function"); } if (getProcAddress == null) { throw new ArgumentNullException("getAddress"); } FunctionContext functionContext = GetFunctionContext(typeof(T)); Debug.Assert(functionContext != null); if (functionContext == null) { throw new InvalidOperationException("unrecognized API type"); } #if NETSTANDARD1_1 || NETSTANDARD1_4 TypeInfo delegatesClass = typeof(T).GetTypeInfo().GetDeclaredNestedType("Delegates"); Debug.Assert(delegatesClass != null); if (delegatesClass == null) { throw new NotImplementedException("missing Delegates class"); } FieldInfo functionField = delegatesClass.GetDeclaredField("p" + functionName); Debug.Assert(functionField != null); if (functionField == null) { throw new NotImplementedException(String.Format("unable to find function named {0}", functionName)); } #else Type delegatesClass = typeof(T).GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic); Debug.Assert(delegatesClass != null); if (delegatesClass == null) { throw new NotImplementedException("missing Delegates class"); } FieldInfo functionField = delegatesClass.GetField("p" + functionName, BindingFlags.Static | BindingFlags.NonPublic); Debug.Assert(functionField != null); if (functionField == null) { throw new NotImplementedException(String.Format("unable to find function named {0}", functionName)); } #endif BindAPIFunction(path, getProcAddress, functionContext, functionField, version, extensions); }
static UnsafeObject() { var getAddressMethod = CreateDynamicMethod <object, IntPtr>(nameof(GetAddressFromIL)); var getObjectMethod = CreateDynamicMethod <IntPtr, object>(nameof(GetObjectFromIL)); BuildIL(getAddressMethod); BuildIL(getObjectMethod); _getAddress = getAddressMethod.CreateDelegate(typeof(GetAddressDelegate)) as GetAddressDelegate; _getObject = getObjectMethod.CreateDelegate(typeof(GetObjectDelegate)) as GetObjectDelegate; }
public void GetAddressSync(string name) { try { GetAddressDelegate dc = new GetAddressDelegate(this.GetAddress); string result = dc(name); Console.WriteLine("\nSync: " + result); } catch (Exception ex) { Console.WriteLine("\nSync: a problem occurred: " + ex.Message); } }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="System.String"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="type"> /// A <see cref="System.Type"/> that specifies the type used for detecting import declarations and delegates fields. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform. /// </param> /// <param name="sImportMap"> /// A <see cref="T:SortedList{String, MethodIndo}"/> mapping a <see cref="MethodInfo"/> with the relative function name. /// </param> /// <param name="sDelegates"> /// A <see cref="T:List{FieldInfo}"/> listing <see cref="FieldInfo"/> related to function delegates. /// </param> /// <remarks> /// <para> /// The type <paramref name="type"/> shall have defined a nested class named "UnsafeNativeMethods" specifying the import declarations and a nested /// class named "Delagates" specifying the delegate fields. /// </para> /// </remarks> private static void LinkProcAddressImports(string path, Type type, GetAddressDelegate getAddress, out SortedList <string, MethodInfo> sImportMap, out List <FieldInfo> sDelegates) { Type impClass = type.GetNestedType("UnsafeNativeMethods", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); Debug.Assert(impClass != null); Type delClass = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic); Debug.Assert(delClass != null); // Query imports declarations MethodInfo[] iMethods = impClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic); sImportMap = new SortedList <string, MethodInfo>(iMethods.Length); foreach (MethodInfo m in iMethods) { sImportMap.Add(m.Name, m); } // Query delegates declarations sDelegates = new List <FieldInfo>(delClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic)); foreach (FieldInfo fi in sDelegates) { Delegate pDelegate = null; string pImportName = fi.Name.Substring(1); IntPtr mAddr = getAddress(path, pImportName); if (mAddr != IntPtr.Zero) { // Try to load external symbol if ((pDelegate = Marshal.GetDelegateForFunctionPointer(mAddr, fi.FieldType)) == null) { MethodInfo mInfo; if (sImportMap.TryGetValue(pImportName, out mInfo) == true) { pDelegate = Delegate.CreateDelegate(fi.FieldType, mInfo); } } if (pDelegate != null) { fi.SetValue(null, pDelegate); } } } }
public void GetResultsOnCallback(IAsyncResult ar) { GetAddressDelegate del = (GetAddressDelegate) ((AsyncResult)ar).AsyncDelegate; try { string result; result = del.EndInvoke(ar); Console.WriteLine("\nOn CallBack: result is " + result); } catch (Exception ex) { Console.WriteLine("\nOn CallBack, problem occurred: " + ex.Message); } }
public void GetAddressAsyncWait(string name) { GetAddressDelegate dc = new GetAddressDelegate(this.GetAddress); IAsyncResult ar = dc.BeginInvoke(name, null, null); // Main thread can in principle do other work now try { string result = dc.EndInvoke(ar); Console.WriteLine("\nAsync waiting : " + result); } catch (Exception ex) { Console.WriteLine("\nAsync waiting, a problem occurred : " + ex.Message); } }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="string"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="path"/> or <paramref name="getAddress"/> is null. /// </exception> internal static void BindAPI <T>(string path, GetAddressDelegate getAddress, KhronosVersion version, ExtensionsCollection extensions) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (getAddress == null) { throw new ArgumentNullException(nameof(getAddress)); } FunctionContext functionContext = GetFunctionContext(typeof(T)); Debug.Assert(functionContext != null); foreach (FieldInfo fi in functionContext.Delegates) { BindAPIFunction(path, getAddress, fi, version, extensions); } }
public void GetResultsOnCallback(IAsyncResult ar) { GetAddressDelegate del = (GetAddressDelegate)((AsyncResult)ar).AsyncDelegate; try { string result; result = del.EndInvoke(ar); lock (this) { this.address = result; this.status = ResultStatus.Done; } } catch (Exception ex) { lock (this) { this.address = ex.Message; this.status = ResultStatus.Failed; } } }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="String"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="imports"> /// A <see cref="ImportMap"/> mapping a <see cref="MethodInfo"/> with the relative function name. /// </param> /// <param name="delegates"> /// A <see cref="DelegateList"/> listing <see cref="FieldInfo"/> related to function delegates. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="path"/>, <paramref name="imports"/>, <paramref name="delegates"/> or <paramref name="getAddress"/> is null. /// </exception> private static void BindAPI <T>(string path, GetAddressDelegate getAddress) { if (path == null) { throw new ArgumentNullException("path"); } if (getAddress == null) { throw new ArgumentNullException("getAddress"); } FunctionContext functionContext = GetFunctionContext(typeof(T)); Debug.Assert(functionContext != null); if (functionContext == null) { throw new InvalidOperationException("unrecognized API type"); } foreach (FieldInfo fi in functionContext.Delegates) { BindAPIFunction(path, functionContext, fi, getAddress); } }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="System.String"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="type"> /// A <see cref="System.Type"/> that specifies the type used for detecting import declarations and delegates fields. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform. /// </param> /// <param name="sImportMap"> /// A <see cref="T:SortedList{String, MethodIndo}"/> mapping a <see cref="MethodInfo"/> with the relative function name. /// </param> /// <param name="sDelegates"> /// A <see cref="T:List{FieldInfo}"/> listing <see cref="FieldInfo"/> related to function delegates. /// </param> /// <remarks> /// <para> /// The type <paramref name="type"/> shall have defined a nested class named "UnsafeNativeMethods" specifying the import declarations and a nested /// class named "Delagates" specifying the delegate fields. /// </para> /// </remarks> private static void LinkProcAddressImports(string path, Type type, GetAddressDelegate getAddress, out SortedList<string, MethodInfo> sImportMap, out List<FieldInfo> sDelegates) { Type impClass = type.GetNestedType("UnsafeNativeMethods", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); Debug.Assert(impClass != null); Type delClass = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic); Debug.Assert(delClass != null); // Query imports declarations MethodInfo[] iMethods = impClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic); sImportMap = new SortedList<string, MethodInfo>(iMethods.Length); foreach (MethodInfo m in iMethods) sImportMap.Add(m.Name, m); // Query delegates declarations sDelegates = new List<FieldInfo>(delClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic)); foreach (FieldInfo fi in sDelegates) { Delegate pDelegate = null; string pImportName = fi.Name.Substring(1); IntPtr mAddr = getAddress(path, pImportName); if (mAddr != IntPtr.Zero) { // Try to load external symbol if ((pDelegate = Marshal.GetDelegateForFunctionPointer(mAddr, fi.FieldType)) == null) { MethodInfo mInfo; if (sImportMap.TryGetValue(pImportName, out mInfo) == true) pDelegate = Delegate.CreateDelegate(fi.FieldType, mInfo); } if (pDelegate != null) fi.SetValue(null, pDelegate); } } }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="String"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="imports"> /// A <see cref="ImportMap"/> mapping a <see cref="MethodInfo"/> with the relative function name. /// </param> /// <param name="delegates"> /// A <see cref="DelegateList"/> listing <see cref="FieldInfo"/> related to function delegates. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="path"/>, <paramref name="imports"/>, <paramref name="delegates"/> or <paramref name="getAddress"/> is null. /// </exception> private static void LoadProcDelegates(string path, ImportMap imports, DelegateList delegates, GetAddressDelegate getAddress) { if (path == null) { throw new ArgumentNullException("path"); } if (imports == null) { throw new ArgumentNullException("importMap"); } if (delegates == null) { throw new ArgumentNullException("delegates"); } if (getAddress == null) { throw new ArgumentNullException("getAddress"); } foreach (FieldInfo fi in delegates) { Attribute[] aliasOfAttributes = Attribute.GetCustomAttributes(fi, typeof(AliasOfAttribute)); string importName = fi.Name.Substring(1); // Delegate name always prefixes with 'p' IntPtr importAddress = IntPtr.Zero; if (aliasOfAttributes.Length > 0) { for (int i = 0; i < aliasOfAttributes.Length; i++) { if ((importAddress = getAddress(path, ((AliasOfAttribute)aliasOfAttributes[i]).SymbolName)) != IntPtr.Zero) { break; } } } else { importAddress = getAddress(path, importName); } // Is function implemented? if (importAddress == IntPtr.Zero) { fi.SetValue(null, null); continue; } Delegate delegatePtr; // Try to load external symbol if ((delegatePtr = Marshal.GetDelegateForFunctionPointer(importAddress, fi.FieldType)) == null) { MethodInfo methodInfo; if (imports.TryGetValue(importName, out methodInfo) == true) { delegatePtr = Delegate.CreateDelegate(fi.FieldType, methodInfo); } } if (delegatePtr != null) { fi.SetValue(null, delegatePtr); } } }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="String"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform. /// </param> /// <param name="functionContext"> /// A <see cref="FunctionContext"/> mapping a <see cref="MethodInfo"/> with the relative function name. /// </param> /// <param name="function"> /// A <see cref="FieldInfo"/> that specifies the underlying function field to be updated. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="path"/>, <paramref name="function"/> or <paramref name="getAddress"/> is null. /// </exception> private static void BindAPIFunction(string path, GetAddressDelegate getAddress, FunctionContext functionContext, FieldInfo function, KhronosVersion version, ExtensionsCollection extensions) { if (path == null) { throw new ArgumentNullException("path"); } if (functionContext == null) { throw new ArgumentNullException("functionContext"); } if (function == null) { throw new ArgumentNullException("function"); } if (getAddress == null) { throw new ArgumentNullException("getAddress"); } if (version != null || extensions != null) { if (IsCompatibleField(function, version, extensions) == false) { function.SetValue(null, null); // Function not supported: reset return; } } string importName = function.Name.Substring(1); // Delegate name always prefixes with 'p' IntPtr importAddress = IntPtr.Zero; // Load command address importAddress = getAddress(path, importName); // Manages aliases (load external symbol) if (importAddress == IntPtr.Zero) { #if !NETCORE Attribute[] aliasOfAttributes = Attribute.GetCustomAttributes(function, typeof(AliasOfAttribute)); #else Attribute[] aliasOfAttributes = new List <Attribute>(function.GetCustomAttributes(typeof(AliasOfAttribute))).ToArray(); #endif for (int i = 1 /* Skip base name */; i < aliasOfAttributes.Length; i++) { AliasOfAttribute aliasOfAttribute = (AliasOfAttribute)aliasOfAttributes[i]; if ((importAddress = getAddress(path, aliasOfAttribute.SymbolName)) != IntPtr.Zero) { break; } } } if (importAddress != IntPtr.Zero) { Delegate delegatePtr; // Try to load external symbol if ((delegatePtr = Marshal.GetDelegateForFunctionPointer(importAddress, function.FieldType)) == null) { MethodInfo methodInfo; if (functionContext.Imports.TryGetValue(importName, out methodInfo) == true) { #if !NETCORE delegatePtr = Delegate.CreateDelegate(function.FieldType, methodInfo); #else delegatePtr = methodInfo.CreateDelegate(function.FieldType); #endif } } if (delegatePtr != null) { function.SetValue(null, delegatePtr); } } else { function.SetValue(null, null); // Function not implemented: reset } }
/// <summary> /// Initializes a new instance of the <see cref="OpenTK.Graphics.GraphicsContext"/> class using /// an external context handle that was created by a third-party library. /// </summary> /// <param name="handle"> /// A valid, unique handle for an external OpenGL context, or <c>ContextHandle.Zero</c> to use the current context. /// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before. /// </param> /// <param name="getAddress"> /// A <c>GetAddressDelegate</c> instance that accepts the name of an OpenGL function and returns /// a valid function pointer, or <c>IntPtr.Zero</c> if that function is not supported. This delegate should be /// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function /// pointers.) /// </param> /// <param name="getCurrent"> /// A <c>GetCurrentContextDelegate</c> instance that returns the handle of the current OpenGL context, /// or <c>IntPtr.Zero</c> if no context is current on the calling thread. This delegate should be implemented /// using the same toolkit that created the OpenGL context (i.e. if the context was created with /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve /// the current context.) /// </param> public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent) { if (getAddress == null || getCurrent == null) throw new ArgumentNullException(); // Make sure OpenTK has been initialized. // Fixes https://github.com/opentk/opentk/issues/52 Toolkit.Init(); lock (SyncRoot) { // Replace a zero-handle by the current context, if any if (handle == ContextHandle.Zero) { handle = getCurrent(); } // Make sure this handle corresponds to a valid, unique OpenGL context if (handle == ContextHandle.Zero) { throw new GraphicsContextMissingException(); } else if (available_contexts.ContainsKey(handle)) { throw new InvalidOperationException("Context handle has already been added"); } // We have a valid handle for an external OpenGL context, wrap it into a // DummyGLContext instance. implementation = new Platform.Dummy.DummyGLContext(handle, getAddress); GetCurrentContext = getCurrent ?? GetCurrentContext; AddContext(this); } implementation.LoadAll(); }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="string"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. /// </param> /// <param name="function"> /// A <see cref="FieldInfo"/> that specifies the underlying function field to be updated. /// </param> /// <param name="version"></param> /// <param name="extensions"></param> private static void BindAPIFunction(string path, GetAddressDelegate getAddress, FieldInfo function, KhronosVersion version, ExtensionsCollection extensions) { Debug.Assert(path != null); Debug.Assert(getAddress != null); Debug.Assert(function != null); RequiredByFeatureAttribute requiredByFeature = null; List <RequiredByFeatureAttribute> requiredByExtensions = new List <RequiredByFeatureAttribute>(); string defaultName = function.Name.Substring(1); // Delegate name always prefixes with 'p' if (version != null || extensions != null) { bool isRemoved = false; #region Check Requirement #if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE IEnumerable <Attribute> attrRequired = new List <Attribute>(function.GetCustomAttributes(typeof(RequiredByFeatureAttribute))); #else IEnumerable <Attribute> attrRequired = Attribute.GetCustomAttributes(function, typeof(RequiredByFeatureAttribute)); #endif // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop foreach (RequiredByFeatureAttribute attr in attrRequired) { // Check for API support if (!attr.IsSupported(version, extensions)) { continue; } // Keep track of the features requiring this command if (attr.FeatureVersion != null) { // Version feature: keep track only of the maximum version if (requiredByFeature == null || requiredByFeature.FeatureVersion < attr.FeatureVersion) { requiredByFeature = attr; } } else { // Extension feature: collect every supporting extension requiredByExtensions.Add(attr); } } #endregion #region Check Deprecation/Removal if (requiredByFeature != null) { // Note: indeed the feature could be supported; check whether it is removed; this is checked only if // a non-extension feature is detected: extensions cannot remove commands #if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE Attribute[] attrRemoved = new List <Attribute>(function.GetCustomAttributes(typeof(RemovedByFeatureAttribute))).ToArray(); #else Attribute[] attrRemoved = Attribute.GetCustomAttributes(function, typeof(RemovedByFeatureAttribute)); #endif KhronosVersion maxRemovedVersion = null; // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop foreach (RemovedByFeatureAttribute attr in attrRemoved) { // Check for API support if (!attr.IsRemoved(version, extensions)) { continue; } // Removed! isRemoved = true; // Keep track of the maximum API version removing this command if (maxRemovedVersion == null || maxRemovedVersion < attr.FeatureVersion) { maxRemovedVersion = attr.FeatureVersion; } } // Check for resurrection if (isRemoved) { Debug.Assert(requiredByFeature != null); Debug.Assert(maxRemovedVersion != null); if (requiredByFeature.FeatureVersion > maxRemovedVersion) { isRemoved = false; } } } #endregion // Do not check feature requirements in case of removal. Note: extensions are checked all the same if (isRemoved) { requiredByFeature = null; } } // Load function pointer IntPtr importAddress; if (requiredByFeature != null || version == null) { // Load command address (version feature) string functionName = defaultName; if (requiredByFeature?.EntryPoint != null) { functionName = requiredByFeature.EntryPoint; } if ((importAddress = getAddress(path, functionName)) != IntPtr.Zero) { BindAPIFunction(function, importAddress); return; } } // Load command address (extension features) foreach (RequiredByFeatureAttribute extensionFeature in requiredByExtensions) { string functionName = extensionFeature.EntryPoint ?? defaultName; if ((importAddress = getAddress(path, functionName)) != IntPtr.Zero) { BindAPIFunction(function, importAddress); return; } } // Function not implemented: reset function.SetValue(null, null); }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="String"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="functionContext"> /// A <see cref="FunctionContext"/> mapping a <see cref="MethodInfo"/> with the relative function name. /// </param> /// <param name="function"> /// A <see cref="FieldInfo"/> that specifies the underlying function field to be updated. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="path"/>, <paramref name="function"/> or <paramref name="getAddress"/> is null. /// </exception> private static void BindAPIFunction(string path, FunctionContext functionContext, FieldInfo function, GetAddressDelegate getAddress) { if (path == null) { throw new ArgumentNullException("path"); } if (functionContext == null) { throw new ArgumentNullException("functionContext"); } if (function == null) { throw new ArgumentNullException("function"); } if (getAddress == null) { throw new ArgumentNullException("getAddress"); } Attribute[] aliasOfAttributes = Attribute.GetCustomAttributes(function, typeof(AliasOfAttribute)); string importName = function.Name.Substring(1); // Delegate name always prefixes with 'p' IntPtr importAddress = IntPtr.Zero; // Manages aliases (load external symbol) if (aliasOfAttributes.Length > 0) { for (int i = 0; i < aliasOfAttributes.Length; i++) { AliasOfAttribute aliasOfAttribute = (AliasOfAttribute)aliasOfAttributes[i]; if ((importAddress = getAddress(path, aliasOfAttribute.SymbolName)) != IntPtr.Zero) { break; } } } else { importAddress = getAddress(path, importName); } if (importAddress != IntPtr.Zero) { Delegate delegatePtr; // Try to load external symbol if ((delegatePtr = Marshal.GetDelegateForFunctionPointer(importAddress, function.FieldType)) == null) { MethodInfo methodInfo; if (functionContext.Imports.TryGetValue(importName, out methodInfo) == true) { delegatePtr = Delegate.CreateDelegate(function.FieldType, methodInfo); } } if (delegatePtr != null) { function.SetValue(null, delegatePtr); } } else { function.SetValue(null, null); // Function not implemented } }
/// <summary> /// Link delegates fields using import declarations. /// </summary> /// <param name="path"> /// A <see cref="string"/> that specifies the assembly file path containing the import functions. /// </param> /// <param name="getAddress"> /// A <see cref="GetAddressDelegate"/> used for getting function pointers. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="path"/> or <paramref name="getAddress"/> is null. /// </exception> internal static void BindAPI <T>(string path, GetAddressDelegate getAddress, KhronosVersion version) { BindAPI <T>(path, getAddress, version, null); }