Как сделать дружественный встроенный API PInvoke?

Как сделать встроенный API, чтобы быть товарищеской встречей PInvoke?

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

использование C или C++ прекрасно.


обновление:
если я пишу API C, что является вещами, я должен сделать так, чтобы Это был P/Invoke-able, использующий синтаксис C# как следующее:

[DLLimport("MyDLL.dll")]

действительно ли возможно сделать то же с собственным кодом/библиотекой C++?


Сводка/Перефразировать Некоторых Подсказок для создания дружественного встроенного API P/Invoke:
+ параметры должны иметь собственные типы (интервал, символ*, плавание...)
+ меньше параметров лучше
+ если динамическая память выделяется и передается управляемому коду, удостоверьтесь, что создали "более чистую" функцию, которая является также p/invoked
+ обеспечьте образцы и/или модульные тесты, которые иллюстрируют, как назвать API от.NET
+ обеспечьте C++ / обертка

6
задан 5 revs 23 May 2017 в 10:24
поделиться

3 ответа

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

1
ответ дан 17 December 2019 в 04:47
поделиться

На самом деле, это возможно.

Для реализации функциональных возможностей необходимо определить TypeListener . Что-то вроде следующего в определении модуля:

bindListener(Matchers.subclassesOf(MyInitClass.class), new TypeListener() {
    @Override
    public <I> void hear(final TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
        typeEncounter.register(new InjectionListener<I>() {
            @Override
            public void afterInjection(Object i) {
                MyInitClass m = (MyInitClass) i;
                m.init();
            }
        });
    }
});
-121--970020-

Можно преобразовать подстановочный запрос в регулярное выражение и использовать его для сопоставления; RE всегда может быть преобразован в DFA (дискретный конечный автомат), и они являются эффективными (время линейного эфира) и малой константой.

-121--3003487-

Вместо использования P/Invoke, если вы сами управляете собственной библиотекой, вы можете написать набор классов C + +/CLI, которые переносят собственные вызовы. Во многих случаях это будет работать лучше, чем использование platform 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.

3
ответ дан 17 December 2019 в 04:47
поделиться

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

, написание простого теста на единицу с NUNIT это доказывает, что ваш код работает правильно когда вызывается из .NET способ сделать это.

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

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

1
ответ дан 17 December 2019 в 04:47
поделиться