Esempio n. 1
0
        public void NegTest1()
        {
            AssemblyBuilder myAssembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly_SignatureHelperAddArgument"), AssemblyBuilderAccess.Run);
            ModuleBuilder   myModule   = TestLibrary.Utilities.GetModuleBuilder(myAssembly, "Module_SignatureHelperAddArgument");

            int expectedValue = 5;
            int actualValue;

            SignatureHelper sHelper = SignatureHelper.GetMethodSigHelper(null, typeof(string), new Type[] { typeof(char), typeof(int) });

            actualValue = sHelper.GetSignature().Length;
            Assert.Equal(expectedValue, actualValue);
        }
        public void PosTest5()
        {
            AssemblyBuilder myAssembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Assembly_SignatureHelperAddArgument"), AssemblyBuilderAccess.Run);
            ModuleBuilder   myModule   = TestLibrary.Utilities.GetModuleBuilder(myAssembly, "Module_SignatureHelperAddArgument");

            int expectedValue = 3;
            int actualValue;

            SignatureHelper sHelper = SignatureHelper.GetMethodSigHelper(myModule, CallingConventions.VarArgs, typeof(string));

            actualValue = sHelper.GetSignature().Length;
            Assert.Equal(expectedValue, actualValue);
        }
Esempio n. 3
0
        private MethodInfo /*!*/ EmitCalliStub()
        {
            if (_calliStub != null)
            {
                return(_calliStub);
            }

            var returnType     = ToNativeType(_returnType);
            var parameterTypes = new Type[1 + _signature.Length];

            // target function ptr:
            parameterTypes[0] = typeof(IntPtr);

            // calli args:
            for (int i = 0; i < _signature.Length; i++)
            {
                parameterTypes[1 + i] = ToNativeType(_signature[i]);
            }

#if USE_SNIPPETS
            TypeGen       tg = Snippets.Shared.DefineType("calli", typeof(object), false, false);
            MethodBuilder dm = tg.TypeBuilder.DefineMethod("calli", CompilerHelpers.PublicStatic, returnType, parameterTypes);
#else
            DynamicMethod dm = new DynamicMethod("calli", returnType, parameterTypes, DynamicModule);
#endif

            var il        = dm.GetILGenerator();
            var signature = SignatureHelper.GetMethodSigHelper(CallingConvention.Winapi, returnType);

            // calli args:
            for (int i = 1; i < parameterTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, i);
                signature.AddArgument(parameterTypes[i]);
            }

            il.Emit(OpCodes.Ldarg_0);

            il.Emit(OpCodes.Calli, signature);
            il.Emit(OpCodes.Ret);

#if USE_SNIPPETS
            return(_calliStub = tg.TypeBuilder.CreateType().GetMethod("calli"));
#else
            return(_calliStub = dm);
#endif
        }
Esempio n. 4
0
        private GrEmit.Utils.DynamicILInfo CreateDynamicILInfo(GrEmit.Utils.DynamicScope scope)
        {
            SignatureHelper helper = SignatureHelper.GetMethodSigHelper(inst.CallingConvention, inst.ReturnType);

            foreach (var parameter in inst.GetParameters())
            {
                helper.AddArgument(parameter.ParameterType);
            }
            byte[] methodSignature = helper.GetSignature();

            // Have to do this, since needed method is internal
            byte[] methodSignatureWithEnd = new byte[methodSignature.Length + 1];
            Array.Copy(methodSignature, methodSignatureWithEnd, methodSignature.Length);
            methodSignatureWithEnd[methodSignatureWithEnd.Length - 1] = 0;

            return(new GrEmit.Utils.DynamicILInfo(scope, inst, methodSignatureWithEnd));
        }
Esempio n. 5
0
    public static int test_0_calli_dynamic()
    {
        /* we need the cdecl version because the icall convention demands it under Windows */
        IntPtr func = mono_test_marshal_lookup_symbol("mono_test_marshal_inout_array_cdecl");

        DynamicMethod dm = new DynamicMethod("calli", typeof(void), new Type [] { typeof(IntPtr), typeof(int[]) });

        var il        = dm.GetILGenerator();
        var signature = SignatureHelper.GetMethodSigHelper(CallingConvention.Cdecl, typeof(void));

        il.Emit(OpCodes.Ldarg, 1);
        signature.AddArgument(typeof(byte[]));

        il.Emit(OpCodes.Ldarg_0);

        il.Emit(OpCodes.Calli, signature);
        il.Emit(OpCodes.Ret);

        var f = (CalliDel)dm.CreateDelegate(typeof(CalliDel));

        int[] arr = new int [1000];
        for (int i = 0; i < 50; ++i)
        {
            arr [i] = (int)i;
        }
        f(func, arr);
        if (arr.Length != 1000)
        {
            return(1);
        }
        for (int i = 0; i < 50; ++i)
        {
            if (arr [i] != 50 - i)
            {
                return(2);
            }
        }

        return(0);
    }
Esempio n. 6
0
        private static string GetMethodSignature(MethodInfo method)
        {
            var returnType = method.ReturnType;
            var parameters = method.GetParameters().Select(p => p.ParameterType).ToArray();

            var requiredParameterTypes = new[] { typeof(int), typeof(int), typeof(long) };
            var lastParameterTypes     = parameters.Skip(parameters.Length - requiredParameterTypes.Length);

            if (!lastParameterTypes.SequenceEqual(requiredParameterTypes))
            {
                throw new Exception(
                          $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet parameter requirements. " +
                          "Wrapper methods must have at least 3 parameters and the last 3 must be of types Int32 (opCode), Int32 (mdToken), and Int64 (moduleVersionPtr).");
            }

            var signatureHelper = SignatureHelper.GetMethodSigHelper(method.CallingConvention, returnType);

            signatureHelper.AddArguments(parameters, requiredCustomModifiers: null, optionalCustomModifiers: null);
            var signatureBytes = signatureHelper.GetSignature();

            if (method.IsGenericMethod)
            {
                // if method is generic, fix first byte (calling convention)
                // and insert a second byte with generic parameter count
                const byte IMAGE_CEE_CS_CALLCONV_GENERIC = 0x10;
                var        genericArguments = method.GetGenericArguments();

                var newSignatureBytes = new byte[signatureBytes.Length + 1];
                newSignatureBytes[0] = (byte)(signatureBytes[0] | IMAGE_CEE_CS_CALLCONV_GENERIC);
                newSignatureBytes[1] = (byte)genericArguments.Length;
                Array.Copy(signatureBytes, 1, newSignatureBytes, 2, signatureBytes.Length - 1);

                signatureBytes = newSignatureBytes;
            }

            return(string.Join(" ", signatureBytes.Select(b => b.ToString("X2"))));
        }
        protected override AssemblyDebugging CreateAssembly()
        {
            using (var assembly = DebuggingTests.CreateDebuggingAssembly("MethodThatUsesSignatureHelper"))
            {
                using (var type = DebuggingTests.CreateDebuggingType(
                           assembly, assembly.Builder.GetDynamicModule(assembly.Builder.GetName().Name),
                           "SimpleClass"))
                {
                    using (var ctor = type.GetMethodDebugging(
                               type.Builder.DefineConstructor(
                                   MethodAttributes.Public | MethodAttributes.SpecialName |
                                   MethodAttributes.RTSpecialName | MethodAttributes.HideBySig,
                                   CallingConventions.Standard, Type.EmptyTypes)))
                    {
                        ctor.Emit(OpCodes.Ldarg_0);
                        var objectCtor = typeof(object).GetConstructor(Type.EmptyTypes);
                        ctor.Emit(OpCodes.Call, objectCtor);
                        ctor.Emit(OpCodes.Ret);
                    }

                    using (var method = type.GetMethodDebugging(
                               type.Builder.DefineMethod("CallViaHelper",
                                                         MethodAttributes.HideBySig | MethodAttributes.Public)))
                    {
                        var helper = SignatureHelper.GetMethodSigHelper(
                            assembly.Builder.GetDynamicModule(assembly.Builder.GetName().Name),
                            CallingConventions.Standard, null);
                        method.Emit(OpCodes.Calli, helper);
                        method.Emit(OpCodes.Ret);
                    }

                    type.Builder.CreateType();
                }

                return(assembly);
            }
        }
    public static void NegativeTest_ViaLdftn()
    {
        /*
         * .locals init (native int V_0)
         * IL_0000:  nop
         * IL_0001:  ldftn      void ConsoleApplication1.Program::callback(int32)
         * IL_0007:  stloc.0
         * IL_0008:  ldc.i4.s   12
         * IL_000a:  ldloc.0
         * IL_000b:  calli      void(int32)
         * IL_0010:  nop
         * IL_0011:  ret
         */
        DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableLdftn", null, null, typeof(Program).Module);
        ILGenerator   il = testNativeCallable.GetILGenerator();

        il.DeclareLocal(typeof(IntPtr));
        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod("LdftnCallback"));
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldc_I4, 12);
        il.Emit(OpCodes.Ldloc_0);

        SignatureHelper sig = SignatureHelper.GetMethodSigHelper(typeof(Program).Module, null, new Type[] { typeof(int) });

        sig.AddArgument(typeof(int));

        // il.EmitCalli is not available  and the below is not correct
        il.Emit(OpCodes.Calli, sig);
        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Ret);

        NativeMethodInvoker testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker));

        testNativeMethod();
    }
Esempio n. 9
0
    static void Main(string[] args)
    {
        AssemblyName an = new AssemblyName();

        an.Name = "HelloWorld";
        AssemblyBuilder ab     = Thread.GetDomain().DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder   module = ab.DefineDynamicModule("b.dll");
        TypeBuilder     tb     = module.DefineType("type", TypeAttributes.Public | TypeAttributes.Class);
        MethodBuilder   mb     = tb.DefineMethod("test",
                                                 MethodAttributes.HideBySig | MethodAttributes.Static |
                                                 MethodAttributes.Public, typeof(void), null);
        ILGenerator ig = mb.GetILGenerator();

        //
        // This is the actual test:
        //   Generate a method signature that contains modopts and modreqs
        //   and call that.  It has no name or anything, not sure how this
        //   is actually used, but we at least generate the stuff
        //
        SignatureHelper sh = SignatureHelper.GetMethodSigHelper(module, CallingConventions.HasThis, typeof(int));

        sh.AddArgument(typeof(bool));
        Type [] req = new Type [] { typeof(System.Runtime.CompilerServices.IsBoxed) };
        sh.AddArgument(typeof(string), req, null);
        Type [] opt = new Type [] { typeof(System.Runtime.CompilerServices.IsConst) };
        sh.AddArgument(typeof(byte), null, opt);
        sh.AddArgument(typeof(int), null, opt);
        sh.AddArgument(typeof(long), null, opt);
        ig.Emit(OpCodes.Call, sh);

        ig.Emit(OpCodes.Ret);

        tb.CreateType();

        ab.Save("b.dll");
    }
        private static string GetMethodSignature(MethodInfo method, InterceptMethodAttribute attribute)
        {
            var returnType = method.ReturnType;
            var parameters = method.GetParameters().Select(p => p.ParameterType).ToArray();

            var requiredParameterTypes = new[] { typeof(int), typeof(int), typeof(long) };
            var lastParameterTypes     = parameters.Skip(parameters.Length - requiredParameterTypes.Length);

            if (attribute.MethodReplacementAction == MethodReplacementActionType.ReplaceTargetMethod)
            {
                if (!lastParameterTypes.SequenceEqual(requiredParameterTypes))
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet parameter requirements. " +
                              "Wrapper methods must have at least 3 parameters and the last 3 must be of types Int32 (opCode), Int32 (mdToken), and Int64 (moduleVersionPtr).");
                }
            }
            else if (attribute.MethodReplacementAction == MethodReplacementActionType.InsertFirst)
            {
                if (attribute.CallerAssembly == null || attribute.CallerType == null || attribute.CallerMethod == null)
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet InterceptMethodAttribute requirements. " +
                              "Currently, InsertFirst methods must have CallerAssembly, CallerType, and CallerMethod defined. " +
                              $"Current values: CallerAssembly=\"{attribute.CallerAssembly}\", CallerType=\"{attribute.CallerType}\", CallerMethod=\"{attribute.CallerMethod}\"");
                }
                else if (parameters.Any())
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet parameter requirements. " +
                              "Currently, InsertFirst methods must have zero parameters.");
                }
                else if (returnType != typeof(void))
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet return type requirements. " +
                              "Currently, InsertFirst methods must have a void return type.");
                }
            }

            var signatureHelper = SignatureHelper.GetMethodSigHelper(method.CallingConvention, returnType);

            signatureHelper.AddArguments(parameters, requiredCustomModifiers: null, optionalCustomModifiers: null);
            var signatureBytes = signatureHelper.GetSignature();

            if (method.IsGenericMethod)
            {
                // if method is generic, fix first byte (calling convention)
                // and insert a second byte with generic parameter count
                const byte IMAGE_CEE_CS_CALLCONV_GENERIC = 0x10;
                var        genericArguments = method.GetGenericArguments();

                var newSignatureBytes = new byte[signatureBytes.Length + 1];
                newSignatureBytes[0] = (byte)(signatureBytes[0] | IMAGE_CEE_CS_CALLCONV_GENERIC);
                newSignatureBytes[1] = (byte)genericArguments.Length;
                Array.Copy(signatureBytes, 1, newSignatureBytes, 2, signatureBytes.Length - 1);

                signatureBytes = newSignatureBytes;
            }

            return(string.Join(" ", signatureBytes.Select(b => b.ToString("X2"))));
        }
Esempio n. 11
0
        public void GetMethodSigHelper_Module_Type_TypeArray_NullObjectInParameterType_ThrowsArgumentNullException()
        {
            ModuleBuilder module = Helpers.DynamicModule();

            AssertExtensions.Throws <ArgumentNullException>("argument", () => SignatureHelper.GetMethodSigHelper(module, typeof(string), new Type[] { typeof(char), null }));
        }
Esempio n. 12
0
        public void GetMethodSigHelper_CallingConventions_Type_Length_ReturnsThree(CallingConventions callingConventions, Type type)
        {
            SignatureHelper helper = SignatureHelper.GetMethodSigHelper(callingConventions, type);

            Assert.Equal(3, helper.GetSignature().Length);
        }
Esempio n. 13
0
        private static IDispatchInvokeDelegate Create_IDispatchInvoke(bool returnResult)
        {
            const int dispatchPointerIndex = 0;
            const int memberDispIdIndex    = 1;
            const int flagsIndex           = 2;
            const int dispParamsIndex      = 3;
            const int resultIndex          = 4;
            const int exceptInfoIndex      = 5;
            const int argErrIndex          = 6;

            Debug.Assert(argErrIndex + 1 == typeof(IDispatchInvokeDelegate).GetMethod("Invoke").GetParameters().Length);

            Type[] paramTypes = new Type[argErrIndex + 1];
            paramTypes[dispatchPointerIndex] = typeof(IntPtr);
            paramTypes[memberDispIdIndex]    = typeof(int);
            paramTypes[flagsIndex]           = typeof(ComTypes.INVOKEKIND);
            paramTypes[dispParamsIndex]      = typeof(ComTypes.DISPPARAMS).MakeByRefType();
            paramTypes[resultIndex]          = typeof(Variant).MakeByRefType();
            paramTypes[exceptInfoIndex]      = typeof(ExcepInfo).MakeByRefType();
            paramTypes[argErrIndex]          = typeof(uint).MakeByRefType();

            // Define the dynamic method in our assembly so we skip verification
            DynamicMethod dm     = new DynamicMethod("IDispatchInvoke", typeof(int), paramTypes, DynamicModule);
            ILGenerator   method = dm.GetILGenerator();

            // return functionPtr(...)

            EmitLoadArg(method, dispatchPointerIndex);
            EmitLoadArg(method, memberDispIdIndex);

            // burn the address of our empty IID in directly.  This is never freed, relocated, etc...
            // Note passing this as a Guid directly results in a ~30% perf hit for IDispatch invokes so
            // we also pass it directly as an IntPtr instead.
            if (IntPtr.Size == 4)
            {
                method.Emit(OpCodes.Ldc_I4, UnsafeMethods.NullInterfaceId.ToInt32()); // riid
            }
            else
            {
                method.Emit(OpCodes.Ldc_I8, UnsafeMethods.NullInterfaceId.ToInt64()); // riid
            }
            method.Emit(OpCodes.Conv_I);

            method.Emit(OpCodes.Ldc_I4_0); // lcid
            EmitLoadArg(method, flagsIndex);

            EmitLoadArg(method, dispParamsIndex);

            if (returnResult)
            {
                EmitLoadArg(method, resultIndex);
            }
            else
            {
                method.Emit(OpCodes.Ldsfld, typeof(IntPtr).GetField("Zero"));
            }
            EmitLoadArg(method, exceptInfoIndex);
            EmitLoadArg(method, argErrIndex);

            // functionPtr = *(IntPtr*)(*(dispatchPointer) + VTABLE_OFFSET)
            int idispatchInvokeOffset = ((int)IDispatchMethodIndices.IDispatch_Invoke) * Marshal.SizeOf(typeof(IntPtr));

            EmitLoadArg(method, dispatchPointerIndex);
            method.Emit(OpCodes.Ldind_I);
            method.Emit(OpCodes.Ldc_I4, idispatchInvokeOffset);
            method.Emit(OpCodes.Add);
            method.Emit(OpCodes.Ldind_I);

            SignatureHelper signature = SignatureHelper.GetMethodSigHelper(CallingConvention.Winapi, typeof(int));

            Type[] invokeParamTypes = new Type[] {
                typeof(IntPtr),     // dispatchPointer
                typeof(int),        // memberDispId
                typeof(IntPtr),     // riid
                typeof(int),        // lcid
                typeof(ushort),     // flags
                typeof(IntPtr),     // dispParams
                typeof(IntPtr),     // result
                typeof(IntPtr),     // excepInfo
                typeof(IntPtr),     // argErr
            };
            signature.AddArguments(invokeParamTypes, null, null);
            method.Emit(OpCodes.Calli, signature);

            method.Emit(OpCodes.Ret);
            return((IDispatchInvokeDelegate)dm.CreateDelegate(typeof(IDispatchInvokeDelegate)));
        }
Esempio n. 14
0
        public static SignatureHelper ResolveReflectionSignature(this IMethodSignature csite, Module context)
        {
            SignatureHelper shelper;

            switch (csite.CallingConvention)
            {
#if !NETSTANDARD
            case MethodCallingConvention.C:
                shelper = SignatureHelper.GetMethodSigHelper(context, CallingConvention.Cdecl, csite.ReturnType.ResolveReflection());
                break;

            case MethodCallingConvention.StdCall:
                shelper = SignatureHelper.GetMethodSigHelper(context, CallingConvention.StdCall, csite.ReturnType.ResolveReflection());
                break;

            case MethodCallingConvention.ThisCall:
                shelper = SignatureHelper.GetMethodSigHelper(context, CallingConvention.ThisCall, csite.ReturnType.ResolveReflection());
                break;

            case MethodCallingConvention.FastCall:
                shelper = SignatureHelper.GetMethodSigHelper(context, CallingConvention.FastCall, csite.ReturnType.ResolveReflection());
                break;

            case MethodCallingConvention.VarArg:
                shelper = SignatureHelper.GetMethodSigHelper(context, CallingConventions.VarArgs, csite.ReturnType.ResolveReflection());
                break;
#else
            case MethodCallingConvention.C:
            case MethodCallingConvention.StdCall:
            case MethodCallingConvention.ThisCall:
            case MethodCallingConvention.FastCall:
            case MethodCallingConvention.VarArg:
                throw new NotSupportedException("Unmanaged calling conventions for callsites not supported");
#endif

            default:
                if (csite.ExplicitThis)
                {
                    shelper = SignatureHelper.GetMethodSigHelper(context, CallingConventions.ExplicitThis, csite.ReturnType.ResolveReflection());
                }
                else
                {
                    shelper = SignatureHelper.GetMethodSigHelper(context, CallingConventions.Standard, csite.ReturnType.ResolveReflection());
                }
                break;
            }

            if (context != null)
            {
                List <Type> modReq = new List <Type>();
                List <Type> modOpt = new List <Type>();

                foreach (ParameterDefinition param in csite.Parameters)
                {
                    if (param.ParameterType.IsSentinel)
                    {
                        shelper.AddSentinel();
                    }

                    if (param.ParameterType.IsPinned)
                    {
                        shelper.AddArgument(param.ParameterType.ResolveReflection(), true);
                        continue;
                    }

                    modOpt.Clear();
                    modReq.Clear();

                    for (
                        TypeReference paramTypeRef = param.ParameterType;
                        paramTypeRef is TypeSpecification paramTypeSpec;
                        paramTypeRef = paramTypeSpec.ElementType
                        )
                    {
                        switch (paramTypeRef)
                        {
                        case RequiredModifierType paramTypeModReq:
                            modReq.Add(paramTypeModReq.ModifierType.ResolveReflection());
                            break;

                        case OptionalModifierType paramTypeOptReq:
                            modOpt.Add(paramTypeOptReq.ModifierType.ResolveReflection());
                            break;
                        }
                    }

                    shelper.AddArgument(param.ParameterType.ResolveReflection(), modReq.ToArray(), modOpt.ToArray());
                }
            }
            else
            {
                foreach (ParameterDefinition param in csite.Parameters)
                {
                    shelper.AddArgument(param.ParameterType.ResolveReflection());
                }
            }

            return(shelper);
        }
 public void GetMethodSigHelperNormalModule()
 {
     SignatureHelper.GetMethodSigHelper(typeof(int).Module, CallingConventions.Standard, typeof(int));
 }
        /// <summary>
        /// takes a mbuilder for output, the input assembly, the name of the type,
        /// and a flag indicating whether it's an instance type or not (i.e. whether
        /// the members should be static or not.
        ///
        /// It then munges mercilessly.
        /// </summary>
        /// <param name="mbuilder"></param>
        /// <param name="inputAssembly"></param>
        /// <param name="typeName"></param>
        /// <param name="isInstanceClass"></param>
        public static void ProcessType(ModuleBuilder mbuilder,
                                       Assembly inputAssembly,
                                       string typeName,
                                       bool isInstanceClass)
        {
            TypeBuilder glbuilder = mbuilder.DefineType(typeName,
                                                        TypeAttributes.Public |
                                                        TypeAttributes.Class |
                                                        TypeAttributes.Sealed);

            glbuilder.SetCustomAttribute(GetCLSCompliantCAB(true));

            Type gltype = inputAssembly.GetType(typeName);

            MemberInfo [] glMembers = gltype.GetMembers(BindingFlags.Instance |
                                                        BindingFlags.Static |
                                                        BindingFlags.Public |
                                                        BindingFlags.NonPublic |
                                                        BindingFlags.DeclaredOnly);

            // just something to help us print some status..
            int methodCount = 0;

            Console.Write("Processing {0}...", typeName);

            foreach (MemberInfo qi in glMembers)
            {
                // Fields
                FieldInfo fi = qi as FieldInfo;
                if (fi != null)
                {
                    // Console.WriteLine ("FIELD: " + fi.Name);
                    FieldBuilder fb = glbuilder.DefineField(fi.Name, fi.FieldType, fi.Attributes);
                    // only set constants in the non-instance class
                    if (fi.FieldType != typeof(System.IntPtr) && !isInstanceClass)
                    {
                        fb.SetConstant(fi.GetValue(gltype));
                    }
                    else
                    {
                        object [] extattrs = fi.GetCustomAttributes(typeof(OpenGl.OpenGLExtensionImport), false);
                        if (extattrs.Length > 0)
                        {
                            OpenGl.OpenGLExtensionImport ogl = extattrs[0] as OpenGl.OpenGLExtensionImport;
                            if (ogl == null)
                            {
                                throw new InvalidProgramException("Thought we had an attr, guess we were wrong!");
                            }
                            fb.SetCustomAttribute(CreateGLExtCAB(ogl.ExtensionName, ogl.EntryPoint));
                        }

                        // this is a slot to hold an extension addr,
                        // so we save it.  We have to do this because on
                        // windows we can't call GetField on a dynamic type.
                        // This is probably faster anyway.
                        field_hash[fi.Name] = fb;
                    }
                    continue;
                }

                // Methods
                MethodInfo mi = qi as MethodInfo;
                if (mi != null)
                {
                    bool      is_ext;
                    bool      is_dll;
                    bool      is_cls_compliant;
                    object [] extattrs = mi.GetCustomAttributes(typeof(OpenGl.OpenGLExtensionImport), false);
                    object [] clsattrs = mi.GetCustomAttributes(typeof(CLSCompliantAttribute), false);

                    is_ext = (extattrs.Length > 0);
                    is_dll = (mi.Attributes & MethodAttributes.PinvokeImpl) != 0;

                    if (clsattrs.Length > 0)
                    {
                        is_cls_compliant = (clsattrs[0] as CLSCompliantAttribute).IsCompliant;
                    }
                    else
                    {
                        is_cls_compliant = true;
                    }

                    ParameterInfo []       parms        = mi.GetParameters();
                    Type []                methodSig    = new Type [parms.Length];
                    ParameterAttributes [] methodParams = new ParameterAttributes [parms.Length];
                    for (int i = 0; i < parms.Length; i++)
                    {
                        methodSig[i]    = parms[i].ParameterType;
                        methodParams[i] = parms[i].Attributes;
                    }

                    // Console.WriteLine ("Method: {0} is_dll: {1}", mi.Name, is_dll);

                    if (is_dll)
                    {
                        // this is a normal DLL import'd method
                        // Console.WriteLine ("DLL import method: " + mi.Name);
                        MethodBuilder mb = glbuilder.DefinePInvokeMethod(mi.Name, GL_NATIVE_LIBRARY, mi.Name,
                                                                         mi.Attributes,
                                                                         CallingConventions.Standard,
                                                                         mi.ReturnType, methodSig,
                                                                         CallingConvention.Winapi,
                                                                         CharSet.Ansi);
                        mb.SetImplementationFlags(mb.GetMethodImplementationFlags() |
                                                  MethodImplAttributes.PreserveSig);

                        // Set In/Out/etc. back
                        for (int i = 0; i < parms.Length; i++)
                        {
                            mb.DefineParameter(i + 1, methodParams[i], null);
                        }

                        mb.SetCustomAttribute(GetSuppressUnmanagedCSCAB());
                        if (is_cls_compliant)
                        {
                            mb.SetCustomAttribute(GetCLSCompliantCAB(true));
                        }
                        else
                        {
                            mb.SetCustomAttribute(GetCLSCompliantCAB(false));
                        }
                    }
                    else if (is_ext)
                    {
                        // this is an OpenGLExtensionImport method
                        OpenGl.OpenGLExtensionImport ogl = extattrs[0] as OpenGl.OpenGLExtensionImport;
                        if (ogl == null)
                        {
                            throw new InvalidProgramException("Thought we had an OpenGLExtensionImport, guess not?");
                        }

                        // Console.WriteLine ("OpenGL Extension method: " + mi.Name);
                        MethodBuilder mb = glbuilder.DefineMethod(mi.Name, mi.Attributes, mi.ReturnType, methodSig);
                        // Set In/Out/etc. back
                        for (int i = 0; i < parms.Length; i++)
                        {
                            mb.DefineParameter(i + 1, methodParams[i], null);
                        }

                        // put attributes
                        mb.SetCustomAttribute(GetSuppressUnmanagedCSCAB());
                        if (is_cls_compliant)
                        {
                            mb.SetCustomAttribute(GetCLSCompliantCAB(true));
                        }
                        else
                        {
                            mb.SetCustomAttribute(GetCLSCompliantCAB(false));
                        }
                        // now build the IL
                        string    fieldname = "ext__" + ogl.ExtensionName + "__" + ogl.EntryPoint;
                        FieldInfo addrfield = field_hash[fieldname] as FieldInfo;

                        // no workie on win32; the field_hash is probably faster anyway
                        //        FieldInfo addrfield = glbuilder.GetField(fieldname,
                        //                                                 BindingFlags.Instance |
                        //                                                 BindingFlags.Static |
                        //                                                 BindingFlags.Public |
                        //                                                 BindingFlags.NonPublic |
                        //                                                 BindingFlags.DeclaredOnly);

                        ILGenerator ilg            = mb.GetILGenerator();
                        ArrayList   locals         = new ArrayList();
                        Type []     methodCalliSig = new Type[methodSig.Length];
                        int         thislocal;
                        int         numargs   = methodSig.Length;
                        int         argoffset = 0;
                        if (isInstanceClass)
                        {
                            argoffset = 1;
                        }

                        for (int arg = argoffset; arg < numargs; arg++)
                        {
                            EmitLdarg(ilg, arg);

                            // we need to convert strings and string arrays to C
                            // null-terminated strings.  Use StringToHGlobalAnsi
                            // from Marshal.  We don't handle byref string arrays;
                            // there are so few (any?) of them that we can just
                            // return an IntPtr.
                            if (methodSig[arg].IsArray &&
                                methodSig[arg].GetElementType() == typeof(string))
                            {
                                //Console.WriteLine ("String[] param: Method: {0} Param: {1} Type: {2}", mi.Name, arg - argoffset, methodSig[arg]);
                                if (locals.Count == 0)
                                {
                                    locals.Add(ilg.DeclareLocal(typeof(int)));
                                }

                                thislocal = locals.Count;
                                locals.Add(ilg.DeclareLocal(typeof(IntPtr[])));

                                // we have the source array on the stack; get its length,
                                // and allocate a new IntPtr array
                                ilg.Emit(OpCodes.Ldlen);
                                ilg.Emit(OpCodes.Conv_I4);
                                ilg.Emit(OpCodes.Newarr, typeof(IntPtr));
                                EmitStloc(ilg, thislocal);

                                // set our loop counter to 0;
                                ilg.Emit(OpCodes.Ldc_I4_0);
                                EmitStloc(ilg, 0);

                                // declare our loop label; we'll branch
                                // back to here after each conversion
                                Label loop = ilg.DefineLabel();
                                ilg.MarkLabel(loop);

                                // put the address of the destination element onto the stack
                                EmitLdloc(ilg, thislocal);
                                EmitLdloc(ilg, 0);
                                ilg.Emit(OpCodes.Ldelema, typeof(IntPtr));

                                // put the source string on the stack
                                EmitLdarg(ilg, arg);
                                EmitLdloc(ilg, 0);
                                ilg.Emit(OpCodes.Ldelem_Ref);

                                // convert
                                ilg.EmitCall(OpCodes.Call, GetStringMarshalMI(), null);

                                // store the result into the address we put up above
                                ilg.Emit(OpCodes.Stobj, typeof(IntPtr));

                                // add 1 to loop counter
                                EmitLdloc(ilg, 0);
                                ilg.Emit(OpCodes.Ldc_I4_1);
                                ilg.Emit(OpCodes.Add);
                                ilg.Emit(OpCodes.Dup);
                                EmitStloc(ilg, 0);

                                // test if loop counter < array length, and branch back
                                // to start of loop
                                EmitLdarg(ilg, arg);
                                ilg.Emit(OpCodes.Ldlen);
                                ilg.Emit(OpCodes.Conv_I4);
                                ilg.Emit(OpCodes.Blt, loop);

                                // finally emit the location of the first element of the array
                                EmitLdloc(ilg, thislocal);
                                ilg.Emit(OpCodes.Ldc_I4_0);
                                ilg.Emit(OpCodes.Ldelema, typeof(IntPtr));

                                methodCalliSig[arg] = typeof(IntPtr);
                            }
                            else if (methodSig[arg].IsByRef &&
                                     methodSig[arg].GetElementType() == typeof(string))
                            {
                                //Console.WriteLine ("String& param: Method: {0} Param: {1} Type: {2}", mi.Name, arg - argoffset, methodSig[arg]);
                                //if (locals.Count == 0) locals.Add(ilg.DeclareLocal(typeof(int)));
                                //thislocal = locals.Count;
                                //locals.Add(ilg.DeclareLocal(typeof(IntPtr)));
                                //methodCalliSig[arg] = typeof(IntPtr);
                            }
                            else if (methodSig[arg] == typeof(string))
                            {
                                //Console.WriteLine ("String param: Method: {0} Param: {1} Type: {2}", mi.Name, arg - argoffset, methodSig[arg]);
                                if (locals.Count == 0)
                                {
                                    locals.Add(ilg.DeclareLocal(typeof(int)));
                                }

                                thislocal = locals.Count;
                                locals.Add(ilg.DeclareLocal(typeof(IntPtr)));

                                ilg.EmitCall(OpCodes.Call, GetStringMarshalMI(), null);
                                ilg.Emit(OpCodes.Dup);
                                EmitStloc(ilg, thislocal);

                                methodCalliSig[arg] = typeof(IntPtr);
                            }
                            else
                            {
                                methodCalliSig[arg] = methodSig[arg];
                            }
                        }

                        if (isInstanceClass)
                        {
                            // load the instance field
                            ilg.Emit(OpCodes.Ldarg_0);
                            ilg.Emit(OpCodes.Ldfld, addrfield);
                        }
                        else
                        {
                            // just load the static field
                            ilg.Emit(OpCodes.Ldsfld, addrfield);
                        }

                        // emit Tailcall; have the return take place directly to our
                        // caller, but only if we have no marshal'd things to clean up
                        if (locals.Count == 0)
                        {
                            ilg.Emit(OpCodes.Tailcall);
                            methodCalliSig = methodSig;
                        }

                        // The .NET 1.1 runtime doesn't let us emit
                        // CallingConvention.Winapi here, or anything else that
                        // might mean "Use whatever the default platform calling
                        // convention is", like p/invoke can have.
                        //
                        // However, Mono 1.1 /does/ let us emit Winapi/Default,
                        // and both .NET 1.1 and Mono handle this as intended
                        // (stdcall on .NET, cdecl on Mono/Linux).  By my reading
                        // of ECMA-335 (CLI), 22.2.2, this should be allowed, and
                        // I'm not sure why MS's impl doesn't allow it.  However,
                        // the .NET System.Reflection.Emit leaves a lot to be
                        // desired anyway.
                        //
                        // So, the issue is how to emit this.  On WIN32, we simply
                        // create our own SignatureHelper, and munge the internal
                        // signature byte.  Fun, eh?
                        //
                        // ... Except that it doesn't quite work that way. The runtime
                        // gets confused by the calling convention.
                        //
#if !WIN32
                        // Mono?  Just emit normally.
                        ilg.EmitCalli(OpCodes.Calli,
                                      CallingConvention.Winapi,
                                      mi.ReturnType, methodCalliSig);
#else
                        // We're too smart for our own good.  We don't tell win32 how to do stack
                        // cleanup, so it leaves things littering the stack.  So, we can't do this.
                        // GRRRrrr.
#if true
                        ilg.EmitCalli(OpCodes.Calli,
                                      CallingConvention.StdCall,
                                      mi.ReturnType, methodCalliSig);
#else
                        // Win32?  Let the fun begin.
                        if (win32SigField == null)
                        {
                            win32SigField = typeof(SignatureHelper).GetField("m_signature",
                                                                             BindingFlags.Instance |
                                                                             BindingFlags.NonPublic);
                        }

                        SignatureHelper sh = SignatureHelper.GetMethodSigHelper(mbuilder,
                                                                                CallingConvention.StdCall, // lie
                                                                                mi.ReturnType);
                        // munge calling convention; the value in the first byte will be 0x2 for StdCall (1 minus
                        // the CallingConvention enum value).  We set to 0.
                        Array sigArr = win32SigField.GetValue(sh) as Array;
                        sigArr.SetValue((byte)0, 0);
                        // then add the rest of the args.
                        foreach (Type t in methodCalliSig)
                        {
                            sh.AddArgument(t);
                        }
                        ilg.Emit(OpCodes.Calli, sh);
#endif
#endif

                        // clean up our string allocations, if any
                        if (locals.Count > 0)
                        {
                            for (int i = 1; i < locals.Count; i++)
                            {
                                Type ltype = (locals[i] as LocalBuilder).LocalType;
                                if (ltype.IsArray)
                                {
                                    Label looptest = ilg.DefineLabel();
                                    Label loop     = ilg.DefineLabel();

                                    // counter = array.Length
                                    EmitLdloc(ilg, i);
                                    ilg.Emit(OpCodes.Ldlen);
                                    ilg.Emit(OpCodes.Conv_I4);
                                    EmitStloc(ilg, 0);

                                    // goto looptest
                                    ilg.Emit(OpCodes.Br, looptest);

                                    ilg.MarkLabel(loop);

                                    // free(array[counter])
                                    EmitLdloc(ilg, i);
                                    EmitLdloc(ilg, 0);
                                    ilg.Emit(OpCodes.Ldelem_I4);
                                    ilg.EmitCall(OpCodes.Call, GetFreeGlobalMI(), null);

                                    ilg.MarkLabel(looptest);

                                    // p = counter; counter -= 1;
                                    EmitLdloc(ilg, 0);
                                    ilg.Emit(OpCodes.Dup);
                                    ilg.Emit(OpCodes.Ldc_I4_1);
                                    ilg.Emit(OpCodes.Sub);
                                    EmitStloc(ilg, 0);

                                    // if (p > 0) goto loop
                                    ilg.Emit(OpCodes.Ldc_I4_0);
                                    ilg.Emit(OpCodes.Bgt, loop);
                                }
                                else
                                {
                                    // just a simple free, thankfully
                                    EmitLdloc(ilg, i);
                                    ilg.EmitCall(OpCodes.Call, GetFreeGlobalMI(), null);
                                }
                            }
                        }

                        ilg.Emit(OpCodes.Ret);
                    }
                    else
                    {
                        // this is a normal method
                        // this shouldn't happen
                        Console.WriteLine();
                        Console.WriteLine("WARNING: Skipping non-DLL and non-Extension method " + mi.Name);
                    }

                    methodCount++;
                    if (methodCount % 50 == 0)
                    {
                        Console.Write(".");
                    }
                    if (methodCount % 1000 == 0)
                    {
                        Console.Write("[{0}]", methodCount);
                    }
                }
            }

            Console.WriteLine();

            glbuilder.CreateType();

            Console.WriteLine("Type created.");
        }