private static Type CreateDelegateTypeForNativeFunctionSignature(NativeFunctionSignature functionSignature, string functionName) { if (_customDelegateTypesModule == null) { var aName = new AssemblyName("HelperRuntimeDelegates"); var delegateTypesAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave); _customDelegateTypesModule = delegateTypesAssembly.DefineDynamicModule(aName.Name, aName.Name + ".dll"); } var delBuilder = _customDelegateTypesModule.DefineType("HelperNativeDelegate" + _createdDelegateTypes.ToString(), TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(MulticastDelegate)); //ufp = UnmanagedFunctionPointer object[] ufpAttrCtorArgValues = { functionSignature.callingConvention }; FieldInfo[] ufpAttrNamedFields = { Field_Ufpa_BestFitMapping.Value, Field_Ufpa_CharSet.Value, Field_Ufpa_SetLastError.Value, Field_Ufpa_ThrowOnUnmappableChar.Value }; object[] ufpAttrFieldValues = { functionSignature.bestFitMapping, functionSignature.charSet, functionSignature.setLastError, functionSignature.throwOnUnmappableChar }; var ufpAttrBuilder = new CustomAttributeBuilder(Ctor_Ufp.Value, ufpAttrCtorArgValues, ufpAttrNamedFields, ufpAttrFieldValues); delBuilder.SetCustomAttribute(ufpAttrBuilder); var ctorBuilder = delBuilder.DefineConstructor(MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, CallingConventions.Standard, DELEGATE_CTOR_PARAMETERS); ctorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); var invokeBuilder = delBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot, CallingConventions.Standard | CallingConventions.HasThis, functionSignature.returnParameter.type, functionSignature.parameters.Select(p => p.type).ToArray()); invokeBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); var invokeReturnParam = invokeBuilder.DefineParameter(0, functionSignature.returnParameter.parameterAttributes, null); foreach (var attr in functionSignature.returnParameter.customAttributes) { var attrBuilder = CreateAttributeBuilderFromAttributeInstance(attr, functionName); if (attrBuilder != null) { invokeReturnParam.SetCustomAttribute(attrBuilder); } } for (int i = 0; i < functionSignature.parameters.Length; i++) { var param = functionSignature.parameters[i]; var paramBuilder = invokeBuilder.DefineParameter(i + 1, param.parameterAttributes, null); foreach (var attr in param.customAttributes) { var attrBuilder = CreateAttributeBuilderFromAttributeInstance(attr, functionName); if (attrBuilder != null) { paramBuilder.SetCustomAttribute(attrBuilder); } } } _createdDelegateTypes++; return(delBuilder.CreateType()); }
/// <summary> /// Creates and registers new DynamicMethod that mocks <paramref name="nativeMethod"/> and itself calls dynamically loaded function from DLL. /// </summary> private static DynamicMethod GetNativeFunctionMockMethod(MethodInfo nativeMethod) { if (!_nativeFunctionMocks.TryGetValue(nativeMethod, out var mockedDynamicMethod)) { var dllImportAttr = nativeMethod.GetCustomAttribute <DllImportAttribute>(); var dllName = dllImportAttr.Value; string dllPath; var nativeFunctionSymbol = dllImportAttr.EntryPoint; if (_dlls.TryGetValue(dllName, out var dll)) { dllPath = dll.path; } else { dllPath = ApplyDirectoryPathMacros(Options.dllPathPattern).Replace(DLL_PATH_PATTERN_DLL_NAME_MACRO, dllName); dll = new NativeDll(dllName, dllPath); _dlls.Add(dllName, dll); } var nativeFunction = new NativeFunction(nativeFunctionSymbol, dll); dll.functions.Add(nativeFunction); var nativeFunctionIndex = _mockedNativeFunctions.Count; _mockedNativeFunctions.Add(nativeFunction); var parameters = nativeMethod.GetParameters(); var parameterTypes = parameters.Select(x => x.ParameterType).ToArray(); var nativeMethodSignature = new NativeFunctionSignature(nativeMethod, dllImportAttr.CallingConvention, dllImportAttr.BestFitMapping, dllImportAttr.CharSet, dllImportAttr.SetLastError, dllImportAttr.ThrowOnUnmappableChar); if (!_delegateTypesForNativeFunctionSignatures.TryGetValue(nativeMethodSignature, out nativeFunction.delegateType)) { nativeFunction.delegateType = CreateDelegateTypeForNativeFunctionSignature(nativeMethodSignature, nativeMethod.Name); _delegateTypesForNativeFunctionSignatures.Add(nativeMethodSignature, nativeFunction.delegateType); } var targetDelegateInvokeMethod = nativeFunction.delegateType.GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public); mockedDynamicMethod = new DynamicMethod(dllName + ":::" + nativeFunctionSymbol, nativeMethod.ReturnType, parameterTypes, typeof(DllManipulator)); mockedDynamicMethod.DefineParameter(0, nativeMethod.ReturnParameter.Attributes, null); for (int i = 0; i < parameters.Length; i++) { mockedDynamicMethod.DefineParameter(i + 1, parameters[i].Attributes, null); } GenerateNativeFunctionMockBody(mockedDynamicMethod.GetILGenerator(), parameters, targetDelegateInvokeMethod, nativeFunctionIndex); _antiGcRefHolder.AddLast(nativeFunction); _antiGcRefHolder.AddLast(mockedDynamicMethod); } return(mockedDynamicMethod); }