简体   繁体   English

如何制作PInvoke友好的原生API?

[英]How to make a PInvoke friendly native-API?

How to make a native API to be PInvoke friendly? 如何使本机API成为PInvoke友好的?

there are some tips on how to modify native-programs to be used with P/Invoke here . 有关于如何修改本机程序,以P中使用的一些技巧/调用这里 But before I even write a native programs, what are the things I should look out to make my programs/library PInvoke friendly? 但在我写一个原生程序之前,我应该注意哪些事情让我的程序/库PInvoke友好?

using C or C++ are fine. 使用C或C ++很好。


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: 如果我编写一个C API,那么我必须做什么才能使用C#语法进行P / Invoke-able,如下所示:

 [DLLimport("MyDLL.dll")] 

is it possible to do the same with native C++ code/library? 是否可以对本机C ++代码/库执行相同的操作?


Summary/Rephrase of Some Tips to make a P/Invoke friendly native-API: 关于制作P / Invoke友好原生API的一些技巧的摘要/改述:
+ the parameters should be of native types (int, char*, float, ...) +参数应该是本机类型(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 +如果分配了动态内存并将其传递给托管代码,请确保创建一个“清理”函数,该函数也是p / invoked
+ provide samples and/or unit tests that illustrate how to call the API from .NET +提供示例和/或单元测试,说明如何从.NET调用API
+ provide C++/CLI wrapper +提供C ++ / CLI包装器

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. 如果您自己控制本机库,则可以编写一组包装本机调用的C ++ / CLI类,而不是使用P / Invoke。 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): 例如,如果你有某种类似下面的C API(它没有做任何有用的事情,我只是添加了指针和结构来强化它是本机代码的事实):

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: 您可以创建一个C ++ / CLI类来包装它:

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#: 然后,您可以在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. 你必须阅读更多关于C ++ / CLI的内容,以了解你对托管堆和本机堆的新控制,以及混合两者的警告(比如我上面使用的pin_ptr ),但总的来说它更多在.NET中实现本机互操作的优雅解决方案。

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, ...). 但是为了使p / invoke友好,函数应该具有尽可能少的参数,这些参数应该是本机类型(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. 此外,如果函数在返回给托管代码的某个指针上分配内存,请确保编写将释放指针的计数器部分,因为托管代码无法释放从非托管代码分配的内存。

Provide an example of correctly calling it from C# or .NET, even better provide a .NET class that wraps all your methods 提供从C#或.NET正确调用它的示例,甚至更好地提供包装所有方法的.NET类

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. 用nunit编写一个简单的单元测试,证明你的代码在从.Net调用时正常工作将是一个很好的方法。

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. 还要记住,可能调用代码的.NET开发人员不太了解C ++,或者不知道不同数据类型的大小等,或者这些类型如何映射到PInvoke属性。

Above all think about how you wish your clients code to look and then design a API that allows it. 最重要的是考虑您希望客户代码的外观,然后设计一个允许它的API。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM