AccessViolationException передавая массивы в нативную функцию - PullRequest
0 голосов
/ 18 сентября 2018

Эта функция объявлена ​​в устаревшем коде VB6, и я пытаюсь переместить вызывающий код в .NET.Поэтому мне нужно перевести следующее на C #.

Private Declare Sub FooFunc "foo.dll" _
                      (ByRef A As Long, _
                      ByVal B As String, _
                      ByRef C As Long, _
                      ByRef D As Integer,)

У меня нет документации по foo.dll.Все, что у меня есть, это текущий код вызова в VB6, который был написан кем-то давно ушедшим:

Dim a as Long
Dim b as String
Dim c(2001) as Integer
Dim d(2001) as Long

c(0) = itemCount
d(0) = itemCount
For i = 1 To itemCount
  c(i) = ...
Next

Call FooFunc(a, b, c(0), d(0))

DoSomethingWithD(d)
...
  • параметр a может быть изменен DLL, поэтому я думаю, что мне нужно ключевое слово out
  • параметр b не изменяется
  • параметр c является массивом входных значений и не изменяется
  • параметр d является предварительно выделенным массивом, который будет получать выходные данныеценности.Смущает то, что первый элемент передается, но я знаю, что массив заполняется значениями при вызове из VB6, как это

Я думаю, что мне нужно что-то вроде следующего в C #, ноКогда я вызываю функцию, я получаю AccessViolationException.

[DllImport("foo.dll")]
public static extern void FooFunc(out int a, string b, int[] c, short[] d);

Я пробовал несколько других вариантов и смотрел больше объяснений на SO, но ничто совершенно не соответствует странному способу, которым код VB6 передает массивы иЯ не знаю, сбивает это с толку или нет.Может быть, это способ заставить его работать как массив в стиле C?И заполнение первого было бы просто странным соглашением, используемым тем, кто создал foo.dll.

Edit 1:

Кажется, FooFunc должен был принятьПервоначально C-массивы, но C # и даже VB6 будут передавать SafeArrays, которые имеют байты для ранга и границ перед фактическими данными массива.Если это так, то передача по ссылке первого элемента имеет смысл, потому что тогда FooFunc может читать остальные данные.

Однако, поскольку неуправляемый код не может напрямую изменять управляемые массивы, мне нужен какой-то способ выделениянеуправляемый массив, который может быть изменен неуправляемым кодом и передачей указателя на первый элемент в качестве параметра.Есть ли способ сделать это?

1 Ответ

0 голосов
/ 18 сентября 2018

Я думаю, что вы неправильно читаете код. Вызов FooFunc не передает массив, он индексирует пару массивов и передает ссылку на индексированные значения, чтобы их можно было изменить.

[DllImport("foo.dll")]
public static extern void FooFunc(ref int a, string b, ref int c, ref short d);
...