繁体   English   中英

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

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

如何使本机API成为PInvoke友好的?

有关于如何修改本机程序,以P中使用的一些技巧/调用这里 但在我写一个原生程序之前,我应该注意哪些事情让我的程序/库PInvoke友好?

使用C或C ++很好。


更新:
如果我编写一个C API,那么我必须做什么才能使用C#语法进行P / Invoke-able,如下所示:

 [DLLimport("MyDLL.dll")] 

是否可以对本机C ++代码/库执行相同的操作?


关于制作P / Invoke友好原生API的一些技巧的摘要/改述:
+参数应该是本机类型(int,char *,float,...)
+更少的参数更好
+如果分配了动态内存并将其传递给托管代码,请确保创建一个“清理”函数,该函数也是p / invoked
+提供示例和/或单元测试,说明如何从.NET调用API
+提供C ++ / CLI包装器

如果您自己控制本机库,则可以编写一组包装本机调用的C ++ / CLI类,而不是使用P / Invoke。 在许多情况下,这将比使用平台调用更好,并且您还可以获得类型正确性的额外好处。 例如,如果你有某种类似下面的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;
}

您可以创建一个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);
    }
}

然后,您可以在C#中调用它:

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

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

根据定义,可以从托管代码调用每个本机函数。 但是为了使p / invoke友好,函数应该具有尽可能少的参数,这些参数应该是本机类型(int,char *,float,...)。 此外,如果函数在返回给托管代码的某个指针上分配内存,请确保编写将释放指针的计数器部分,因为托管代码无法释放从非托管代码分配的内存。

提供从C#或.NET正确调用它的示例,甚至更好地提供包装所有方法的.NET类

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

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

最重要的是考虑您希望客户代码的外观,然后设计一个允许它的API。

暂无
暂无

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

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