tags:

views:

233

answers:

3

How to make a native API to be PInvoke friendly?

there are some tips on how to modify native-programs to be used with P/Invoke here. But before I even write a native programs, what are the things I should look out to make my programs/library PInvoke friendly?

using C or C++ are fine.


update:
if I write a C API, what are the things I have to do so that It is P/Invoke-able using C# syntax like the following:

[DLLimport("MyDLL.dll")]

is it possible to do the same with native C++ code/library?


Summary/Rephrase of Some Tips to make a P/Invoke friendly native-API:
+ the parameters should be of native types (int, char*, float, ...)
+ less parameters is better
+ if dynamic memory is allocated and passed to managed code, make sure to create a "cleaner" function which is also p/invoked
+ provide samples and/or unit tests that illustrate how to call the API from .NET
+ provide C++/CLI wrapper

+1  A: 

By definition every native function can be p/invoked from managed code. But in order to be p/invoke friendly a function should have as few parameters as possible which should be of native types (int, char*, float, ...). Also if a function allocates memory on some pointer that is returned to managed code, make sure you write its counter part that will free the pointer as managed code cannot free memory allocated from unmanaged code.

Darin Dimitrov
"a function should have as few parameters as possible which should be of native types (int, char*, float, ...)" Can I summarize it into: -> the parameters should be of native types (int, char*, float, ...) -> less parameters is better -> if dynamic memory is allocated and passed to managed code, make sure to create a "cleaner" function which is also p/invoked
afriza
Yes, that's a good summary.
Darin Dimitrov
+1  A: 

Provide an example of correctly calling it from C# or .NET, even better provide a .NET class that wraps all your methods

Writing a simple unit test with nunit that proves your code works correctly when called from .Net would be a great way of doing it.

Also remember that the .NET developers that are likely to be calling your code are unlikely to know much about C++, or don’t know the sizes of different data types etc or how these types map to the PInvoke attributes.

Above all think about how you wish your clients code to look and then design a API that allows it.

Ian Ringrose
+1  A: 

Instead of using P/Invoke, if you are controlling the native library yourself, you can write a set of C++/CLI classes that wrap the native calls. In many cases, this will perform better than using platform invoke, and you get the added benefit of type correctness. For example, if you have some sort of C API like the following (it doesn't do anything useful, I just added pointers and structs to reinforce the fact that it is native code):

struct SomeStruct {
  int a, b;
  int* somePtr;
};

int foo(struct SomeStruct* a, int b) {
  *a->somePtr = a->a + a->b;
  return a->b * *a->somePtr + b;
}

You can create a C++/CLI class to wrap it:

public ref class MyNativeAPI {
  private:
    SomeStruct* x;
  public:
    MyNativeAPI() {
      x = new SomeStruct;
    }  
    ~MyNativeAPI() {
      delete x;
    }
    int Foo(int a) {
      pin_ptr<SomeStruct*> ptr = this->x;
      return foo(ptr, a);
    }
}

Then, you can call this in C#:

MyNativeAPI a = new MyNativeAPI();
if(a.Foo(5) > 5) { ... };

You'll have to read more on C++/CLI to understand the new controls you have over both the managed heap and the native heap, and the caveats to mixing the two (like the pin_ptr I used above), but overall it's a much more elegant solution to accomplishing native interop in .NET.

atanamir