2010-01-19 15 views
6

Wie man eine native API macht, um PInvoke freundlich zu sein?Wie mache ich eine PInvoke-freundliche native-API?

Es gibt einige Tipps zum Ändern von nativen Programmen, die mit P/Invoke here verwendet werden sollen. Aber bevor ich überhaupt ein natives Programm schreibe, worauf sollte ich achten, um meine Programme/Bibliothek PInvoke freundlich zu machen?

mit C oder C++ sind in Ordnung.


Update:
wenn ich eine C-API zu schreiben, was sind die Dinge, die ich so zu tun haben, dass es P/Invoke-fähig ist C# Syntax wie folgt aus:

[DLLimport("MyDLL.dll")] 

ist es möglich, zu tun das Gleiche mit nativem C++ Code/Bibliothek?


Zusammenfassung/Rephrase einiger Tipps, um einen P zu machen/Invoke freundliche nativer API:
+ die Parameter von nativen Typen sein sollte (int, char *, float, ...)
+ weniger Parameter ist besser
+ Wenn dynamischer Speicher zugewiesen und an verwalteten Code übergeben wird, stellen Sie sicher, dass eine "cleaner" -Funktion erstellt wird, die ebenfalls aufgerufen wird
+ Beispiele und/oder Komponententests bereitstellen, die veranschaulichen, wie die API von .NET
aufgerufen wird + C++/CLI-Wrapper bereitstellen

Antwort

1

Per Definition kann jede native Funktion aus verwaltetem Code aufgerufen werden. Aber um p/invoke friendly zu sein, sollte eine Funktion so wenig Parameter wie möglich haben, die von nativen Typen sein sollten (int, char *, float, ...). Wenn eine Funktion Speicher auf einem Zeiger zuordnet, der an verwalteten Code zurückgegeben wird, stellen Sie sicher, dass Sie den Zählerabschnitt schreiben, der den Zeiger freigibt, da verwalteter Code den aus nicht verwaltetem Code zugewiesenen Speicher nicht freigeben kann.

+0

„eine Funktion soll so wenige Parameter wie möglich hat, die von nativen Typen (int, char *, float, ...) sein sollte“ Kann ich es in zusammenfassen: -> die Parameter von nativen Typen sein sollten (int, char *, float, ...) -> weniger Parameter ist besser -> Wenn dynamischer Speicher zugewiesen und an verwalteten Code übergeben wird, stellen Sie sicher, eine "cleaner" -Funktion zu erstellen, die auch p/aufgerufen –

+0

Ja Das ist eine gute Zusammenfassung. –

1

Geben Sie ein Beispiel für richtig es von C# oder .NET aufrufen, auch eine besseren eine .NET-Klasse, die Ihre Methoden aller

wickelt

einen einfachen Unit-Test mit nunit Schreiben , dass Ihr Code funktioniert beweist richtig wenn es von .Net aufgerufen wird, wäre eine großartige Art, es zu tun.

Denken Sie auch daran, dass die .NET-Entwickler, die wahrscheinlich den Code zu rufen sind unwahrscheinlich viel über C wissen ++, oder nicht wissen, die Größen von verschiedenen Datentypen usw. oder, wie diese Typen werden die auf PInvoke Attribute .

Denken Sie vor allem darüber nach, wie Sie möchten, dass Ihre Kunden den Code sehen und entwerfen Sie dann eine API, die dies ermöglicht.

3

Anstatt P/Invoke zu verwenden, können Sie, wenn Sie die systemeigene Bibliothek selbst steuern, eine Reihe von C++/CLI-Klassen schreiben, die die systemeigenen Aufrufe umschließen. In vielen Fällen wird dies eine bessere Leistung erzielen als die Verwendung von Plattformaufrufen, und Sie erhalten den zusätzlichen Vorteil der Typkorrektheit.Zum Beispiel, wenn Sie irgendeine Art von C-API wie die folgenden (es tut nichts nützlich, ich habe gerade hinzugefügt Zeiger und Strukturen, um die Tatsache zu verstärken, dass es native Code ist):

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; 
} 

können Sie erstellen eine C++/CLI-Klasse, es zu wickeln:

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); 
    } 
} 

Dann können Sie diese in C# anrufen:

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

Sie werden mehr auf C++/CLI müssen lesen Sie die neuen Steuerelemente, die Sie müssen verstehen, über beide schaffte er es ap und der native Heap, und die Vorbehalte zu mischen die beiden (wie die pin_ptr ich oben verwendet), aber insgesamt ist es eine viel elegantere Lösung für native Interop in .NET zu erreichen.