How to implement Unity like internal call with mono - mono

C# side code
[WrapperlessIcall]
[MethodImpl(MethodImplOptions.InternalCall)]
private extern void INTERNAL_set_rotation(ref Quaternion value);
How to expose this method from C++ to mono
Thanks.

You need to call mono_add_internal_call:
mono_add_internal_call ("YourClass::INTERNAL_set_rotation", yourclass_INTERNAL_set_rotation);
There is some documentation here: http://www.mono-project.com/Embedding_Mono#Exposing_C_code_to_the_CIL_universe
And here is a code sample: https://github.com/mono/moon/blob/8d8ece884382d653d215b0da5bf633079566d816/src/deployment.cpp#L579

Related

Generic List in C# DLL cannot be accessed from CLI

Want to preface this by pointing out I am new to C++/CLI
We have one solution with an unmanaged C++ application project(We'll call "Application") and a C# .net remoting project which builds to a DLL(We'll call "Remoting"), and a CLI project for interfacing between the two(We'll call "Bridge").
Everything seems to be working, we have an IMyEventHandler interface in Bridge which successfully receives events from Remoting and can call methods in Application.
#ifndef EVENTS_HANDLER_INTERFACE_H_INCLUDED
#include "EventsHandlerInterface.h"
#endif
#define DLLEXPORT __declspec(dllexport)
#ifdef __cplusplus
extern "C"
{
#endif
DLLEXPORT bool RegisterAppWithBridge(IMyEventsHandler * aHandler);
DLLEXPORT void PostEventToServer(AppToServerEvent eventType);
DLLEXPORT void PollEventsFromServer();
#ifdef __cplusplus
}
#endif
In Bridge implementation we have a method for handling an event and depending on which event type it is, we will call a different method for handling that exact type:
void Bridge::OnReceiveServerEvent(IMyEvent^ aEvent)
{
// Determine event type
...
Handle_SpecificEventType();
}
This all is working fine so far. Once we call the handler for a known type of event, we can directly cast to it from the generic interface type. And this is where we start to see the issue. All these event types are defined in another DLL generated from C#. Simple events that have just ints or strings work just fine, but we have this SpecificEventType which contains a list of other types(We'll call "AnotherType") all defined in another DLL. All required DLL's have been added as references, and I am able to gcnew a AnotherType without it complaining.
However, once I try to get AnotherType element out of the list, we see the build error: "C2526 'System::Collections::Generic::List::GetEnumerator' C linkage function cannot return C++ class"
void Bridge::Handle_SpecificEventType(IMyEvent ^evt)
{
SpecificEventType ^e = (SpecificEventType ^)evt;
// We can pull the list itself, but accessing elements gives error
System::Collections::Generic:List<AnotherType ^> ^lst = e->ThatList;
// These all cause error
array<AnotherType ^> ^arr = lst->ToArray();
AnotherType ^singleElement = lst[0];
for each(AnotherType ^loopElement in lst){}
}
To clarify why we're doing this, we are trying to take managed events defined in a C# DLL and sent through .net remoting from a newer C# server, and "translate" them for an older unmanaged C++ application. So the end goal is to create a copy of the C# type "SpecificEventType" and translate it to unmanaged "SpecificEventType_Unmanaged" and just make a call to the application with that data:
// Declared in Bridge.h and gets assigned from DLLEXPORT RegisterGameWithBridge method.
IMyEventsHandler *iApplicationEventHandler;
// Bridge.cpp
void Bridge::Handle_SpecificEventType(IMyEvent ^evt)
{
... Convert SpecificEventType to SpecificEventType_Unmanaged
iApplicationEventHandler->Handle_SpecificEvent(eventUnmanaged);
}
This messaging all seems to be working and setup correctly - but it really doesn't want to give us the elements from the generic list - preventing us from pulling the data and building an unmanaged version of the event to send down to the application.
I hope I have explained this well, again I am new to CLI and haven't had to touch C++ for some years now - so let me know if any additional details are needed.
Thanks in advance for any assistance.
Turns out the issue was because all the methods in Bridge implementation were still inside of an extern "C" block. So much time lost - such a simple issue.

Pass objects from referenced managed dll to a C++/CLI wrapper

So, I'm a writing a C++/CLI wrapper and I would like it to interact with objects from a referenced, managed (C#) dll. More specifically, in my C++/CLI project, I would like to have classes like this:
public ref class MyClass
{
public:
void InputPoints(array<Point3d^>^ ptsIn);
};
Where, "Point3d" is an object from the referenced, managed dll - call it "MyGeometryDLL.dll". This compiles without any problems, however when I use the wrapper in a C# project (that also references "MyGeometryDLL.dll") , I can't pass Point3d directly to the wrapper, i.e., intellisense detects:
void MyClass.InputPoints(ValueType[] ptsIn);
How would I pass Point3d directly to the wrapper?
So class Point3d is already defined in a C# DLL, correct? In that case, I think it may be an issue of carats.
If it's declared in C# as public struct Point3d, then it's a value type, not a reference type. That means that whenever you use it in C++/CLI, you don't use the ^, and you don't call gcnew. If that's the case, then you need to change the method declaration to this:
void InputPoints(array<Point3d>^ ptsIn); // No carat on Point3d
The reason that C# sees this as ValueType[] is because Point3d^ is a legal type in C++/CLI, but it doesn't exist in C#. A general ValueType is the closest thing, so that's what C# sees.

How to dispose/delete managed object from C++/CLI

I'm working on a native C++ project (/clr enabled) that must use a couple of managed, COM visible C# DLLs. Some of the managed objects implement IDisposable and I would like to call Dispose() on them. How can I do that?
The code looks something like this:
HRESULT hr = CoInitialize(NULL);
IManagedClassPtr pIObj(__uuidof(ManagedClass));
//do stuff with pIObj
...
//dispose of pIObj somehow
...
CoUninitialize();
First of all, if you don't have to, just don't use COM.
C++/CLI is designed to give an easy interface between C++ and .Net languages.
If you want to create a .Net object in C++/CLI you just use gcnew with a reference variable.
.Net classes that have a Dispose() method will have it in C++/CLI too. The difference is that if you declare a ref class (.Net reference class) in C++/CLI then the ~destructor turns into a Dispose method.
The !finalizer is what's actually called by the GC.
So anyway, if you create a .Net object with a Dispose() method, you would be able to do this:
MyDisposable^ m = gcnew MyDisposable();
m->Dispose();

How to push data from unmanaged to managed code?

I am using a C++/CLI Wrapper to access a purely C++ library (-> unmanaged) from a C# framework (-> managed). I want to build in a mechanism which enables the C++ library to push information about its status towards the framework. In my understanding this means that I will have to call at least a managed function from unmanaged code at some point. Is this possible and how can I achieve this?
Many thanks for your help!
Best regards,
Jakob
Use a delegate to let unmanaged code call a managed method. Marshal::GetFunctionPointerForDelegate() creates a stub that takes care of the transition, calling an instance method is supported. You can cast the returned pointer to a function pointer usable by the unmanaged code.
You'll find a full code sample in this answer.
I would recommend using a (managed) event for this. You could have your C++ wrapper call a method on your C++/CLI generated class which raises the event.
The event can easily be subscribed to from the C# side, and used like any other C# based event.

C++ virtual (sealed) function

I am using classes from a dll in my C++ project. All is working fine, until...
When trying to call a certain method (listed in the object browser), I am getting an error that this method is not a member of the namespace.
Upon investigation, I noticed that this method is listed as "virtual void x() sealed".
Is there a way to make a call to such a function?
For future reference, I just received a response from the enterprise library support team. They posted a link to the following:
Managed C++ and IDisposable
I'm writing some code using the new Managed C++/CLI syntax and I ran into this error:
error C2039: 'Dispose' : is not a member of 'System::IDisposable'
the code I started with was this:
image->Dispose(); // image implements IDisposable
which gave me the same compiler error, so I wanted to eliminate a class/namespace error so I rewrote it as this:
((IDisposable ^)image)->Dispose();
Which gave the above error. Yikes!
Here's the fix:
use delete. Managed C++ now hides Dispose() inside the finalizer. Just delete the object, it handles the rest. Freaky.
This really works!!!!
Sealed in a C++ CLI keyword (managed C++) specific to .NET and not C++ in general.
sealed on a function means that you can't override that method in a derived type.
sealed does not mean that you can't call the function, I'm guessing your function is private.
I don't see why it being virtual and sealed should in itself prevent you from calling the function. According to MSDN, the sealed keyword is specifically meant for virtual methods anyway.
Is there any more information you can give about the function in question and how you are trying to use it?