CLR Host - how to execute functions with arbitrary method signature - c#

I've a managed C# test DLL and I want to call its functions from my unmanaged C++ code.
The problem is that I can't find an example that shows how to call arbitrary functions from my c++ code, I could only get the ICLRRuntimeHost::ExecuteInDefaultAppDomain working, but this function does use a predefined method signature.
Question
I'm able to execuete the ShowMsg function from my C# DLL but I can't find out how to call methods with other signatures than int(int). Can someone please help me with that?
C++ Code
// interface definitions of functions from c# dll
typedef int (*TestCallbackPtr)(std::wstring info, int value1, double value2);
typedef int (*TestFunctionPtr)(std::wstring string1, int int1, double double1, TestCallbackPtr callback);
// path of my c# dll
auto pathDll = L"..."
void RunTest()
{
ICLRMetaHost* clrMetaHost = NULL;
ICLRRuntimeInfo* clrRuntimeInfo = NULL;
ICLRRuntimeHost* clrRuntimeHost = NULL;
// loading the data above is excluded for simplicity!
// ...
// -------------
// Test 1: run ShowMsg => WORKING
// -------------
DWORD pReturnValue;
HRESULT result = clrRuntimeHost->ExecuteInDefaultAppDomain(pathDll, L"Test.Managed", L"ShowMsg", L"Hello from C++", &pReturnValue);
// -------------
// Test 2: run TestFunction
// -------------
TestCallbackPtr callback = [](std::wstring info, int value1, double value2) {
return 21;
};
TestFunctionPtr function = NULL;
// how to continue? how can I execute the function here and assign my local function pointer so that following will work:
// (*function)(L"Test", 45, 1.23, callback);
}
C# Code
namespace Test
{
public class Managed
{
public static int ShowMsg(string msg)
{
MessageBox.Show(msg);
return 0;
}
public delegate int TestCallback([MarshalAs(UnmanagedType.LPWStr)] string info, int value1, double value2);
public static int TestFunction(
[MarshalAs(UnmanagedType.LPWStr)] string string1,
int int1,
double double1,
TestCallback callback)
{
string info = $"string1 = {string1} | int1 = {int1} | double1 = {double1}";
int returnValue = callback(info, 5, 10.34);
return returnValue;
}
}
}

Related

'ShowSUM': __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention

I have a C# DLL with the following code:
namespace Csharplib`{
public class Calculate
{
public static int Sum(String value1, String value2)
{
int res = int.Parse(value1) + int.Parse(value2);
return res;
}
}
}`
I have a CLI/CLR C++ Application where I have added the reference of my C# DLL. Following is the code of my CLI/CLR C++ Application:
using namespace System;
using namespace System::Reflection;
namespace CplusManaged {
public ref class DoWork
{
public:int DoSum(System::String ^value1, System::String ^value2)
{
return Csharplib::Calculate::Sum(value1, value2);
}
};
}
__declspec(dllexport) int ShowSUM(System::String ^value1, System::String ^value2)`{
CplusManaged::DoWork work;
return work.DoSum(value1,value2);
}`
When I build my application, I get the following error:
'ShowSUM': __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention
I am a C# developer and I have no experience in C++ whatsoever. Is there any way I can solve this problem?
Use wchar_t* as parameter type, and convert to String ^ using gcnew String() like this:
__declspec(dllexport) int ShowSUM(wchar_t * inValue1, wchar_t * inValue2)
{
String ^ value1 = gcnew String(inValue1);
String ^ value2 = gcnew String(inValue2);
CplusManaged::DoWork work;
return work.DoSum(value1, value2);
}

Reference to var c#

I wonder if there is a way to use a reference of a var like 'ref' but not in a method.
exemple :
using System;
using System.Collections;
using System.Collections.Generic;
public class Class3
{
struct myStruct
{
public bool structBool;
public int structInt;
public myStruct(bool _structBool, int _structInt)
{
structBool = _structBool;
structInt = _structInt;
}
}
myStruct currentTask;
int value1,value2;
bool mybool, isProcessing;
Queue<myStruct> myTask = new Queue<myStruct>();
void main()
{
//these two lines don't work due to the "ref" but I'm looking for something work like this
if (value1 > value2) myTask.Enqueue(new myStruct(mybool,ref value1));
if (value2 > value1) myTask.Enqueue(new myStruct(mybool,ref value2));
MyFunction();
}
void MyFunction()
{
if (myTask.Count > 0)
{
if (!isProcessing)
{
currentTask = myTask.Dequeue();
isProcessing = true;
}
else
{
currentTask.structInt++; // here I need to catch my var (value1 or value2)
}
}
}
}
I tried to put the values into an array but I think it's a bad way. I tried lot of other stuff but nothing work properly.
You can change the constructor to pass those parameters by reference like so:
public myStruct(bool _structBool, ref int _structInt),
The problem is that invoking this line
currentTask.structInt++;
still wouldn't change the original variables (value1, value2). Check the solution in the answer here: https://stackoverflow.com/a/13120988/775018
Usually when you want to give multiple values to a constructor (or even a method), it's very acceptable that you give them as part of a class:
public class Args
{
public int Value { get; set; }
}
So now you can do this:
Args args1 = new Args { Value = 10 };
Args args2 = new Args { Value = 34 };
// Obviously, your structs or classes should accept Args class as input parameter
var struct1 = new MyStruct(true, args1);
var struct2 = new MyStruct(false, args2);
Now modifications to Args.Value1 and/or Args.Value2 will be available for the struct constructor callers.

How to debug theories in xunit tests

I have big amount of similar tests which I implement as a theory using MemberData attribute. How can I navigate to each fallen test case and debug it?
Here an example:
public const int A = 2;
public const int B = 3;
public const int C = 2;
public static IEnumerable<object[]> GetTestCases
{
get
{
// 1st test case
yield return new object[]
{
A, B, 4
};
// 2nd test case
yield return new object[]
{
A, C, 4
};
}
}
[Theory]
[MemberData("GetTestCases")]
public void TestMethod1(int operand1, int operand2, int expected)
{
// Q: How can I debug only test case, which is failed?
//...and break execution before exception will be raised
var actual = operand1 + operand2;
Assert.Equal(actual, expected);
}
Well, you can set conditional breakpoint in TestMethod1 and try to find fallen test case. But in many cases it is not so comfortable.
One trick can be helpful here:
public const int A = 2;
public const int B = 3;
public const int C = 2;
public static IEnumerable<object[]> GetTestCases
{
get
{
// 1st test case
// This line will be in stack trace if this test will failed
// So you can navigate from Test Explorer directly from StackTrace.
// Also, you can debug only this test case, by setting a break point in lambda body - 'l()'
Action<Action> runLambda = l => l();
yield return new object[]
{
A, B, 4,
runLambda
};
// 2nd test case
runLambda = l => l();
yield return new object[]
{
A, C, 4,
runLambda
};
// ...other 100500 test cases...
}
}
[Theory]
[MemberData("GetTestCases")]
public void TestMethod1(int operand1, int operand2, int expected, Action<Action> runLambda)
{
// pass whole assertions in a callback
runLambda(() =>
{
var actual = operand1 + operand2;
Assert.Equal(actual, expected);
});
}
Idea is to put target logic and assertions into callback and call it through a special similar lambdas which are injected in each test case. Every of that lambdas will be passed as argument and called in test method, so it will be present in stack trace. And when some test case will fall, you can easily navigate to it through StackTrace by clicking on corresponding line (in this example it will looks like 'at UnitTestProject1.ExampleTests2.<>c.b__4_0(Action l)')
Also, you can set breakpoint inside lambda of that test case, which you want to debug and see what is happen with data.

With SWIG, how do you wrap C++ void func(Class& out) as C# Class func()?

(Unfortunately, SWIG's documentation is very difficult to parse and online examples seem rare. So I come here.)
Suppose a C++ function uses this typical return style for a class type:
void func(Class& out);
Using SWIG, this function should be wrapped in C# like this:
Class func();
From what I've found, I can use a typemap to accomplish this.
Pretending that Class is actually int, I've attempted the following based on examples I've found:
%include <typemaps.i>
%{
void func(int& pOut);
%}
%apply int &OUTPUT { int &pOut }
void func(int& pOut);
Many examples (leaning toward Python, though) suggest that this should create a function with no parameters that outputs an int.
However, I've used the following commandline:
swig.exe -namespace Test -o .\Test.cxx -c++ -module Test -csharp -outdir . test.i
This output the following Test.cs:
namespace Test {
using System;
using System.Runtime.InteropServices;
public class Test {
public static void func(out int pOut) {
TestPINVOKE.func(out pOut);
}
}
}
How can I achieve the function signature I want, and how do I transfer this to an object type?
Looks like I've found a way to do this specifically in C#, although it should be extendable to other languages.
Consider this SWIG interface, where I've added additional arguments for dramatic effect:
%include <typemaps.i>
%{
class MyClass{};
void func(MyClass& pOut, int x);
MyClass* func2(int x);
%}
%typemap(ctype, out="void *") void func ""
%typemap(imtype, out="global::System.IntPtr") void func ""
%typemap(cstype, out="MyClass") void func ""
%typemap(in, numinputs=0, noblock=1) MyClass &pOut
{
$1 = new MyClass();
}
%typemap(argout, noblock=1) MyClass &pOut
{
$result = $1;
}
%typemap(csout, excode=SWIGEXCODE) void func
{
IntPtr cPtr = $imcall;$excode
MyClass ret = (cPtr != IntPtr.Zero) ? null : new MyClass(cPtr, $owner);
return ret;
}
class MyClass{};
void func(MyClass& pOut, int x);
MyClass* func2(int x);
I've included func2 with the proper signature as well.
The first 3 %typemaps change the return type of the C++ wrapper function, C# interop method, and the C# wrapper method respectively.
The %typemap(in) removes the extraneous output parameter and adds code to use a new object in its place. This also, miraculously, leaves other arguments intact.
The %typemap(argout) uses the output parameter value as the newly created return value.
The %typemap(csout) rewrites the C# wrapper method code to utilize the return value of the interop method just like in the normal case.
Here are the example outputs proving it works like a charm:
Test.cxx
SWIGEXPORT void * SWIGSTDCALL CSharp_func(int jarg2) {
void * jresult ;
MyClass *arg1 = 0 ;
int arg2 ;
arg1 = new MyClass();
arg2 = (int)jarg2;
func(*arg1,arg2);
jresult = arg1;
return jresult;
}
SWIGEXPORT void * SWIGSTDCALL CSharp_func2(int jarg1) {
void * jresult ;
int arg1 ;
MyClass *result = 0 ;
arg1 = (int)jarg1;
result = (MyClass *)func2(arg1);
jresult = (void *)result;
return jresult;
}
TestPINVOKE.cs
[DllImport("Test", EntryPoint="CSharp_func")]
public static extern global::System.IntPtr func(int jarg2);
[DllImport("Test", EntryPoint="CSharp_func2")]
public static extern IntPtr func2(int jarg1);
Test.cs
public class Test {
public static MyClass func(int x) {
IntPtr cPtr = TestPINVOKE.func(x);
MyClass ret = (cPtr != IntPtr.Zero) ? null : new MyClass(cPtr, false);
return ret;
}
public static MyClass func2(int x) {
IntPtr cPtr = TestPINVOKE.func2(x);
MyClass ret = (cPtr == IntPtr.Zero) ? null : new MyClass(cPtr, false);
return ret;
}
}
The C#-specific %typemaps would need to be replaced with other language-specific ones to use with other languages, but alas I found no language-agnostic way to do it.
To make this work easily with multiple types and functions, a macro could be defined.

add Mono internal call where a string is passed by reference

I'm trying to create a method using mono where a string is passed by reference,
here is the test code I have:
C++:
static bool p_TestMethod(int num, MonoString ** response) {
auto b = mono_string_new(mono_domain_get(), "Test repsonse");
response = &b;
return true;
}
//...
mono_add_internal_call("SharpCode.TestClass::Testmethod", p_TestMethod);
C#:
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern bool Testmethod(int num, out string response);
public bool RunTheTest()
{
string x;
Testmethod(0, out x);
Console.WriteLine("Test: {0}", x);
return true;
}
But no response is printed (only Test: )
How do I properly pass a string by reference using Mono?
Fixed by doing it like this:
*response = mono_string_new(mono_domain_get(), "Test repsonse");
as suggested by delnan

Categories

Resources