Сложная (?) Ситуация пинвока - избегайте перегрузки функций - PullRequest
0 голосов
/ 10 июня 2009

Резюме:

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

Материал C:

где-то в заголовочном файле

typedef struct _unknown_stuff * handle; // a opaque pointer

пример функции

func( uint      num_entries,
      handle *  objects,
      uint *    n)
{ ... }

в C должна использоваться функция, подобная этой:

// warning: i bet that the syntax is not correct but you should get the idea...

uint n;

func(0, null, &n);

handle * objects = malloc(n * sizeof(handle));

func(n, objects, null);

Материал C #:

сейчас я делаю в C # следующее:

public struct handle
{
    public IntPtr Pointer;
}

// version to get number of objects
[DllImport(dll, ...]
private static extern void
func(  uint        must_be_zero,
       object      must_be_null,
       out uint    n);

// version to get the actual data
[DllImport(dll, ...]
private static extern void
func(   uint           num_entries,
        [Out] handle[] objects,
        int            must_be_zero);

и затем:

handle[] objects;

uint n = 42;

func(0, null, out n);

objects = new handle[n];

func(n, objects, 0);

Вопрос

Так как я новичок в C #, мне было интересно, если это лучший способ сделать это. Особенно я хотел бы знать, есть ли способ перегрузки функции.

Ответы [ 2 ]

1 голос
/ 10 июня 2009

Прежде всего, ваш код «как есть» неверен, потому что во второй сигнатуре C # ваш третий аргумент - int, а соответствующий аргумент C - все еще int*. Он будет работать при нацеливании на 32-битную Windows, потому что sizeof(int)==sizeof(int*) там - так что когда вы передаете 0 int, вы в конечном итоге пропускаете нулевой указатель - но это не 64-битная безопасность. Если вы все еще хотите сделать это таким образом, вам нужно использовать IntPtr там.

Кроме этого, вы можете попробовать:

[DllImport(dll, ...]
private static extern void func(
  uint num_entries,
  [Out] handle[] objects,
  [Out] int[] num_devices);

сделать третий аргумент массивом, чтобы вы могли передать ему значение null.

Или просто используйте указатели. В этом нет ничего плохого, и не бойтесь ключевого слова unsafe - любой вид P / Invoke в любом случае небезопасен, так что вы также можете быть откровенным об этом.

0 голосов
/ 10 июня 2009

Не будет ли C dll смотреть на 0 и обрабатывать его как ноль?

Он имеет только одну функцию, правильно? То есть функция C определяется один раз, а не отдельно для нулевого случая, и где-то там будет проверка

if( objects == NULL )
. В большинстве систем (проверьте stdio.h целевой системы) это 0. Поэтому вызов из pinvoke со значением 0 в этом месте должен сделать то, что вы хотели сделать с перегрузкой.
...