Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping unmanaged C++ with C++/CLI - a proper approach

as stated in the title, I want to have my old C++ library working in managed .NET. I think of two possibilities:

1) I might try to compile the library with /clr and try "It Just Works" approach.

2) I might write a managed wrapper to the unmanaged library.

First of all, I want to have my library working FAST, as it was in unmanaged environment. Thus, I am not sure if the first approach will not cause a large decrease in performance. However, it seems to be faster to implement (not a right word :-)) (assuming it will work for me).

On the other hand, I think of some problems that might appear while writing a wrapper (e.g. how to wrap some STL collection (vector for instance)?) I think of writing a wrapper residing in the same project as the unmanaged C++ resides - is that a reasonable approach (e.g. MyUnmanagedClass and MyManagedClass in the same project, the second wrapping the other)?

What would you suggest in that problem? Which solution is going to give me better performance of the resulting code?

Thank you in advance for any suggestions and clues!

Cheers

like image 676
Jamie Avatar asked Jan 10 '11 00:01

Jamie


2 Answers

First of all, forget about Managed C++. Use C++/CLI.

The difference is that Managed C++ was Microsoft's first attempt at extending C++ to work with .NET, and honestly, it was all kinds of horrible.

So they gave up on that, and designed C++/CLI instead, which works much better.

Second, valid C++ code should just work if you compile it as C++/CLI, so that does seem like the obvious way to do it.

Of course, in order to expose your C++ types to .NET assemblies, you're going to have to write some wrappers either way. For STL types, you might look into Microsoft's STL/CLR library.

But in general, just add the /cli switch, compile your code as C++/CLI, and then add what wrappers you need. There's no reason why your code would magically become slower or anything.

like image 200
jalf Avatar answered Oct 24 '22 19:10

jalf


The way I do it is

  1. Create a normal unmanaged .lib. Make sure that you link to the standard runtime as a DLL (required if the .lib is in an assembly)

  2. Create a C++/CLI assembly.

  3. Add the .lib to the link like of the assembly

  4. Create a managed interface

  5. Minimize the granularity of calls across managed/unmanaged. Meaning, prefer getting big chunks of data (like a datastructure) rather than use an interface to an unmanaged data-structure from the managed side. This is because calls across the boundary are slow.

Things like a std::vector need to be hand-wrapped in System.Collections -- but, "it just works" is good for built-in types and even function pointers.

Other gotchas. Callbacks need to be stdcall to be turned into a delegate, and delgates sent to unmanaged callbacks do not hold a reference (so, arrange to hold a reference somewhere else or crash when the object is GC'd).

like image 35
Lou Franco Avatar answered Oct 24 '22 19:10

Lou Franco