views:

627

answers:

2

In the process of learning P/Invoke, I asked this previous question:

How to P/Invoke when pointers are involved

However, I don't quite understand the implications of using P/Invoke in C# over creating a wrapper in Managed C++. Creating the same DLL using P/Invoke in C# definately resulted in a cleaner interface since I could use DLLImport on an embedded resource, but would a Managed C++ wrapper for a native DLL, where I do the marshaling myself, have better performance?

+5  A: 

C++ wrapper should be faster, have a look at this MSDN page:

C++ Interop uses the fastest possible method of data marshaling, whereas P/Invoke uses the most robust method. This means that C++ Interop (in a fashion typical for C++) provides optimal performance by default, and the programmer is responsible for addressing cases where this behavior is not safe or appropriate.

So basically the main reason is that P/Invoke does pinning, blitting, error checking, while C++ interop just pushes the parameters on the stack and calls the function.

Another point to remember is that C++ can call a several APIs in a single call while P/Invoke EVERY parameter passed by address gets pinned and unpinned on EVERY call, copied and copied back, etc.

Dror Helper
I've read that before, but I read it to mean that using C++ interop from within C++, rather than P/Invoke from within C++, is quicker, which I would have assumed anyways. It doesn't necessarily address going from C# to C++ to DLL as opposed to C# to DLL through P/Invoke
Will Eddins
I don't think so - because Managed C++ is still a managed language (transformed to IL code) calling it from C# should not incur large performance overhead
Dror Helper
Accepted this since this is pretty much right. The only thing I'm confused about is where does the IL stop and the native code stop, since you can use both native pointers and objects and managed objects mixed together in C++. It's unclear at what point it may leave managed space and enter native.
Will Eddins
+1  A: 

Would you get better performance? Depends on what you're doing and how you're doing it. Generally speaking, your performance hit will more likely come from doing managed/unmanaged transitions and the more of those you can cut out the better. Ideally, your interfacing to unmanaged code should be chunky and not chatty.

Let's say that you have a unmanaged code that has a collection of a few thousand objects. You could expose an API like this to managed code:

int GetFooCount();
IntPtr GetFoo(int n);
void ReleaseFoo(IntPtr p);

and that's all well and good, until you start using it in C# like this:

int total = API.GetFooCount();
IntPtr[] objects = new IntPtr[total];
for (int i=0; i < total; i++) {
    objects[i] = GetFoo(i);
}
// and later:
foreach (IntPtr p in objects) { ReleaseFoo(p); }

which for total == 1000, will be 4002 managed/unmanaged transitions. If instead you have this:

int GetFooCount();
void GetFoos(IntPtr[] arr, int start, int count);
void ReleaseFoos(IntPtr arr, int start, int count);

then you can do the same work with 6 transitions. Which do you think will perform better?

Of course, the next important question to ask is "is this performance gain worthwhile?" so remember to measure first.

One thing you should be aware of as well is that funny things can happen to STL when you're working with managed C++. I have some unmanaged library code which happens to use STL. My experience was that if I ever touched any of the STL types in managed C++, ALL of them became managed implementations. The end result of this was that low level code was doing managed/unmanaged transitions while iterating lists. Yikes. I solved this by never exposing the STL types to managed C++.

In our experience, it is far better (if possible) to go C#->managed C++ wrapper->static library, if you have the ability to do that.

plinth