Как сделать PInvoke дружественным native-API? - PullRequest
6 голосов
/ 19 января 2010

Как сделать нативный API-интерфейс удобным для PInvoke?

Есть несколько советов о том, как изменить native-программы для использования с P / Invoke здесь . Но прежде чем я даже напишу нативные программы, что я должен посмотреть, чтобы сделать мои программы / библиотеку PInvoke дружественными?

с использованием C или C ++ - это нормально. <Ч /> Обновление:
если я напишу C API, что мне нужно сделать, чтобы он мог работать с P / Invoke, используя синтаксис C #, например:

[DLLimport("MyDLL.dll")]

возможно ли сделать то же самое с собственным кодом / библиотекой C ++? <Ч /> Резюме / перефразировка некоторых советов, чтобы сделать P / Invoke дружественным native-API:
+ параметры должны быть нативного типа (int, char *, float, ...)
+ меньше параметров, тем лучше
+ если динамическая память выделена и передана в управляемый код, обязательно создайте «более чистую» функцию, которая также вызывается p / invoc
+ предоставить образцы и / или модульные тесты, которые иллюстрируют, как вызвать API из .NET
+ предоставить оболочку C ++ / CLI

Ответы [ 3 ]

3 голосов
/ 19 января 2010

Вместо использования 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, чтобы понять новые имеющиеся у вас элементы управления как для управляемой, так и для собственной кучи, а также предостережения относительно их смешивания (например, pin_ptr, который я использовал выше), но В целом, это гораздо более элегантное решение для реализации встроенного взаимодействия в .NET.

1 голос
/ 19 января 2010

Предоставьте пример правильного вызова его из C # или .NET, еще лучше предоставьте класс .NET, охватывающий все ваши методы

Написание простого модульного теста с помощью nunit, который подтверждает, что ваш код работает правильноПри вызове из .Net это был бы отличный способ сделать это.

Также помните, что разработчики .NET, которые могут вызывать ваш код, вряд ли много знают о C ++ или не знаютзнать размеры различных типов данных и т. д. или как эти типы отображаются на атрибуты PInvoke.

Прежде всего подумайте о том, как вы хотите, чтобы ваш клиентский код выглядел, и затем спроектируйте API, который это позволяет.

1 голос
/ 19 января 2010

По определению каждая нативная функция может быть вызвана из управляемого кода. Но чтобы быть дружественным к p / invoke, функция должна иметь как можно меньше параметров, которые должны быть нативного типа (int, char *, float, ...). Также, если функция выделяет память для некоторого указателя, который возвращается в управляемый код, убедитесь, что вы написали его счетчик, который освободит указатель, поскольку управляемый код не может освободить память, выделенную из неуправляемого кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...