2010-01-19 64 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中完成本地互操作的更加優雅的解決方案。