How can I get around the "ByRef return value not supported when calling reflection" error in C #?

I have a .Net library provided by a third party. I reflected on one of my classes and found a member method. The signature was ...

Byte& FooBar() 

So, I wanted to call this method through reflection and got the exception "Return value ByRef, not supported when calling reflection".

Here is what I tried ...

  var strm = new TheirClass(); var t = strm.GetType(); var ms = t.GetMembers( BindingFlags.Static|BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach (var m in ms) { Debug.WriteLine(String.Format("Name: {0}: {1}", m.Name, m.ToString())); // ... // Name: FooBar: Byte& FooBar() // ... } var meth = t.GetMethod("FooBar"); object returnValue = meth.Invoke(strm, new object[] { }); //throw exception 

I tried to provide parameters, as in calling functions with ref parameters, but that didn't matter.

I would like to get around this exception in C #.

+6
source share
2 answers

In the comments: here's how to do it from CIL, which can be generated with C #.

I was hoping to use DynamicMethod , but I can't get this to work without creating a custom delegate type at runtime, so I needed to use AssemblyBuilder instead.

 using System; using System.Reflection; using System.Reflection.Emit; public delegate void CallBadFunction(Delegate d, Callback c); public delegate void Callback(ref int i); static class Program { static int i; static object BadMethod() { return i; } static MethodInfo GetBadMethod() { return typeof(Program).GetMethod("BadMethod", BindingFlags.Static | BindingFlags.NonPublic); } static void Main() { var badMethod = GetBadMethod(); var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("-"), AssemblyBuilderAccess.Run); var module = assembly.DefineDynamicModule("-"); var badDelegate = module.DefineType("BadDelegateType", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(MulticastDelegate)); var badDelegateCtor = badDelegate.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) }); badDelegateCtor.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); var badDelegateInvoke = badDelegate.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.HideBySig, typeof(int).MakeByRefType(), Type.EmptyTypes); badDelegateInvoke.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); var badDelegateType = badDelegate.CreateType(); var method = module.DefineGlobalMethod("-", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(Delegate), typeof(Callback) }); var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, badDelegate); il.Emit(OpCodes.Callvirt, badDelegateInvoke); il.Emit(OpCodes.Callvirt, typeof(Callback).GetMethod("Invoke")); il.Emit(OpCodes.Ret); module.CreateGlobalFunctions(); var callBadFunction = (CallBadFunction)Delegate.CreateDelegate(typeof(CallBadFunction), module.GetMethod("-")); callBadFunction(badMethod.CreateDelegate(badDelegateType), (ref int i) => { i++; }); } } 

After compiling this program, use ILDASM to disassemble it and replace BadMethod with

 .method private hidebysig static int32& BadMethod() cil managed { ldsflda int32 Program::i ret } 

This turns it into a function that returns int32& , which is followed by the following code. The only place C # allows int32& type is in the function parameters ( ref int ), so to make the result useful, I used a callback function that gets the BadMethod return BadMethod .

+5
source

Thanks, "hvd" for pointing me in the right direction. After some thought, this is what I came up with. It is simpler, but please tell me if you see a flaw.

  var theirObj = new TheirClass(); var t = theirObj.GetType(); var fooBar = t.GetMethod("FooBar"); // Byte& FooBar() DynamicMethod dm = new DynamicMethod( "MyFooBar", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(IntPtr), new Type[] { typeof(TheirClass) }, typeof(TheirClass), true); var ilg = dm.GetILGenerator(); ilg.Emit(OpCodes.Ldarg_0); ilg.Emit(OpCodes.Call, foobar); ilg.Emit(OpCodes.Ret); var del = dm.CreateDelegate(typeof(Func<TheirClass,IntPtr>)); var ret = (IntPtr)del.DynamicInvoke(theirObject); byte[] buf = new byte[theirObj.FooBarSize()]; //no need for reflection/IL here // not sure about the following, it works, but should it be inside an "unsafe" section? Marshal.Copy(ret, buf, 0, buf.Length); 

I put a simple wrapper around the insult method, and IL doesn't care that I treat Byte & as IntPtr. I'm still not sure that you are making a copy without a dangerous shell. But now it’s good.

0
source

All Articles