获取访问违规异常将固定长度的字符串从 C# 传递到 dll 时

本文关键字:字符串 dll 访问 异常 获取 | 更新日期: 2023-09-27 18:36:54

我有以下(VB6?)代码在VBA for Excel中完美运行。 我正在使用的dll(x.dll)对我来说是一个"黑匣子"。 我不知道它是用什么写的,它是否是非托管的。 从历史技术的角度来看,我对它知之甚少。 我只知道这个特定的函数在从 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 for Excel Code

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 中实现相同的内容,当它到达"返回 dllSpace(-1, -1, c, d);"时出现错误;在 [] 试图读取或写入受保护的内存时发生了 system.accessviarationexception 类型的未处理异常。 其他内存已损坏

我需要将其转换为.NET,并且我得到一个AccessViolationException。 我到处都读到StringBuilders保留的内存可以被C#中的dll访问。 我尝试过"ref StringBuilder",我尝试使用byte[],我尝试使用不安全的描述符,我不明白。 另外,如果有一种方法可以让我使用 IDE 查看内存中正在发生的事情,这对我也有帮助。 我可以在局部和监视窗口中看到我的所有变量,但我看不到也不知道如何查看有关抛出的异常的更多详细信息。 我在Win7 32位操作系统机器上使用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);
}

获取访问违规异常将固定长度的字符串从 C# 传递到 dll 时

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
);