public static Type CreateWrapper <T>(IntPtr Instance, out NativeClassInfo NativeCInfo) where T : class { NativeCInfo = null; string WrapperName = typeof(T).Name + "_impl"; if (NativeClassWrappers.ContainsKey(WrapperName)) { return(NativeClassWrappers[WrapperName]); } NativeClassInfo NativeInfo = NativeCInfo = NativeClass.CalculateClassLayout(typeof(T)); Type TypeWrapper = CreateInterfaceImpl <T>(WrapperName, (TB) => { foreach (var VarInf in NativeInfo.VariableInfo) { CreateVariableImpl(TB, VarInf.PropertyInfo, VarInf.Offset); } foreach (var MetInf in NativeInfo.MethodInfo) { if (MetInf.DoesOverride) { continue; } CreateMethodImpl(TB, MetInf.Method, (MB, ILGen, ParamTypes) => { ILGen.Emit(OpCodes.Ldarg_0); ILGen.Emit(OpCodes.Ldc_I4, MetInf.ThisOffset); ILGen.EmitCall(OpCodes.Call, TB.BaseType.GetMethod(nameof(NativeClassImpl.OffsetThisPtr)), null); for (int i = 0; i < ParamTypes.Length; i++) { ILGen.Emit(OpCodes.Ldarg, i + 1); } ILGen.Emit(OpCodes.Ldarg_0); ILGen.Emit(OpCodes.Ldc_I4, MetInf.VTableOffset); ILGen.Emit(OpCodes.Ldc_I4, MetInf.MethodIndex); ILGen.EmitCall(OpCodes.Call, TB.BaseType.GetMethod(nameof(NativeClassImpl.GetMethodPointer)), null); ILGen.EmitCalli(OpCodes.Calli, CallingConvention.ThisCall, MetInf.Method.ReturnType, new Type[] { typeof(IntPtr) }.Append(ParamTypes)); ILGen.Emit(OpCodes.Ret); }); } }); NativeClassWrappers.Add(WrapperName, TypeWrapper); return(TypeWrapper); }
public static NativeClassInfo CalculateClassLayout(Type T) { List <NativeMethodInfo> MethodInfos = new List <NativeMethodInfo>(); List <NativeVariableInfo> VariableInfos = new List <NativeVariableInfo>(); Dictionary <int, int> MethodCounter = new Dictionary <int, int>(); Dictionary <int, int> VariableOffsets = new Dictionary <int, int>(); CalculateVTableLayout(T, (VTableOffset, Interface) => { MethodInfo[] Methods = Interface.GetMethods(); if (!MethodCounter.ContainsKey(VTableOffset)) { MethodCounter.Add(VTableOffset, 0); VariableOffsets.Add(VTableOffset, VTablePointerSize); } for (int i = 0; i < Methods.Length; i++) { PropertyInfo Prop; if ((Prop = GetPropertyForMethod(Methods[i])) != null) { if (Prop.GetSetMethod() == Methods[i]) { continue; } NativeVariableInfo VarInfo = new NativeVariableInfo(); VarInfo.Offset = VariableOffsets[VTableOffset]; VarInfo.PropertyInfo = Prop; VarInfo.VariableType = VarInfo.PropertyInfo.PropertyType; VarInfo.Name = VarInfo.PropertyInfo.Name; VariableOffsets[VTableOffset] += Marshal.SizeOf(VarInfo.VariableType); VariableInfos.Add(VarInfo); continue; } NativeMethodInfo VMethInfo = new NativeMethodInfo(); VMethInfo.Method = Methods[i]; MethodInfo BMI; if (BaseContains(Methods[i], out BMI)) { VMethInfo.BaseMethod = BMI; VMethInfo.DoesOverride = true; } else { VMethInfo.BaseMethod = null; VMethInfo.MethodIndex = MethodCounter[VTableOffset]++; VMethInfo.VTableOffset = VTableOffset; VMethInfo.DoesOverride = false; } MethodInfos.Add(VMethInfo); } }); NativeClassInfo Ret = new NativeClassInfo(); Ret.MethodInfo.AddRange(MethodInfos); Ret.VariableInfo.AddRange(VariableInfos); return(Ret); }