AccessViolationException将数组传递给本机函数

时间:2018-09-17 23:02:51

标签: c# vb6 vb6-migration

我有在旧版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,填写第一个都是奇怪的约定。

编辑1:

似乎FooFunc原本是要接收C数组的,但是C#甚至VB6都将传入SafeArrays,该数组在实际数组数据之前具有用于行距和界限的字节。如果是这样,则按引用传递第一个元素很有意义,因为FooFunc可以读取其余数据。

但是,由于非托管代码不能直接修改托管数组,因此我需要某种方式分配可以由非托管代码修改的非托管数组,并将指向第一个元素的指针作为参数传递。有办法吗?

1 个答案:

答案 0 :(得分:1)

我认为您误读了代码。调用FooFunc不会传递数组,它会索引成两个数组,并传递对索引值的引用,以便可以对其进行更改。

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