Is it possible to store member functions in C++ the way delegates are used in C#?
How do Delegates accomplish the object-instance, memberFuncPtr pairs and calls without knowing anything about the instance class?
(note: this questions arose while I was trying to understand events/delegates in publisher/subscriber code design)
I read that:
C++ requires knowledge of a class type such as ClassType::*FuncPtr
C# delegates allow someDelegate += classInstance.memberFunc
There is type called std::function,but if you are using older version of C++ (older than C++11) you will need to use raw function pointers.Check function pointers in C,they are the same for C++.
Not getting exactly what you are asking.
But you can store member functions in form of function pointers in c++.
void yourFunc(int x);
int main()
{
void (*funcPtr)(int)=&yourFunc;
(*funcPtr)(10);
}
Or
A normal function with an int parameter
// and void return type
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
// fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
/* The above line is equivalent of following two
void (*fun_ptr)(int);
fun_ptr = &fun;
*/
// Invoking fun() using fun_ptr
(*fun_ptr)(10);
return 0;
}
Related
I would like to call a specific method in my Unity3D project within an external plugin. Here is my C++ code:
static void UNITY_INTERFACE_API OnRenderEventThreadSafe(int eventID)
{
[...] Some C++ code
//Call C# Method here
}
My C++ code does already work on its own but now I want to call a specific C# method. How can I manage to do this? I tried creating delegates like this
#if UNITY_EDITOR
[DllImport("lib")]
#else
[DllImport ("lib")]
#endif
private static extern void Method(Delegate callback);
private delegate void Delegate(int number);
[MonoPInvokeCallback(typeof(Delegate))]
private static void DelegateMessageReceived(int number)
{
Debug.Log("MessageReceived " + number);
}
public static void Method2()
{
Method(DelegateMessageReceived);
}
But I don't think this is the right way...
Should have mentioned it earlier, but I'm coding on Linux-Fedora25
I ran into the-same issue in the past when making rendering plugin but the solution is not really hard.
You need to create a global static function pointer to hold the C# function you want to call from C++. The C++ function pointer must be static. Initialize this variable from the Start or Awake function in C#. After this, you can freely call that function anytime from C++.
C++ (YourCppPlugin.h)
#define DLLExport __declspec(dllexport)
extern "C"
{
//Create a function pointer and give it a callback alias to shorten it
typedef void(*FuncCallBack)(int eventID);
//Create a callback delegate from the alias to hold the function from C#
static FuncCallBack callbackInstance = nullptr;
//Create the function that will be called from C# to store the function
DLLExport void RegisterRenderCallback(FuncCallBack cb);
}
C++ (YourCppPlugin.cpp):
#include "YourCPP.h"
//Save the function we received from C# to the global variable for future use:
void RegisterRenderCallback(FuncCallBack cb) {
callbackInstance = cb;
}
Done. You can now use the callbackInstance variable to call the C# function anytime from the Unity's UNITY_INTERFACE_API OnRenderEventThreadSafe C++ API function. Just make sure it's not null before calling it like below:
static void UNITY_INTERFACE_API OnRenderEventThreadSafe(int eventID)
{
[...] Some C++ code
//Call C# Method here
if (callbackInstance != nullptr)
callbackInstance(eventID);
}
Register a function to it first from C# with the RegisterRenderCallback function first before using the callbackInstance variable. See example in the Start function below.
C# side of the code:
// Use this for initialization
void Start()
{
//Register the OnRenderCallback function to our C++ plugin for a callback
RegisterRenderCallback(OnRenderCallback);
}
//Function that registers a local C# function to a delegate in C# for later use
[DllImport("YourCppPlugin", CallingConvention = CallingConvention.Cdecl)]
static extern void RegisterRenderCallback(renderCallback cb);
//int param callback delegate that links to the C# function we want to call from C++
delegate void renderCallback(int eventID);
//Function we want to call from C#. Registered in the Start function
[MonoPInvokeCallback(typeof(renderCallback))]
static void OnRenderCallback(int eventID)
{
Debug.Log("Called from C# with ID: " + eventID);
}
Finally, if you have more than one function to register, you have to use List, array or dictionary to hold them on both C# and C++ side then iterate and call each one when necessary.
I'm wrapping Microsoft's assert class in c# and want to use that code in c++. The issue I'm having has to deal with the info strings and I'm not quite sure how to pass a c++ string to a c# method. Both are managed.
//c# Assert wrapper
static public bool AreEqual<T>(T expected, T actual, string info){
//...
WriteLine(info);
//...
}
called from c++
//c++
void someCppFunc(){
long expected = 2;
long actual = 2;
Assert::AreEqual<long>(expected, actual, L"Some info message");
}
But the error I get says it has no matching function. How would I go about this?
Just pass it a managed string instead of a native C++ one:
//c++/clr
void someCppFunc(){
long expected = 2;
long actual = 2;
Assert::AreEqual<long>(expected, actual, gcnew System::String(L"Some info message"));
}
Here is my unmanaged code:
delegate void MyDelegate(array<int>^% arguments);
typedef void (__stdcall *MyCallback)(array<int>^% arguments);
void Test(MyDelegate^ delegate)
{
MyCallback myCallback = static_cast<MyCallback>(Marshal::GetFunctionPointerForDelegate(delegate).ToPointer());
array<int>^ foo = gcnew array<int>(5);
foo[0] = 1;
foo[1] = 2;
foo[2] = 3;
foo[3] = 4;
foo[4] = 5;
myCallback(foo);
}
result:
The delegate is called, but array.Length of the argument in delegate is one instead of five. The first element in the array is correct. After the callback foo.Length() is also one! Can anyone tell me why??
More infomation:
I am using C++/CLI to wrap a C++ library so that it can be accessed by C#. The C++ library uses member function pointers (FastDelegate) to achieve a type of unmanaged "delegate". I need to provide one of these "FastDelegate" member function pointers that eventually calls a c# delegate. To achieve this it seems I need to do one of the following:
Store a delegate reference in an unmanaged (non ref) class.
Get the address of a managed class to pass to an unmanaged class. (So that I can use a member function pointer to it.)
Something else?
Any ideas?
I'm working with the ref and don't understand clearly "Is it like a pointer as in C/C++ or it's like a reference in C++?"
Why did I ask such a weak question as you thought for a moment?
Because, when I'm reading C#/.NET books, msdn or talking to C# developers I'm becoming confused by the following reasons:
C# developers suggest NOT to use ref in the arguments of a function, e.g. ...(ref Type someObject) doesn't smell good for them and they suggest ...(Type someObject), I really don't understand clearly this suggestion. The reasons I heard: better to work with the copy of object, then use it as a return value, not to corrupt memory by a reference etc... Often I hear such explanation about DB connection objects. As on my plain C/C++ experience, I really don't understand why to use a reference is a bad stuff in C#? I control the life of object and its memory allocations/re-allocations etc... I read in books and forums only advises it's bad, because you can corrupt your connection and cause a memory leak by a reference lose, so I control the life of object, I may control manually what I really want, so why is it bad?
Nowadays reading different books and talk to different people, I don't clearly understand is ref a pointer (*) or a reference like in C++ by & ? As I remember pointers in C/C++ always do allocate a space with a size of void* type - 4 bytes (the valid size depends on architecture), where hosts an address to a structure or variable. In C++ by passing a reference & there is no new allocations from the heap/stack and you work with already defined objects in memory space and there is no sub-allocating memory for a pointer externally like in plain C. So what's the ref in C#? Does .NET VM handle it like a pointer in plain C/C++ and its GC allocates temporary space for a pointer or it does a work like reference in C++? Does ref work only with a managed types correctly or for value types like bool, int it's better to switch an unsafe code and pass through a pointer in unmanaged style?
In C#, when you see something referring to a reference type (that is, a type declared with class instead of struct), then you're essentially always dealing with the object through a pointer. In C++, everything is a value type by default, whereas in C# everything is a reference type by default.
When you say "ref" in the C# parameter list, what you're really saying is more like a "pointer to a pointer." You're saying that, in the method, that you want to replace not the contents of the object, but the reference to the object itself, in the code calling your method.
Unless that is your intent, then you should just pass the reference type directly; in C#, passing reference types around is cheap (akin to passing a reference in C++).
Learn/understand the difference between value types and reference types in C#. They're a major concept in that language and things are going to be really confusing if you try to think using the C++ object model in C# land.
The following are essentially semantically equivalent programs:
#include <iostream>
class AClass
{
int anInteger;
public:
AClass(int integer)
: anInteger(integer)
{ }
int GetInteger() const
{
return anInteger;
}
void SetInteger(int toSet)
{
anInteger = toSet;
}
};
struct StaticFunctions
{
// C# doesn't have free functions, so I'll do similar in C++
// Note that in real code you'd use a free function for this.
static void FunctionTakingAReference(AClass *item)
{
item->SetInteger(4);
}
static void FunctionTakingAReferenceToAReference(AClass **item)
{
*item = new AClass(1729);
}
};
int main()
{
AClass* instanceOne = new AClass(6);
StaticFunctions::FunctionTakingAReference(instanceOne);
std::cout << instanceOne->GetInteger() << "\n";
AClass* instanceTwo;
StaticFunctions::FunctionTakingAReferenceToAReference(&instanceTwo);
// Note that operator& behaves similar to the C# keyword "ref" at the call site.
std::cout << instanceTwo->GetInteger() << "\n";
// (Of course in real C++ you're using std::shared_ptr and std::unique_ptr instead,
// right? :) )
delete instanceOne;
delete instanceTwo;
}
And for C#:
using System;
internal class AClass
{
public AClass(int integer)
: Integer(integer)
{ }
int Integer { get; set; }
}
internal static class StaticFunctions
{
public static void FunctionTakingAReference(AClass item)
{
item.Integer = 4;
}
public static void FunctionTakingAReferenceToAReference(ref AClass item)
{
item = new AClass(1729);
}
}
public static class Program
{
public static void main()
{
AClass instanceOne = new AClass(6);
StaticFunctions.FunctionTakingAReference(instanceOne);
Console.WriteLine(instanceOne.Integer);
AClass instanceTwo = new AClass(1234); // C# forces me to assign this before
// it can be passed. Use "out" instead of
// "ref" and that requirement goes away.
StaticFunctions.FunctionTakingAReferenceToAReference(ref instanceTwo);
Console.WriteLine(instanceTwo.Integer);
}
}
A ref in C# is equivalent to a C++ reference:
Their intent is pass-by-reference
There are no null references
There are no uninitialized references
You cannot rebind references
When you spell the reference, you are actually denoting the referred variable
Some C++ code:
void foo(int& x)
{
x = 42;
}
// ...
int answer = 0;
foo(answer);
Equivalent C# code:
void foo(ref int x)
{
x = 42;
}
// ...
int answer = 0;
foo(ref answer);
Every reference in C# is pointer to objects on heap as pointer in C++ and ref of C# is same as & in C++
The reason ref should be avoided is, C# works on fundamental that method should not change the object passed in parameter, because for someone who does not have source of method may not know if it will result in loss of data or not.
String a = " A ";
String b = a.Trim();
In this case I am confident that a remains intact. In mathematics change should be seen as an assignment that visually tells is that b is changed here by programmer's consent.
a = a.Trim();
This code will modify a itself and the coder is aware of it.
To preserve this method of change by assignment ref should be avoided unless it is exceptional case.
C# has no equvalent of C++ pointers and works on references. ref adds a level of indirection. It makes value type argument a reference and when used with reference type it makes it a reference to a reference.
In short it allows to carry any changes to a value type outside a method call. For reference type it allows to replace the original reference to a totally different object (and not just change object content). It can be used if you want to re-initialize an object inside a method and the only way to do it is to recreate it. Although I would try avoid such an approach.
So to answer your question ref would be like C++ reference to a reference.
EDIT
The above is true for safe code. Pointers do exist in unsafe C# and are used in some very specific cases.
This seems like a disposing/eventing nightmare. If I have an object who's events are registered for and pass it into a function by reference and that reference is then reallocated, the dispose should be called or the memory will be allocated until the program is closed. If the dispose is called everything registered to the objects events will no longer be registered for and everything it is registered for will no longer be registered for. How would someone keep this straight? I guess you could compare memory addresses and try to bring things back to sanity if you don't go insane.
in c# you can check run unsafe in your project properties
and then you can run this code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Exercise_01
{
public struct Coords
{
public int X;
public int Y;
public override string ToString() => $"({X}, {Y})";
}
class Program
{
static unsafe void Main(string[] args)
{
int n = 0;
SumCallByRefPointer(1, 2, &n);
Console.Clear();
Console.WriteLine("call by refrence {0}",n);
n = 0;
SumCallByValue(3, 4, n);
Console.WriteLine("call by Value {0}", n);
n = 0;
SumCallByRef(5, 6, ref n);
Console.WriteLine("call by refrence {0}", n);
Pointer();
Console.ReadLine();
}
private static unsafe void SumCallByRefPointer(int a, int b, int* c)
{
*c = a + b;
}
private static unsafe void SumCallByValue(int a, int b, int c)
{
c = a + b;
}
private static unsafe void SumCallByRef(int a, int b, ref int c)
{
c = a + b;
}
public static void Pointer()
{
unsafe
{
Coords coords;
Coords* p = &coords;
p->X = 3;
p->Y = 4;
Console.WriteLine(p->ToString()); // output: (3, 4)
}
}
}
}
I have a C++ function that produces a list of rectangles that are interesting. I want to be able to get that list out of the C++ library and back into the C# application that is calling it.
So far, I'm encoding the rectangles like so:
struct ImagePatch{
int xmin, xmax, ymin, ymax;
}
and then encoding some vectors:
void MyFunc(..., std::vector<int>& rectanglePoints){
std::vector<ImagePatch> patches; //this is filled with rectangles
for(i = 0; i < patches.size(); i++){
rectanglePoints.push_back(patches[i].xmin);
rectanglePoints.push_back(patches[i].xmax);
rectanglePoints.push_back(patches[i].ymin);
rectanglePoints.push_back(patches[i].ymax);
}
}
The header for interacting with C# looks like (and works for a bunch of other functions):
extern "C" {
__declspec(dllexport) void __cdecl MyFunc(..., std::vector<int>& rectanglePoints);
}
Are there some keywords or other things I can do to get that set of rectangles out? I found this article for marshalling objects in C#, but it seems way too complicated and way too underexplained. Is a vector of integers the right way to do this, or is there some other trick or approach?
The STL is a C++ specific library, so you cant directly get it across as one object to C#.
The one thing that is guaranteed about std::vector is that &v[0] points to the first element and all the elements lie linearly in memory (in other words, its just like a C array in terms of memory layout)
So marshal as array of int... which shouldn't be hard - There are lot of examples on the web.
Added
Assuming you only pass the data from C++ to C# :
C# cannot handle a C++ vector object, so do not try passing it by reference : Instead your C++ code must return a pointer to an array of ints...
If you are not going to be using this function from multiple threads, you can use static storage :
int *getRects(bool bClear)
{
static vector<int> v; // This variable persists across invocations
if(bClear)
{
v.swap(vector<int>());
}
else
{
v.clear();
// Fill v with data as you wish
}
return v.size() ? &v[0] : NULL;
}
call getRects(true) if the returned data is significant in size, so you release the memory in v.
For simplicity, instead of passing out the size of the vector data too, just put a sentinel value at the end (like say -1) so the C# code can detect where the data ends.
Yes. You can. Actually, not just std::vector, std::string, std::wstring, any standard C++ class or your own classes can be marshaled or instantiated and called from C#/.NET.
Wrapping a std::vector<any_type> in C# is indeed possible with just regular P/Invoke Interop, it is complicated though. even a std::map of any type can be done in C#/.NET.
public class SampleClass : IDisposable
{
[DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void SampleClassConstructor(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DestructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void SampleClassDestructor(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject, int x);
IntPtr ptr;
public SampleClass(int sizeOfYourCppClass)
{
this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
SampleClassConstructor(this.ptr);
}
public void DoSomething()
{
DoSomething(this.ptr);
}
public void DoSomethingElse(int x)
{
DoSomethingElse(this.ptr, x);
}
public void Dispose()
{
if (this.ptr != IntPtr.Zero)
{
// The following 2 calls equals to "delete object" in C++
// Calling the destructor of the C++ class will free the memory allocated by the native c++ class.
SampleClassDestructor(this.ptr);
// Free the memory allocated from .NET.
Marshal.FreeHGlobal(this.ptr);
this.ptr = IntPtr.Zero;
}
}
}
Please see the below link,
C#/.NET PInvoke Interop SDK
(I am the author of the SDK tool)
Once you have the C# wrapper class for your C++ class ready, it is easy to implement ICustomMarshaler so that you can marshal the C++ object from .NET.
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx
I'm pretty sure you can't do this. You have to be able to translate the C++ code directly to a C# class, so you would at least have to replicate the internals of the vector class to marshall it correctly. I'm also pretty sure you won't be able to move references across the boundary, you'll have to use IntPtr (raw pointers). The approach that i know works is to marshall a raw array of the structs.