none
Passing parameters from C++ to C# RRS feed

  • Question

  • I have this signature provided by unmanaged C++ dll:

    bool resolve (int code, double& result);

    I call this method from C# using reflection. Both the bool "return" and double "result" values are further required in the C# program. My question is: how to access the value of "result" in my C# program, in code please.

    Thanks

     

    Wednesday, January 16, 2013 2:36 AM

Answers

  • Uncommenting the lines wouldn't be enough. You need to check the actual output of the function. As they are:
    ac.Exec("resolve", new Object[]{100, 123, null});
    Console.WriteLine("Ret Value: " + args[2]);
    those lines pass a temporary array to the function, and then check an unrelated array which has not been changed, of course.
    Thursday, January 17, 2013 12:22 PM

All replies

  • I have this signature provided by unmanaged C++ dll:

    bool resolve (int code, double& result);

    I call this method from C# using reflection. Both the bool "return" and double "result" values are further required in the C# program. My question is: how to access the value of "result" in my C# program, in code please.

    Thanks

    Wednesday, January 16, 2013 7:15 AM
  • I didn't read the question correctly. You didn't explain how is reflection and unmanaged C++ mixed in your program. Could you show the code you tried?

    Here is an example of passing an out parameter to a reflected method call:

    bool solved;
    int code = 42;
    double result;
    
    object[] parameters = new object[] { code, null };
    
    MethodInfo method = /* some code to retrieve the method */
    
    solved = (bool)method.Invoke(parameters);
    result = (double)parameters[1];

    Wednesday, January 16, 2013 7:55 AM
  • Thanks again.

    Here is how my source looks like:

    C++ side:

    double somevar = 100;

    bool resolve(int code, double& result) { somevar += 10; result = somevar; return true;}

    C# Side:

    interface IClient { void Exec(string name, Object[] args); } // args: are parameters needed to call a dynamic C# method.

    class SomeClass { // in this class, I create a dynamic assembly and adynamic Exec method.

    // create assembly code

    // create module

    // create type (dClass) that inherits from IClient above

    // Create dynamic method Exec (exec) that overrides the method provided by IClient

    // Get an IGenerator (iGen) for Exec method

    // Here is the difficult bit: create a dynamic method targeting a method provided by C++ dll

    // The C++ method signature is bool resolve(int code, double& result)

    MethodBuilder xMethod = module.DefinePInvokeMethod(name, dll_name, ...);

    // set the second parameter of xMethod as an OUT parameter

    ParameterBuilder outParam = xMethod.DefineParameter(1, ParameterAttributes.Out, "someName");

    // Prepare for invoking xMethod: emit OpCodes that pass values for code and initial zero for result

    iGen = EmitCall(OpCodes.Call, xMethod, args);

    //========================================

    // Here where I should read result after "resolve" method has been invoked. 

    // the question is: How to get the value of the parameter "result" after 

    // the method has been invoked. Please notice that the dll is  a 3rd party binary.

    // I use the 2nd Exec method parameter to return the "result" to the caller of "SomeClass"

    //========================================

    // Create the Exec dynamic method

    module.CreateGlobalFunctions();

    // return the xMethod 

    iGen.Emit(OpCodes.Ret);

    // Get info about Exec 

    MethodInfo execInfo = typeof(IClient).GetMethod("Exec");

    dClass.DefineMethodOverride(exec, execInfo );

    // create the type

    tc = dClass.CreateType();

    // the rest of the class

    } // end of class "SomeClass"

    Wednesday, January 16, 2013 10:20 AM
  • Here is the c# code

            static void Main(string[] args)
            {
                int code = 123;
                double results = -1;
                bool status = resolve (code, ref results);
            }
            static bool resolve(int code, ref double results)
            {
                bool status = true;
                results = 456.789;
                return status;
            }


    jdweng

    Wednesday, January 16, 2013 10:59 AM
  • Thanks.

    This is not what my question is about and I am sorry if I wasn't clear enough. The resolve method is emitted dynamically using reflection. The resolve method calls an external method (provided by a dll). If you are interested, you may follow my thread at here.

    Wednesday, January 16, 2013 12:42 PM
  • Here is some code to generate a class implementing IClient. Its Exec method calls the named function. If you have questions, just ask.
    AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("dyn"), AssemblyBuilderAccess.Run);
    var module = asm.DefineDynamicModule("dyn");
    TypeBuilder dClass = module.DefineType("dyn");
    dClass.AddInterfaceImplementation(typeof(IClient));
    var exec = dClass.DefineMethod("Exec", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[]{typeof(string),typeof(object[])});
    var iGen = exec.GetILGenerator();
    MethodBuilder xMethod = module.DefinePInvokeMethod(name, "dllname.dll", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(bool), new[] { typeof(int), typeof(double).MakeByRefType()}, CallingConvention.Cdecl, CharSet.Ansi);
    iGen.DeclareLocal(typeof(double));
    iGen.Emit(OpCodes.Ldarg_2);
    iGen.Emit(OpCodes.Ldc_I4_0);
    iGen.Emit(OpCodes.Ldelem_Ref);
    iGen.Emit(OpCodes.Unbox_Any, typeof(int));
    iGen.Emit(OpCodes.Ldloca, 0); // Here I pass a local variable byref
    iGen.EmitCall(OpCodes.Call, xMethod, null);
    iGen.Emit(OpCodes.Ldarg_2);
    iGen.Emit(OpCodes.Ldc_I4_1);
    iGen.Emit(OpCodes.Ldloc_0);
    iGen.Emit(OpCodes.Box, typeof(double));
    iGen.Emit(OpCodes.Stelem_Ref); // And I store the local variable value in the args array
    module.CreateGlobalFunctions();
    iGen.Emit(OpCodes.Pop);
    iGen.Emit(OpCodes.Ret);
    var tc = dClass.CreateType();
    IClient c = (IClient)Activator.CreateInstance(tc);
    c.Exec("resolve", args);

    Wednesday, January 16, 2013 3:40 PM
  • Thank you Louis. I tested the code against the method resolve, but it didn't work. The second element in the parameter args is still null after invoking resolve. It doesn't seem that the local variable returned the current result value. I attach below the code as tested. 

    using System;
    using System.Runtime.InteropServices;
    using System.Reflection.Emit;
    using System.Reflection;
    using System.Threading;
    
    namespace myspace
    {
    	public interface IClient
    	{
    		void Exec(string name, Object[] args);
    	}
    	partial class SomeClass : IClient
    	{
    		public void Exec(string name,  Object[] args)
    		{
    			AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(
    				new AssemblyName("dyn"), AssemblyBuilderAccess.Run);
    			var module = asm.DefineDynamicModule("dyn");
    			TypeBuilder dClass = module.DefineType("dyn");
    			dClass.AddInterfaceImplementation(typeof(IClient));
    			var exec = dClass.DefineMethod("Exec", 
    				MethodAttributes.Public | 
    				MethodAttributes.Virtual, 
    				typeof(void), new[]{typeof(string),typeof(object[])});
    			var iGen = exec.GetILGenerator();
    			MethodBuilder xMethod = module.DefinePInvokeMethod("Deposit", 
    				"myhook.dll", 
    				MethodAttributes.Public | 
    				MethodAttributes.Static, 
    				CallingConventions.Standard, 
    				typeof(bool), new[] { typeof(int), typeof(double).MakeByRefType()}, 
    				CallingConvention.Cdecl, CharSet.Ansi);
    			iGen.DeclareLocal(typeof(double));
    			iGen.Emit(OpCodes.Ldarg_2);
    			iGen.Emit(OpCodes.Ldc_I4_0);
    			iGen.Emit(OpCodes.Ldelem_Ref);
    			iGen.Emit(OpCodes.Unbox_Any, typeof(int));
    			iGen.Emit(OpCodes.Ldloca, 0); // Here I pass a local variable byref
    			iGen.EmitCall(OpCodes.Call, xMethod, null);
    			iGen.Emit(OpCodes.Ldarg_2);
    			iGen.Emit(OpCodes.Ldc_I4_1);
    			iGen.Emit(OpCodes.Ldloc_0);
    			iGen.Emit(OpCodes.Box, typeof(double));
    			iGen.Emit(OpCodes.Stelem_Ref); // And I store the local variable value in the args array
    			module.CreateGlobalFunctions();
    			iGen.Emit(OpCodes.Pop);
    			iGen.Emit(OpCodes.Ret);
    			var tc = dClass.CreateType();
    			IClient c = (IClient)Activator.CreateInstance(tc);
    			//c.Exec("resolve", new Object[]{100, null});
    			Console.WriteLine("Ret Value: " + args[1]);
    		}
    		public static void Main(string[] args)
    		{
    			SomeClass c = new SomeClass();
    			c.Exec("resolve", new Object[]{100, null});
    
    		}
    	}
    }

    I hope there is a way around this?

    Wednesday, January 16, 2013 8:48 PM
  • A better test together with the error message is listed below:

    /*
        Unhandled Exception: System.TypeLoadException: Method 'Exec' in type 'dyn' from
        assembly 'dyn, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
        at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, I
        nt32 tk, ObjectHandleOnStack type)
        at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
        at System.Reflection.Emit.TypeBuilder.CreateType()
        at myspace.SomeClass.CreateHook()
        at myspace.SomeClass.Main(String[] args)
       
        Please notice that the "bool resolve(int, double&)" --> "void Deposit(int, int, int&)"
     */
    
    using System;
    using System.Runtime.InteropServices;
    using System.Reflection.Emit;
    using System.Reflection;
    
    
    namespace myspace
    {
    	public interface IClient
    	{
    		void Exec(string name, ref Object[] args);
    	}
    	partial class SomeClass
    	{
            public IClient CreateHook()
    		{
    			AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(
    				new AssemblyName("dyn"), AssemblyBuilderAccess.Run);
    			var module = asm.DefineDynamicModule("dyn");
    			TypeBuilder dClass = module.DefineType("dyn");
    			dClass.AddInterfaceImplementation(typeof(IClient));
    			var exec = dClass.DefineMethod("Exec", 
    				MethodAttributes.Public | 
    				MethodAttributes.Virtual, 
    				typeof(void), new[]{typeof(string),typeof(object[])});
    			var iGen = exec.GetILGenerator();
    			MethodBuilder xMethod = module.DefinePInvokeMethod("Deposit", 
    				"bank.dll", 
    				MethodAttributes.Public | 
    				MethodAttributes.Static, 
    				CallingConventions.Standard, 
    				null, new[] { typeof(int), typeof(int), typeof(int).MakeByRefType()}, 
    				CallingConvention.Cdecl, CharSet.Ansi);
    			iGen.DeclareLocal(typeof(int));
    			
                iGen.Emit(OpCodes.Ldarg_2);
    			iGen.Emit(OpCodes.Ldc_I4_0);
    			iGen.Emit(OpCodes.Ldelem_Ref);
    			iGen.Emit(OpCodes.Unbox_Any, typeof(int));
    
                iGen.Emit(OpCodes.Ldarg_2);
                iGen.Emit(OpCodes.Ldc_I4_1);
                iGen.Emit(OpCodes.Ldelem_Ref);
                iGen.Emit(OpCodes.Unbox_Any, typeof(int));
    
    			iGen.Emit(OpCodes.Ldloca, 0); // Here I pass a local variable byref
    			iGen.EmitCall(OpCodes.Call, xMethod, null);
    			iGen.Emit(OpCodes.Ldarg_2);
    			iGen.Emit(OpCodes.Ldc_I4_2);
    			iGen.Emit(OpCodes.Ldloc_0);
    			iGen.Emit(OpCodes.Box, typeof(int));
                iGen.Emit(OpCodes.Stelem_Ref); // And I store the local variable value in the args array
    			
                module.CreateGlobalFunctions();
    
    			iGen.Emit(OpCodes.Pop);
    			iGen.Emit(OpCodes.Ret);
    			var tc = dClass.CreateType();
    			//IClient c = 
                return (IClient)Activator.CreateInstance(tc);
    			//ac.Exec("resolve", new Object[]{100, 123, null});
    			//Console.WriteLine("Ret Value: " + args[2]);
    		}
    		public static void Main(string[] args)
    		{
    			SomeClass c = new SomeClass();
                IClient link = c.CreateHook();
                Object[] obj = { 100, 123, null };
                link.Exec("Deposit", ref obj);
    
    		}
    	}
    }


    Thursday, January 17, 2013 7:27 AM
  • How did you test it? The only output you have is commented, and if you uncomment it you are passing a new temporary array to the Exec method and checking the args. Of course Exec won't change args.

    The error is because you changed the interface's Exec method signature. Either remove the ref from the signature (since it doesn't look to have any purpose) or change the dynamic method's signature.

    Thursday, January 17, 2013 7:46 AM
  • In both tests, there where no commented lines.  Furthermore, I tried the code before and after changing the signature of Exec. I will be removing the "ref" in Exec signature and see how it goes.

    Thanks


    • Edited by DLL Exports Thursday, January 17, 2013 11:06 AM
    Thursday, January 17, 2013 11:05 AM
  • Uncommenting the lines wouldn't be enough. You need to check the actual output of the function. As they are:
    ac.Exec("resolve", new Object[]{100, 123, null});
    Console.WriteLine("Ret Value: " + args[2]);
    those lines pass a temporary array to the function, and then check an unrelated array which has not been changed, of course.
    Thursday, January 17, 2013 12:22 PM
  • Many thanks Louis.

    I have properly tested your code which worked as intended. I would be grateful if you can recommend some readings about C# reflection. I need to build code that invokes methods provided by dlls with any parameter/return types.

    Thanks again

    Thursday, January 17, 2013 3:30 PM
  • To better understand IL, you can write methods in C# and look at the generated IL code.

    Some things to read:

    - ECMA-335 (CLI Specification), notably partition III (CIL Instruction Set)

    - Introduction to MSIL by Kenny Kerr (look for December 2004 articles)


    • Edited by Louis.fr Monday, January 21, 2013 8:50 AM
    Monday, January 21, 2013 8:49 AM