Wrapping unmanaged C++ with C++/CLI - a proper approach
Asked Answered
J

3

8

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

Jaclin answered 10/1, 2011 at 0:7 Comment(0)
M
6

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.

Maybe answered 10/1, 2011 at 0:16 Comment(4)
writing "managed C++" I thought of C++/CLI obviously :-) - now it is edited, thanks for that :)Jaclin
Yeah, it's common to mix them up. But it can lead to confusion too. :)Maybe
so much hatred for the double underscore syntax :PIrritating
Do keep in mind that if your code contains any native classes, then it will not run in untrusted mode. Something to think about if you turn around and want to deploy something in a silverlight xap. You would have to use /clr:pure then, and that means you have to essentially rewrite everything.Viquelia
E
3

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

Exigible answered 10/1, 2011 at 0:19 Comment(3)
So step 4 I assume is with the use of P/Invoke approach?Midgut
No. In C++/CLI you can make managed classes and unmanaged classes. There is no P/Invoke -- both classes are in the same assemblyExigible
I actually just realized it shortly after my comment. It's the IJW (It Just Works). I'm actually linking the unmanaged and CLI libraries as two projects of the same solution through Visual Studio -> Add Reference, like in this question: #18303284 And yes, I had to write conversions for most of the arrays, vectors and other complex types. MS Marshaling library helped a lot: msdn.microsoft.com/en-us/library/vstudio/bb384865.aspxMidgut
K
1

If you have a lot of unmanaged functions to wrap, you should consider using SWIG. It writes all the wrapper and interop code for you, and has pre-written SWIG interface files that support std::vector, std::string, windows types, etc.

I have a full example exposing unmanaged C++ DLL functions if you are interested.

Kwasi answered 10/1, 2011 at 3:51 Comment(1)
Mark i would like to see a full exampleTearoom

© 2022 - 2024 — McMap. All rights reserved.