将固定长度的字符串从 C# 传递到 dll 时获取 AccessViolationException

Getting AccessViolationException when passing a fixed length string from C# to a dll

我有以下 (VB6?) 代码在 VBA 中完美地用于 Excel。我正在使用的 dll (x.dll) 对我来说是 "black box"。我不知道它是用什么写的,是否不受管理。从历史技术的角度来看,我对此知之甚少。我只知道这个特定的函数在从 Excel VBA 调用时有效,而当我从 C# 调用它时我不能同样地让它起作用,我认为我应该能够。 c.b128 的值再次被 dll 使用和更改。

'In VBA for excel the value inside "c.b128" is changed from
'" 1234567890123456789012345678901234567890123456789012345678901234567890123456789                                                 "
'to
'" 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 123456789                                          "

VBA Excel 代码

Private Type k128
    b128 As String * 128
End Type

Private Declare Function dllSpace Lib "x.dll" (aInfo As Long, _
   bVec As Long, cQry As k128, dErr As k128) As Long    

Function Space() As Long

    Dim c  As k128
    Dim d  As k128

    c.b128 = Left(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789", 128)
    d.b128 = Left("", 128)


    Space = dllSpace(-1, -1, c, d)

 End Function

我试图在 .NET 中实现相同的功能,但在到达 "return dllSpace(-1, -1, c, d);" 时出现错误 system.accessviolationexception 类型的未处理异常发生在 [...] 试图读取或写入受保护的内存中。其他内存已损坏

我需要将其转换为 .NET,我得到了一个 AccessViolationException。我到处都读到 StringBuilders 保留的内存可供 C# 中的 dll 访问。我试过“ref StringBuilder” 我试过使用 byte[],我试过使用不安全的描述符,我不明白。另外,如果有一种方法可以让我使用 IDE 查看更多内存中发生的事情,那对我也会有帮助。我可以在本地看到我所有的变量并观察 windows,但我看不到也不知道如何查看有关抛出的异常的更多详细信息。我在 Win7 32 位 OS 机器上使用 Visual Studio Express 2013 for Windows Desktop。

这是我的 C# 代码片段


C# 代码片段

[DllImport(@"x.dll")]
private static extern int dllSpace(int aInfo,
                  int bVec,
                  StringBuilder cQry,
                  StringBuilder dErr);


public int StartTheDataSpace()
{


    StringBuilder c = new StringBuilder(128);

    StringBuilder d = new StringBuilder(128);

    c.Append(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789                                                 ");

    return dllSpace(-1, -1, c, d);
}

VBA代码清楚地表明,您所拥有的实际上是一个包含固定长度字符串的结构。这意味着 StringBuilder 是错误的类型。您应该改用:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct k128
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string b128;
}

此外,据我了解,VBA 默认使用 ByRef。所以 C# 声明应该是:

[DllImport(@"x.dll")]
private static extern int dllSpace(
    ref int aInfo,
    ref int bVec,
    ref k128 cQry,
    ref k128 dErr
);

现在,碰巧 ref k128 与容量为 128 的 StringBuilder 编组时具有相同的内存布局,因此您可能会发现切换回更方便:

[DllImport(@"x.dll")]
private static extern int dllSpace(
    ref int aInfo,
    ref int bVec,
    StringBuilder cQry,
    StringBuilder dErr
);