Using managed objects in native C++ class - c++-cli

I want to call members of a C++/CLI class from native C++ code. Compiler is prohibiting me from doing that. I know that we can use native pointers/references in managed code but don't know way of going opposite. Can anyone help me with this by giving a simple example.Thanks in advance.

It can't be done. Memory layout of managed types is determined by the JIT, so unless your native code uses the CLR programming interface, it has no way of discovering and accessing them. Keeping references visible to the garbage collector is another problem, although overcoming that is more straightforward.
However it is possible to create native types with C++/CLI and those will have a memory layout fixed at compile time, so both managed and native code can use them. That is the way to cross the managed-native boundary in reverse. (Function pointers created from delegates are another way to cross in reverse)

Related

Interoperability with SwiftyChrono from Objective-C

I'm trying to use the SwiftyChrono swift library from an Objective-C project. Since it's using a struct instead of a class (amongst many other Swift only features), I'm unable to make it work.
Given I am not in the position of moving all our Objective-C code to Swift, what are my options? Would writing a second Swift framework work, one that sits in between our app and SwiftyChrono and serves as a wrapper? Would that even work? I'm guessing if this new Swift framework was dumb enough to only perform a single function in 'Swift Land', it would play well with Objective-C?
I haven't dealt with inter-op and it really feels like a losing battle. Any help would be appreciated.

C++ Declare managed type in native code

I need to know how do I declare a managed type inside native code?
Like: I have a ref class Editor in Editor.h
In native code(main.cpp):
Editor^ MainEditor;
But it gives me the following:
MainEditor' : global or static variable may not have managed type 'Cube3D::Editor ^'
I've tried to make it inside a container but I still need to declare it.
You can't do that directly. The issue is that the managed object will be moved by the garbage collector, and purely native code can't handle that.
Here's what is allowed:
Members of managed types must be compiled with /clr to produce managed code. This can use both managed and native types implemented with both managed and native code.
Members of native types and namespaces can be compiled with /clr to produce managed code. This can use both managed and native types implemented with both managed and native code.
Members of native types and namespaces can be compiled without /clr to produce native code. This can use only native types, but the types used can be implemented by either managed or native code.
It's even possible for some members of a native type to be implemented in native code and other members of the same type to be implemented in managed code.
So, you need a layer in between your native code and your managed type, this in-between layer will be a native type implemented with managed code.
Of course, #pragma managed can be used interchangeably with /clr, for finer control.
As the error states you can't have a managed type at global or static level.
You've declared it right for using it inside a method. For storing it inside a native class, you'll want to use gcroot.

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.

Wrapper to unmanaged code

How would you build a wrapper to unmanaged code in order to use it in managed code, and when exactly do you have to do that?
You don't often need a wrapper, many DLLs with straight-forward exported C functions can be pinvoked with the [DllImport] attribute. An exception for C exports would be a poorly designed DLL that requires the client code to release memory, that can't be done by the managed code since it doesn't have access to the allocator.
The case where you have to have a wrapper is a native C++ class. Managed code cannot pinvoke it directly since it doesn't know how to create an instance of the class (which requires knowing the size of the object and calling the constructor) nor how to destroy it (which requires calling the destructor). It is pretty easy to do in C++/CLI. Very mechanical, the SWIG project can do it automatically. Learning that tool is however more of an investment than learning how to write the wrapper.

c++/cli wrapper question

Is there a recommended way to wrap a native c++ library by c++ cli?
Not sure if one size fits all, but yeah, it is largely a mechanical process. Your ref class wrapper should declare a private member that's a pointer to your native C++ class. Create the instance in the constructor. You'll need a destructor and a finalizer to delete that instance again.
Then for each function in the native C++ class you write a managed version of it. That's almost always a one-to-one call, you simply call the corresponding native method and let C++ Interop convert the arguments. Sometimes you have to write a bit of glue code to convert a managed argument to the native version of it, particularly if your native method uses 8-bit char* or structure arguments.
You'll find that standard pattern in code in my answer here. I also should mention SWIG, a tool that can automate it. Not sure how good it is, never used it myself.