private MethodIL EmitIL() { // We have 4 code streams: // - _marshallingCodeStream is used to convert each argument into a native type and // store that into the local // - callsiteSetupCodeStream is used to used to load each previously generated local // and call the actual target native method. // - _returnValueMarshallingCodeStream is used to convert the native return value // to managed one. // - _unmarshallingCodestream is used to propagate [out] native arguments values to // managed ones. ILEmitter emitter = new ILEmitter(); ILCodeStream fnptrLoadStream = emitter.NewCodeStream(); ILCodeStream marshallingCodeStream = emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = emitter.NewCodeStream(); ILCodeStream returnValueMarshallingCodeStream = emitter.NewCodeStream(); ILCodeStream unmarshallingCodestream = emitter.NewCodeStream(); // Marshal the arguments for (int i = 0; i < _marshallers.Length; i++) { Marshaller marshaller = _marshallers[i]; marshaller.EmitMarshallingIL(emitter, marshallingCodeStream, callsiteSetupCodeStream, unmarshallingCodestream, returnValueMarshallingCodeStream); } // make the call TypeDesc nativeReturnType = _marshallers[0].NativeType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeType; } MethodDesc targetMethod = _methodData.TargetMethod; PInvokeMetadata importMetadata = _methodData.ImportMetadata; PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration = _methodData.PInvokeILEmitterConfiguration; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( _methodData.PInvokeMarshal.GetKnownMethod("ClearLastWin32Error", null))); } if (MarshalHelpers.UseLazyResolution(targetMethod, importMetadata.Module, pinvokeILEmitterConfiguration)) { MetadataType lazyHelperType = targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField((DefType)targetMethod.OwningType, importMetadata); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(importMetadata.Attributes); MethodSignature nativeCalliSig = new MethodSignature( targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeCalliSig)); } else { // Eager call PInvokeMetadata nativeImportMetadata = new PInvokeMetadata(importMetadata.Module, importMetadata.Name ?? targetMethod.Name, importMetadata.Attributes); MethodSignature nativeSig = new MethodSignature( targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(targetMethod.OwningType, nativeSig, nativeImportMetadata, pinvokeILEmitterConfiguration.GetNextNativeMethodId()); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later // by calling PInvokeMarshal.GetLastWin32Error if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( _methodData.PInvokeMarshal.GetKnownMethod("SaveLastWin32Error", null))); } unmarshallingCodestream.Emit(ILOpcode.ret); return(emitter.Link(targetMethod)); }