2010-01-19 61 views
6

如何使本地API成为PInvoke友好?如何使PInvoke友好的原生API?

有关于如何修改与P/Invoke here一起使用的本机程序的一些提示。但是在我编写本地程序之前,我应该注意什么使我的程序/库PInvoke友好?

使用C或C++都很好。


更新:
如果我写一个C API,什么是我必须这样做,这是P /使用C#的语法类似于下面的调用,能够在事情:

[DLLimport("MyDLL.dll")] 

是有可能这样做与原生C++代码/库相同吗?


摘要/改写一些提示,使一个的P/Invoke友好的本地API:
+的参数应该是原生类型(INT,CHAR *,浮法,...)
+参数少是更好
+如果分配了动态内存并将其传递给托管代码,请确保创建一个也称为“清理程序”的函数,该函数也可以被p/
+ +提供样本和/或单元测试, +提供C++/CLI封装器

回答

1

根据定义,每个本地函数都可以从托管代码中进行p /调用。但为了使p/invoke变得友好,一个函数应该尽可能少的参数应该是本地类型(int,char *,float,...)。另外,如果某个函数在返回到托管代码的某个指针上分配内存,请确保写入其计数器部分以释放指针,因为托管代码无法释放从非托管代码分配的内存。

+0

“函数应该尽可能少的参数应该是本机类型(int,char *,float,...)” 我可以将它总结为: - >参数应该是本机类型(INT,CHAR *,浮法,...) - >少参数更好 - >如果动态内存分配和传递到托管代码,确保创建一个“干净”的功能,这也是p /援引 – 2010-01-19 09:52:14

+0

是这是一个很好的总结。 – 2010-01-19 16:25:13

1

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

写作与NUnit的 一个简单的单元测试,证明你的代码正常 的.NET类当从.Net调用将是一个很好的做法。

还记得那.NET开发人员很可能会调用你的代码不可能很了解C++,或者不知道不同的数据类型等的尺寸或这些类型如何映射到属性的PInvoke 。

首先考虑你希望你的客户代码看起来,然后设计一个允许它的API。

3

而不是使用P/Invoke,如果您自己控制本机库,则可以编写一组包装本机调用的C++/CLI类。在许多情况下,这将比使用平台调用更好,并且您可以获得类型正确性的额外好处。举例来说,如果你有某种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,了解你的新控件在两个管理他ap和本地堆,以及混合两者的注意事项(就像我上面使用的pin_ptr一样),但总的来说,它是在.NET中完成本地互操作的更加优雅的解决方案。