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

(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.

Related

CLR Host - how to execute functions with arbitrary method signature

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;
}
}
}

'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.

Cannot implicit convert a type

I am running into a road block when I am trying to do some testing on delegate. My goal is to create instances of MyStates class that have the ability to call some predefined functions that I defined in MyFunctions class. In the class, I have a dictionary that will refer the functions by name and have a function that retrieve the address of the function and put it in MyState instance so that I could refer it at run time. The idea appears to be simple but the compiler is not happy about it. I think I may have an idea of what is wrong but I am not sure how to get rid of the compiler error. Please advise how to fix this compiler error.
MyFunctions class is defined as below:
public sealed class MyFunctions
{
public delegate int myFunction(object o);
private static Dictionary<string, myFunction> funcRouter
= new Dictionary<string, myFunction>();
#region Singleton
private static readonly MyFunctions _functionInstance = new MyFunctions();
static MyFunctions()
{
}
private MyFunctions()
{
funcRouter.Add("Test2", Test2);
}
public static MyFunctions functionInstance
{
get
{
return _functionInstance;
}
}
#endregion
#region Definition and implementation of all the functions
public int Test2(object o)
{
System.Diagnostics.Debug.WriteLine("Testing 2, object received {0}", (int)o);
return 112;
}
#endregion
public myFunction Get(string s)
{
return (myFunction)funcRouter[s];
}
}
MyStates class is defined below:
public delegate int myFunction(object o);
public class MyState
{
private int _ID;
private myFunction _func;
public myFunction func
{
get { return _func; }
}
public int ID
{
get { return _ID; }
}
public MyState(int myID, myFunction f = null)
{
_ID = myID;
_func = f;
}
}
My main program:
public delegate int myFunction(object o);
class Program
{
static void Main(string[] args)
{
myFunction f = null;
//f = MyFunctions.functionInstance.Test2;
f = MyFunctions.functionInstance.Get("Test2");
MyState s = new MyState(123,f);
Console.ReadLine();
}
}
Note: The code above will generate the compiling error. However, if I use the statement
f = MyFunctions.functionInstance.Test2;
The program will compile fine and execute correctly. I think the issue resides in the use of dictionary to retrieve the address of the function. It is possible to possible to do that in C++, I would think C# should allow me to do the same thing. I just did not do it correctly.
Please advise.
You are defining public delegate int myFunction(object o); in two places. The compiler error error says you can't convert one to the other. This is because in the case of f = MyFunctions.functionInstance.Get("Test2"); you are assigning a return value of one type to a variable of a different type, but with f = MyFunctions.functionInstance.Test2; the compiler just looks for a method signature that matches the delegate.
One fix is to declare f as MyDelegates.MyFunctions.myFunction.
MyDelegates.MyFunctions.myFunction f;
f = MyDelegates.MyFunctions.functionInstance.Get("Test2");
Another way is to wrap it in your local delegate (because then the signature-match is used again):
myFunction f;
f = new myFunction(MyDelegates.MyFunctions.functionInstance.Get("Test2"));
The same applies to using it in the MyState-call later.
Another way to work around this is to just use Func<object, int> everywhere instead of the myFunction delegate.

Implementing lock in C++

Sorry that the question of this problem might be a bit vague. I'm trying to port this ObjectPool code from C# into C++ but seems there are some parts where I don't know how I should proceed. Codes are as follows:
using System;
namespace FastRank
{
public class ObjectPool<T> where T : class, new()
{
private int _count;
private T[] _pool;
public ObjectPool(int initSize)
{
_pool = new T[initSize];
}
public T Get()
{
lock (_pool)
{
if (_count > 0)
{
--_count;
T item = _pool[_count];
_pool[_count] = null;
return item;
}
}
return new T();
}
public void Return(T item)
{
lock (_pool)
{
if (_count == _pool.Length)
Array.Resize(ref _pool, _pool.Length*2 + 1);
_pool[_count++] = item;
}
}
}
}
My questions are:
1) How should I implement that constraint on generic parameter T in C++? (class, new())
2) Is there a simple way to implement the mutex lock part?
3) Will it be more efficient to define _pool as vector instead of T[] in C++?
edit -> Implemented something as:
#include "object_pool.h"
#include <boost/thread.hpp>
#include <vector>
using namespace std;
template <class T>
ObjectPool<T>::ObjectPool(int init_size) {
pool_.reserve(init_size);
}
template <class T>
T ObjectPool<T>::Get() {
boost::lock_guard<boost::mutex> lock(guard_);
int sz = (int) pool_.size();
if (sz == 0) {
throw "Object pool size is now zero.";
}
else {
T item = pool_[sz-1];
pool_.pop_back();
return item;
}
}
template <class T>
void ObjectPool<T>::Return(T item) {
boost::lock_guard<boost::mutex> lock(guard_);
pool_.push_back(item);
}
Wondering if there's any problem with this code...
1) How should I implement that constraint on generic parameter T in C++? (class, new())
In general, don't. If it fails to meet the constraints, it will fail to compile. Simple enough. There are tricky ways to get better error messages, but I've forgotten them offhand because I never bothered.
2) Is there a simple way to implement the mutex lock part?
Use a boost::mutex.
3) Will it be more efficient to define _pool as vector instead of T[] in C++?
Considering that you can't have a local T[] without a size, yes. Use a std::vector. (You can have it as a parameter, but not at the variable definition.)
Here's a naive snippet that illustrates one possible approach:
#include <mutex>
template <typename T>
class SyncStack
{
T * m_data;
std::size_t m_size;
std::size_t m_count;
std::mutex m_lock;
public:
T get()
{
std::lock_guard<std::mutex> lock(m_lock);
if (m_count == 0) { throw UnderrunException; }
--m_count;
T x(m_data[m_count]);
m_data[m_count].~T();
return x;
}
void put(T x)
{
std::lock_guard<std::mutex> lock(m_lock);
::new (m_data + m_count) T(std::move(x));
++m_count;
}
};
This example assumes that m_data points to infinite memory. Reallocation is a bit tricky and involves making lots of copies.
A simpler approach would be to wrap your synchronized structure around another, existing standard container such as std::vector<T>.
This is how I would have implemented it. You could replace tbb::concurrenct_queue with a std::mutex guarded std::queue, although that would be less efficient. With this implementation you do need to worry about "returning" objects back to the pool, it's handled automatically.
#include <memory>
#include <tbb/concurrent_queue.h>
namespace FastRank
{
template<typename T>
class object_pool
{
typedef tbb::concurrent_bounded_queue<std::shared_ptr<T>> pool_t;
std::shared_ptr<pool_t> pool_;
public:
object_pool() : pool_(new pool_t())
{
}
std::shared_ptr<T> get()
{
std::shared_ptr<T> ptr;
if(!pool_.try_pop(ptr))
ptr = std::make_shared<T>();
auto pool = pool_;
return std::shared_ptr<T>(ptr.get(), [pool, ptr](T*){pool->push(ptr);});
}
}
}
Without concurrent_queue
#include <memory>
#include <queue>
#include <boost/mutex.hpp>
namespace FastRank
{
template<typename T>
class object_pool
{
typedef std::pair<std::queue<std::shared_ptr<T>>, boost::mutex> pool_t;
std::shared_ptr<pool_t> pool_;
public:
object_pool() : pool_(new pool_t())
{
}
std::shared_ptr<T> get()
{
std::shared_ptr<T> ptr;
{
boost::scoped_lock<boost::mutex> lock(pool_->second);
if(!pool_->first.empty())
{
ptr = std::move(pool->first.front());
pool->first.pop()
}
}
if(!ptr)
ptr = std::make_shared<T>();
auto pool = pool_;
return std::shared_ptr<T>(ptr.get(), [pool, ptr](T*)
{
boost::scoped_lock<boost::mutex> lock(pool->second);
pool->push(ptr);
});
}
}
}

Categories

Resources